2c65db0cc68fa48c711ff9fac8d911e17b308685
[reactos.git] / base / applications / network / net / cmdUser.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS net command
4 * FILE: base/applications/network/net/cmdUser.c
5 * PURPOSE:
6 *
7 * PROGRAMMERS: Eric Kohl
8 * Curtis Wilson
9 */
10
11 #include "net.h"
12
13
14 static
15 int
16 CompareInfo(const void *a,
17 const void *b)
18 {
19 return _wcsicmp(((PUSER_INFO_0)a)->usri0_name,
20 ((PUSER_INFO_0)b)->usri0_name);
21 }
22
23
24 static
25 NET_API_STATUS
26 EnumerateUsers(VOID)
27 {
28 PUSER_INFO_0 pBuffer = NULL;
29 PSERVER_INFO_100 pServer = NULL;
30 DWORD dwRead = 0, dwTotal = 0;
31 DWORD i;
32 DWORD_PTR ResumeHandle = 0;
33 NET_API_STATUS Status;
34
35 Status = NetServerGetInfo(NULL,
36 100,
37 (LPBYTE*)&pServer);
38 if (Status != NERR_Success)
39 return Status;
40
41 ConPuts(StdOut, L"\n");
42 ConResPrintf(StdOut, IDS_USER_ACCOUNTS, pServer->sv100_name);
43 ConPuts(StdOut, L"\n\n");
44 PrintPadding(L'-', 79);
45 ConPuts(StdOut, L"\n");
46
47 NetApiBufferFree(pServer);
48
49 do
50 {
51 Status = NetUserEnum(NULL,
52 0,
53 0,
54 (LPBYTE*)&pBuffer,
55 MAX_PREFERRED_LENGTH,
56 &dwRead,
57 &dwTotal,
58 &ResumeHandle);
59 if ((Status != NERR_Success) && (Status != ERROR_MORE_DATA))
60 return Status;
61
62 qsort(pBuffer,
63 dwRead,
64 sizeof(PUSER_INFO_0),
65 CompareInfo);
66
67 for (i = 0; i < dwRead; i++)
68 {
69 if (pBuffer[i].usri0_name)
70 ConPrintf(StdOut, L"%s\n", pBuffer[i].usri0_name);
71 }
72
73 NetApiBufferFree(pBuffer);
74 pBuffer = NULL;
75 }
76 while (Status == ERROR_MORE_DATA);
77
78 return NERR_Success;
79 }
80
81
82 static
83 VOID
84 PrintDateTime(DWORD dwSeconds)
85 {
86 LARGE_INTEGER Time;
87 FILETIME FileTime;
88 SYSTEMTIME SystemTime;
89 WCHAR DateBuffer[80];
90 WCHAR TimeBuffer[80];
91
92 RtlSecondsSince1970ToTime(dwSeconds, &Time);
93 FileTime.dwLowDateTime = Time.u.LowPart;
94 FileTime.dwHighDateTime = Time.u.HighPart;
95 FileTimeToLocalFileTime(&FileTime, &FileTime);
96 FileTimeToSystemTime(&FileTime, &SystemTime);
97
98 GetDateFormatW(LOCALE_USER_DEFAULT,
99 DATE_SHORTDATE,
100 &SystemTime,
101 NULL,
102 DateBuffer,
103 80);
104
105 GetTimeFormatW(LOCALE_USER_DEFAULT,
106 TIME_NOSECONDS,
107 &SystemTime,
108 NULL,
109 TimeBuffer,
110 80);
111
112 ConPrintf(StdOut, L"%s %s", DateBuffer, TimeBuffer);
113 }
114
115
116 static
117 DWORD
118 GetTimeInSeconds(VOID)
119 {
120 LARGE_INTEGER Time;
121 FILETIME FileTime;
122 DWORD dwSeconds;
123
124 GetSystemTimeAsFileTime(&FileTime);
125 Time.u.LowPart = FileTime.dwLowDateTime;
126 Time.u.HighPart = FileTime.dwHighDateTime;
127 RtlTimeToSecondsSince1970(&Time, &dwSeconds);
128
129 return dwSeconds;
130 }
131
132
133 static
134 NET_API_STATUS
135 DisplayUser(LPWSTR lpUserName)
136 {
137 PUSER_MODALS_INFO_0 pUserModals = NULL;
138 PUSER_INFO_4 pUserInfo = NULL;
139 PLOCALGROUP_USERS_INFO_0 pLocalGroupInfo = NULL;
140 PGROUP_USERS_INFO_0 pGroupInfo = NULL;
141 DWORD dwLocalGroupRead, dwLocalGroupTotal;
142 DWORD dwGroupRead, dwGroupTotal;
143 DWORD dwLastSet;
144 DWORD i;
145 INT nPaddedLength = 29;
146 NET_API_STATUS Status;
147
148 /* Modify the user */
149 Status = NetUserGetInfo(NULL,
150 lpUserName,
151 4,
152 (LPBYTE*)&pUserInfo);
153 if (Status != NERR_Success)
154 return Status;
155
156 Status = NetUserModalsGet(NULL,
157 0,
158 (LPBYTE*)&pUserModals);
159 if (Status != NERR_Success)
160 goto done;
161
162 Status = NetUserGetLocalGroups(NULL,
163 lpUserName,
164 0,
165 0,
166 (LPBYTE*)&pLocalGroupInfo,
167 MAX_PREFERRED_LENGTH,
168 &dwLocalGroupRead,
169 &dwLocalGroupTotal);
170 if (Status != NERR_Success)
171 goto done;
172
173 Status = NetUserGetGroups(NULL,
174 lpUserName,
175 0,
176 (LPBYTE*)&pGroupInfo,
177 MAX_PREFERRED_LENGTH,
178 &dwGroupRead,
179 &dwGroupTotal);
180 if (Status != NERR_Success)
181 goto done;
182
183 PrintPaddedResourceString(IDS_USER_NAME, nPaddedLength);
184 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_name);
185
186 PrintPaddedResourceString(IDS_USER_FULL_NAME, nPaddedLength);
187 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_full_name);
188
189 PrintPaddedResourceString(IDS_USER_COMMENT, nPaddedLength);
190 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_comment);
191
192 PrintPaddedResourceString(IDS_USER_USER_COMMENT, nPaddedLength);
193 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_usr_comment);
194
195 PrintPaddedResourceString(IDS_USER_COUNTRY_CODE, nPaddedLength);
196 ConPrintf(StdOut, L"%03ld ()\n", pUserInfo->usri4_country_code);
197
198 PrintPaddedResourceString(IDS_USER_ACCOUNT_ACTIVE, nPaddedLength);
199 if (pUserInfo->usri4_flags & UF_ACCOUNTDISABLE)
200 ConResPuts(StdOut, IDS_GENERIC_NO);
201 else if (pUserInfo->usri4_flags & UF_LOCKOUT)
202 ConResPuts(StdOut, IDS_GENERIC_LOCKED);
203 else
204 ConResPuts(StdOut, IDS_GENERIC_YES);
205 ConPuts(StdOut, L"\n");
206
207 PrintPaddedResourceString(IDS_USER_ACCOUNT_EXPIRES, nPaddedLength);
208 if (pUserInfo->usri4_acct_expires == TIMEQ_FOREVER)
209 ConResPuts(StdOut, IDS_GENERIC_NEVER);
210 else
211 PrintDateTime(pUserInfo->usri4_acct_expires);
212 ConPuts(StdOut, L"\n\n");
213
214 PrintPaddedResourceString(IDS_USER_PW_LAST_SET, nPaddedLength);
215 dwLastSet = GetTimeInSeconds() - pUserInfo->usri4_password_age;
216 PrintDateTime(dwLastSet);
217
218 PrintPaddedResourceString(IDS_USER_PW_EXPIRES, nPaddedLength);
219 if ((pUserInfo->usri4_flags & UF_DONT_EXPIRE_PASSWD) || pUserModals->usrmod0_max_passwd_age == TIMEQ_FOREVER)
220 ConResPuts(StdOut, IDS_GENERIC_NEVER);
221 else
222 PrintDateTime(dwLastSet + pUserModals->usrmod0_max_passwd_age);
223 ConPuts(StdOut, L"\n");
224
225 PrintPaddedResourceString(IDS_USER_PW_CHANGEABLE, nPaddedLength);
226 PrintDateTime(dwLastSet + pUserModals->usrmod0_min_passwd_age);
227
228 PrintPaddedResourceString(IDS_USER_PW_REQUIRED, nPaddedLength);
229 ConResPuts(StdOut, (pUserInfo->usri4_flags & UF_PASSWD_NOTREQD) ? IDS_GENERIC_NO : IDS_GENERIC_YES);
230 ConPuts(StdOut, L"\n");
231
232 PrintPaddedResourceString(IDS_USER_CHANGE_PW, nPaddedLength);
233 ConResPuts(StdOut, (pUserInfo->usri4_flags & UF_PASSWD_CANT_CHANGE) ? IDS_GENERIC_NO : IDS_GENERIC_YES);
234 ConPuts(StdOut, L"\n\n");
235
236 PrintPaddedResourceString(IDS_USER_WORKSTATIONS, nPaddedLength);
237 if (pUserInfo->usri4_workstations == NULL || wcslen(pUserInfo->usri4_workstations) == 0)
238 ConResPuts(StdOut, IDS_GENERIC_ALL);
239 else
240 ConPrintf(StdOut, L"%s", pUserInfo->usri4_workstations);
241 ConPuts(StdOut, L"\n");
242
243 PrintPaddedResourceString(IDS_USER_LOGON_SCRIPT, nPaddedLength);
244 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_script_path);
245
246 PrintPaddedResourceString(IDS_USER_PROFILE, nPaddedLength);
247 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_profile);
248
249 PrintPaddedResourceString(IDS_USER_HOME_DIR, nPaddedLength);
250 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_home_dir);
251
252 PrintPaddedResourceString(IDS_USER_LAST_LOGON, nPaddedLength);
253 if (pUserInfo->usri4_last_logon == 0)
254 ConResPuts(StdOut, IDS_GENERIC_NEVER);
255 else
256 PrintDateTime(pUserInfo->usri4_last_logon);
257 ConPuts(StdOut, L"\n\n");
258
259 PrintPaddedResourceString(IDS_USER_LOGON_HOURS, nPaddedLength);
260 if (pUserInfo->usri4_logon_hours == NULL)
261 ConResPuts(StdOut, IDS_GENERIC_ALL);
262 ConPuts(StdOut, L"\n\n");
263
264 ConPuts(StdOut, L"\n");
265 PrintPaddedResourceString(IDS_USER_LOCAL_GROUPS, nPaddedLength);
266 if (dwLocalGroupTotal != 0 && pLocalGroupInfo != NULL)
267 {
268 for (i = 0; i < dwLocalGroupTotal; i++)
269 {
270 if (i != 0)
271 PrintPadding(L' ', nPaddedLength);
272 ConPrintf(StdOut, L"*%s\n", pLocalGroupInfo[i].lgrui0_name);
273 }
274 }
275 else
276 {
277 ConPuts(StdOut, L"\n");
278 }
279
280 PrintPaddedResourceString(IDS_USER_GLOBAL_GROUPS, nPaddedLength);
281 if (dwGroupTotal != 0 && pGroupInfo != NULL)
282 {
283 for (i = 0; i < dwGroupTotal; i++)
284 {
285 if (i != 0)
286 PrintPadding(L' ', nPaddedLength);
287 ConPrintf(StdOut, L"*%s\n", pGroupInfo[i].grui0_name);
288 }
289 }
290 else
291 {
292 ConPuts(StdOut, L"\n");
293 }
294
295 done:
296 if (pGroupInfo != NULL)
297 NetApiBufferFree(pGroupInfo);
298
299 if (pLocalGroupInfo != NULL)
300 NetApiBufferFree(pLocalGroupInfo);
301
302 if (pUserModals != NULL)
303 NetApiBufferFree(pUserModals);
304
305 if (pUserInfo != NULL)
306 NetApiBufferFree(pUserInfo);
307
308 return NERR_Success;
309 }
310
311
312 static
313 VOID
314 ReadPassword(
315 LPWSTR *lpPassword,
316 LPBOOL lpAllocated)
317 {
318 WCHAR szPassword1[PWLEN + 1];
319 WCHAR szPassword2[PWLEN + 1];
320 LPWSTR ptr;
321
322 *lpAllocated = FALSE;
323
324 while (TRUE)
325 {
326 ConResPuts(StdOut, IDS_USER_ENTER_PASSWORD1);
327 ReadFromConsole(szPassword1, PWLEN + 1, FALSE);
328 ConPuts(StdOut, L"\n");
329
330 ConResPuts(StdOut, IDS_USER_ENTER_PASSWORD2);
331 ReadFromConsole(szPassword2, PWLEN + 1, FALSE);
332 ConPuts(StdOut, L"\n");
333
334 if (wcslen(szPassword1) == wcslen(szPassword2) &&
335 wcscmp(szPassword1, szPassword2) == 0)
336 {
337 ptr = HeapAlloc(GetProcessHeap(),
338 0,
339 (wcslen(szPassword1) + 1) * sizeof(WCHAR));
340 if (ptr != NULL)
341 {
342 wcscpy(ptr, szPassword1);
343 *lpPassword = ptr;
344 *lpAllocated = TRUE;
345 return;
346 }
347 }
348 else
349 {
350 ConPuts(StdOut, L"\n");
351 ConResPuts(StdOut, IDS_USER_NO_PASSWORD_MATCH);
352 ConPuts(StdOut, L"\n");
353 *lpPassword = NULL;
354 }
355 }
356 }
357
358
359 INT
360 cmdUser(
361 INT argc,
362 WCHAR **argv)
363 {
364 INT i, j;
365 INT result = 0;
366 BOOL bAdd = FALSE;
367 BOOL bDelete = FALSE;
368 #if 0
369 BOOL bDomain = FALSE;
370 #endif
371 LPWSTR lpUserName = NULL;
372 LPWSTR lpPassword = NULL;
373 PUSER_INFO_4 pUserInfo = NULL;
374 USER_INFO_4 UserInfo;
375 LPWSTR p;
376 LPWSTR endptr;
377 DWORD value;
378 BOOL bPasswordAllocated = FALSE;
379 NET_API_STATUS Status;
380
381 if (argc == 2)
382 {
383 Status = EnumerateUsers();
384 ConPrintf(StdOut, L"Status: %lu\n", Status);
385 return 0;
386 }
387 else if (argc == 3)
388 {
389 Status = DisplayUser(argv[2]);
390 ConPrintf(StdOut, L"Status: %lu\n", Status);
391 return 0;
392 }
393
394 i = 2;
395 if (argv[i][0] != L'/')
396 {
397 lpUserName = argv[i];
398 // ConPrintf(StdOut, L"User: %s\n", lpUserName);
399 i++;
400 }
401
402 if (argv[i][0] != L'/')
403 {
404 lpPassword = argv[i];
405 // ConPrintf(StdOut, L"Password: %s\n", lpPassword);
406 i++;
407 }
408
409 for (j = i; j < argc; j++)
410 {
411 if (_wcsicmp(argv[j], L"/help") == 0)
412 {
413 ConResPuts(StdOut, IDS_USER_HELP);
414 return 0;
415 }
416 else if (_wcsicmp(argv[j], L"/add") == 0)
417 {
418 bAdd = TRUE;
419 }
420 else if (_wcsicmp(argv[j], L"/delete") == 0)
421 {
422 bDelete = TRUE;
423 }
424 else if (_wcsicmp(argv[j], L"/domain") == 0)
425 {
426 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/DOMAIN");
427 #if 0
428 bDomain = TRUE;
429 #endif
430 }
431 }
432
433 if (bAdd && bDelete)
434 {
435 result = 1;
436 goto done;
437 }
438
439 /* Interactive password input */
440 if (lpPassword != NULL && wcscmp(lpPassword, L"*") == 0)
441 {
442 ReadPassword(&lpPassword,
443 &bPasswordAllocated);
444 }
445
446 if (!bAdd && !bDelete)
447 {
448 /* Modify the user */
449 Status = NetUserGetInfo(NULL,
450 lpUserName,
451 4,
452 (LPBYTE*)&pUserInfo);
453 if (Status != NERR_Success)
454 {
455 ConPrintf(StdOut, L"Status: %lu\n", Status);
456 result = 1;
457 goto done;
458 }
459 }
460 else if (bAdd && !bDelete)
461 {
462 /* Add the user */
463 ZeroMemory(&UserInfo, sizeof(USER_INFO_4));
464
465 UserInfo.usri4_name = lpUserName;
466 UserInfo.usri4_password = lpPassword;
467 UserInfo.usri4_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT;
468
469 pUserInfo = &UserInfo;
470 }
471
472 for (j = i; j < argc; j++)
473 {
474 if (_wcsnicmp(argv[j], L"/active:", 8) == 0)
475 {
476 p = &argv[i][8];
477 if (_wcsicmp(p, L"yes") == 0)
478 {
479 pUserInfo->usri4_flags &= ~UF_ACCOUNTDISABLE;
480 }
481 else if (_wcsicmp(p, L"no") == 0)
482 {
483 pUserInfo->usri4_flags |= UF_ACCOUNTDISABLE;
484 }
485 else
486 {
487 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/ACTIVE");
488 result = 1;
489 goto done;
490 }
491 }
492 else if (_wcsnicmp(argv[j], L"/comment:", 9) == 0)
493 {
494 pUserInfo->usri4_comment = &argv[j][9];
495 }
496 else if (_wcsnicmp(argv[j], L"/countrycode:", 13) == 0)
497 {
498 p = &argv[i][13];
499 value = wcstoul(p, &endptr, 10);
500 if (*endptr != 0)
501 {
502 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/COUNTRYCODE");
503 result = 1;
504 goto done;
505 }
506
507 /* FIXME: verify the country code */
508
509 pUserInfo->usri4_country_code = value;
510 }
511 else if (_wcsnicmp(argv[j], L"/expires:", 9) == 0)
512 {
513 p = &argv[i][9];
514 if (_wcsicmp(p, L"never") == 0)
515 {
516 pUserInfo->usri4_acct_expires = TIMEQ_FOREVER;
517 }
518 else
519 {
520 /* FIXME: Parse the date */
521 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/EXPIRES");
522 }
523 }
524 else if (_wcsnicmp(argv[j], L"/fullname:", 10) == 0)
525 {
526 pUserInfo->usri4_full_name = &argv[j][10];
527 }
528 else if (_wcsnicmp(argv[j], L"/homedir:", 9) == 0)
529 {
530 pUserInfo->usri4_home_dir = &argv[j][9];
531 }
532 else if (_wcsnicmp(argv[j], L"/passwordchg:", 13) == 0)
533 {
534 p = &argv[i][13];
535 if (_wcsicmp(p, L"yes") == 0)
536 {
537 pUserInfo->usri4_flags &= ~UF_PASSWD_CANT_CHANGE;
538 }
539 else if (_wcsicmp(p, L"no") == 0)
540 {
541 pUserInfo->usri4_flags |= UF_PASSWD_CANT_CHANGE;
542 }
543 else
544 {
545 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDCHG");
546 result = 1;
547 goto done;
548 }
549 }
550 else if (_wcsnicmp(argv[j], L"/passwordreq:", 13) == 0)
551 {
552 p = &argv[i][13];
553 if (_wcsicmp(p, L"yes") == 0)
554 {
555 pUserInfo->usri4_flags &= ~UF_PASSWD_NOTREQD;
556 }
557 else if (_wcsicmp(p, L"no") == 0)
558 {
559 pUserInfo->usri4_flags |= UF_PASSWD_NOTREQD;
560 }
561 else
562 {
563 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDREQ");
564 result = 1;
565 goto done;
566 }
567 }
568 else if (_wcsnicmp(argv[j], L"/profilepath:", 13) == 0)
569 {
570 pUserInfo->usri4_profile = &argv[j][13];
571 }
572 else if (_wcsnicmp(argv[j], L"/scriptpath:", 12) == 0)
573 {
574 pUserInfo->usri4_script_path = &argv[j][12];
575 }
576 else if (_wcsnicmp(argv[j], L"/times:", 7) == 0)
577 {
578 /* FIXME */
579 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/TIMES");
580 }
581 else if (_wcsnicmp(argv[j], L"/usercomment:", 13) == 0)
582 {
583 pUserInfo->usri4_usr_comment = &argv[j][13];
584 }
585 else if (_wcsnicmp(argv[j], L"/workstations:", 14) == 0)
586 {
587 /* FIXME */
588 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/WORKSTATIONS");
589 }
590 }
591
592 if (!bAdd && !bDelete)
593 {
594 /* Modify the user */
595 Status = NetUserSetInfo(NULL,
596 lpUserName,
597 4,
598 (LPBYTE)pUserInfo,
599 NULL);
600 ConPrintf(StdOut, L"Status: %lu\n", Status);
601 }
602 else if (bAdd && !bDelete)
603 {
604 /* Add the user */
605 Status = NetUserAdd(NULL,
606 4,
607 (LPBYTE)pUserInfo,
608 NULL);
609 ConPrintf(StdOut, L"Status: %lu\n", Status);
610 }
611 else if (!bAdd && bDelete)
612 {
613 /* Delete the user */
614 Status = NetUserDel(NULL,
615 lpUserName);
616 ConPrintf(StdOut, L"Status: %lu\n", Status);
617 }
618
619 done:
620 if ((bPasswordAllocated != FALSE) && (lpPassword != NULL))
621 HeapFree(GetProcessHeap(), 0, lpPassword);
622
623 if (!bAdd && !bDelete && pUserInfo != NULL)
624 NetApiBufferFree(pUserInfo);
625
626 if (result != 0)
627 ConResPuts(StdOut, IDS_USER_SYNTAX);
628
629 return result;
630 }
631
632 /* EOF */