517e2c028bdef4068629d24fd97383b33b098d65
[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 typedef struct _COUNTY_TABLE
14 {
15 DWORD dwCountryCode;
16 DWORD dwMessageId;
17 } COUNTRY_TABLE, *PCOUNTRY_TABLE;
18
19
20 static WCHAR szPasswordChars[] = L"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@#$%_-+:";
21 static COUNTRY_TABLE CountryTable[] =
22 { { 0, 5080}, // System Default
23 { 1, 5081}, // United States
24 { 2, 5082}, // Canada (French)
25 { 3, 5083}, // Latin America
26 { 31, 5084}, // Netherlands
27 { 32, 5085}, // Belgium
28 { 33, 5086}, // France
29 { 34, 5090}, // Spain
30 { 39, 5087}, // Italy
31 { 41, 5088}, // Switzerland
32 { 44, 5089}, // United Kingdom
33 { 45, 5091}, // Denmark
34 { 46, 5092}, // Sweden
35 { 47, 5093}, // Norway
36 { 49, 5094}, // Germany
37 { 61, 5095}, // Australia
38 { 81, 5096}, // Japan
39 { 82, 5097}, // Korea
40 { 86, 5098}, // China (PRC)
41 { 88, 5099}, // Taiwan
42 { 99, 5100}, // Asia
43 {351, 5101}, // Portugal
44 {358, 5102}, // Finland
45 {785, 5103}, // Arabic
46 {972, 5104} }; // Hebrew
47
48
49 static
50 int
51 CompareInfo(const void *a, const void *b)
52 {
53 return _wcsicmp(((PUSER_INFO_0)a)->usri0_name,
54 ((PUSER_INFO_0)b)->usri0_name);
55 }
56
57
58 static
59 NET_API_STATUS
60 EnumerateUsers(VOID)
61 {
62 PUSER_INFO_0 pBuffer = NULL;
63 PSERVER_INFO_100 pServer = NULL;
64 DWORD dwRead = 0, dwTotal = 0;
65 DWORD i;
66 DWORD ResumeHandle = 0;
67 NET_API_STATUS Status;
68
69 Status = NetServerGetInfo(NULL,
70 100,
71 (LPBYTE*)&pServer);
72 if (Status != NERR_Success)
73 return Status;
74
75 ConPuts(StdOut, L"\n");
76 PrintMessageStringV(4410, pServer->sv100_name);
77 ConPuts(StdOut, L"\n");
78 PrintPadding(L'-', 79);
79 ConPuts(StdOut, L"\n");
80
81 NetApiBufferFree(pServer);
82
83 do
84 {
85 Status = NetUserEnum(NULL,
86 0,
87 0,
88 (LPBYTE*)&pBuffer,
89 MAX_PREFERRED_LENGTH,
90 &dwRead,
91 &dwTotal,
92 &ResumeHandle);
93 if ((Status != NERR_Success) && (Status != ERROR_MORE_DATA))
94 return Status;
95
96 qsort(pBuffer,
97 dwRead,
98 sizeof(PUSER_INFO_0),
99 CompareInfo);
100
101 for (i = 0; i < dwRead; i++)
102 {
103 if (pBuffer[i].usri0_name)
104 ConPrintf(StdOut, L"%s\n", pBuffer[i].usri0_name);
105 }
106
107 NetApiBufferFree(pBuffer);
108 pBuffer = NULL;
109 }
110 while (Status == ERROR_MORE_DATA);
111
112 return NERR_Success;
113 }
114
115
116 static
117 VOID
118 PrintDateTime(DWORD dwSeconds)
119 {
120 LARGE_INTEGER Time;
121 FILETIME FileTime;
122 SYSTEMTIME SystemTime;
123 WCHAR DateBuffer[80];
124 WCHAR TimeBuffer[80];
125
126 RtlSecondsSince1970ToTime(dwSeconds, &Time);
127 FileTime.dwLowDateTime = Time.u.LowPart;
128 FileTime.dwHighDateTime = Time.u.HighPart;
129 FileTimeToLocalFileTime(&FileTime, &FileTime);
130 FileTimeToSystemTime(&FileTime, &SystemTime);
131
132 GetDateFormatW(LOCALE_USER_DEFAULT,
133 DATE_SHORTDATE,
134 &SystemTime,
135 NULL,
136 DateBuffer,
137 80);
138
139 GetTimeFormatW(LOCALE_USER_DEFAULT,
140 TIME_NOSECONDS,
141 &SystemTime,
142 NULL,
143 TimeBuffer,
144 80);
145
146 ConPrintf(StdOut, L"%s %s", DateBuffer, TimeBuffer);
147 }
148
149
150 static
151 DWORD
152 GetTimeInSeconds(VOID)
153 {
154 LARGE_INTEGER Time;
155 FILETIME FileTime;
156 DWORD dwSeconds;
157
158 GetSystemTimeAsFileTime(&FileTime);
159 Time.u.LowPart = FileTime.dwLowDateTime;
160 Time.u.HighPart = FileTime.dwHighDateTime;
161 RtlTimeToSecondsSince1970(&Time, &dwSeconds);
162
163 return dwSeconds;
164 }
165
166
167 static
168 BOOL
169 GetCountryFromCountryCode(
170 _In_ DWORD dwCountryCode,
171 _In_ DWORD dwCountryLength,
172 _Out_ PWSTR szCountryBuffer)
173 {
174 DWORD i;
175
176 for (i = 0; i < ARRAYSIZE(CountryTable); i++)
177 {
178 if (CountryTable[i].dwCountryCode == dwCountryCode)
179 {
180 if (szCountryBuffer != NULL && dwCountryLength > 0)
181 {
182 FormatMessageW(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS,
183 hModuleNetMsg,
184 CountryTable[i].dwMessageId,
185 LANG_USER_DEFAULT,
186 szCountryBuffer,
187 dwCountryLength,
188 NULL);
189 }
190
191 return TRUE;
192 }
193 }
194
195 return FALSE;
196 }
197
198
199 static
200 NET_API_STATUS
201 DisplayUser(LPWSTR lpUserName)
202 {
203 PUSER_MODALS_INFO_0 pUserModals = NULL;
204 PUSER_INFO_4 pUserInfo = NULL;
205 PLOCALGROUP_USERS_INFO_0 pLocalGroupInfo = NULL;
206 PGROUP_USERS_INFO_0 pGroupInfo = NULL;
207 DWORD dwLocalGroupRead, dwLocalGroupTotal;
208 DWORD dwGroupRead, dwGroupTotal;
209 DWORD dwLastSet;
210 DWORD i;
211 WCHAR szCountry[40];
212 INT nPaddedLength = 36;
213 NET_API_STATUS Status;
214
215 /* Modify the user */
216 Status = NetUserGetInfo(NULL,
217 lpUserName,
218 4,
219 (LPBYTE*)&pUserInfo);
220 if (Status != NERR_Success)
221 return Status;
222
223 Status = NetUserModalsGet(NULL,
224 0,
225 (LPBYTE*)&pUserModals);
226 if (Status != NERR_Success)
227 goto done;
228
229 Status = NetUserGetLocalGroups(NULL,
230 lpUserName,
231 0,
232 0,
233 (LPBYTE*)&pLocalGroupInfo,
234 MAX_PREFERRED_LENGTH,
235 &dwLocalGroupRead,
236 &dwLocalGroupTotal);
237 if (Status != NERR_Success)
238 goto done;
239
240 Status = NetUserGetGroups(NULL,
241 lpUserName,
242 0,
243 (LPBYTE*)&pGroupInfo,
244 MAX_PREFERRED_LENGTH,
245 &dwGroupRead,
246 &dwGroupTotal);
247 if (Status != NERR_Success)
248 goto done;
249
250 PrintPaddedMessageString(4411, nPaddedLength);
251 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_name);
252
253 PrintPaddedMessageString(4412, nPaddedLength);
254 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_full_name);
255
256 PrintPaddedMessageString(4413, nPaddedLength);
257 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_comment);
258
259 PrintPaddedMessageString(4414, nPaddedLength);
260 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_usr_comment);
261
262 PrintPaddedMessageString(4416, nPaddedLength);
263 GetCountryFromCountryCode(pUserInfo->usri4_country_code,
264 ARRAYSIZE(szCountry), szCountry);
265 ConPrintf(StdOut, L"%03ld (%s)\n", pUserInfo->usri4_country_code, szCountry);
266
267 PrintPaddedMessageString(4419, nPaddedLength);
268 if (pUserInfo->usri4_flags & UF_ACCOUNTDISABLE)
269 ConResPuts(StdOut, IDS_GENERIC_NO);
270 else if (pUserInfo->usri4_flags & UF_LOCKOUT)
271 PrintMessageString(4440);
272 else
273 ConResPuts(StdOut, IDS_GENERIC_YES);
274 ConPuts(StdOut, L"\n");
275
276 PrintPaddedMessageString(4420, nPaddedLength);
277 if (pUserInfo->usri4_acct_expires == TIMEQ_FOREVER)
278 ConResPuts(StdOut, IDS_GENERIC_NEVER);
279 else
280 PrintDateTime(pUserInfo->usri4_acct_expires);
281 ConPuts(StdOut, L"\n\n");
282
283 PrintPaddedMessageString(4421, nPaddedLength);
284 dwLastSet = GetTimeInSeconds() - pUserInfo->usri4_password_age;
285 PrintDateTime(dwLastSet);
286 ConPuts(StdOut, L"\n");
287
288 PrintPaddedMessageString(4422, nPaddedLength);
289 if ((pUserInfo->usri4_flags & UF_DONT_EXPIRE_PASSWD) || pUserModals->usrmod0_max_passwd_age == TIMEQ_FOREVER)
290 ConResPuts(StdOut, IDS_GENERIC_NEVER);
291 else
292 PrintDateTime(dwLastSet + pUserModals->usrmod0_max_passwd_age);
293 ConPuts(StdOut, L"\n");
294
295 PrintPaddedMessageString(4423, nPaddedLength);
296 PrintDateTime(dwLastSet + pUserModals->usrmod0_min_passwd_age);
297 ConPuts(StdOut, L"\n");
298
299 PrintPaddedMessageString(4437, nPaddedLength);
300 ConResPuts(StdOut, (pUserInfo->usri4_flags & UF_PASSWD_NOTREQD) ? IDS_GENERIC_NO : IDS_GENERIC_YES);
301 ConPuts(StdOut, L"\n");
302
303 PrintPaddedMessageString(4438, nPaddedLength);
304 ConResPuts(StdOut, (pUserInfo->usri4_flags & UF_PASSWD_CANT_CHANGE) ? IDS_GENERIC_NO : IDS_GENERIC_YES);
305 ConPuts(StdOut, L"\n\n");
306
307 PrintPaddedMessageString(4424, nPaddedLength);
308 if (pUserInfo->usri4_workstations == NULL || wcslen(pUserInfo->usri4_workstations) == 0)
309 ConResPuts(StdOut, IDS_GENERIC_ALL);
310 else
311 ConPrintf(StdOut, L"%s", pUserInfo->usri4_workstations);
312 ConPuts(StdOut, L"\n");
313
314 PrintPaddedMessageString(4429, nPaddedLength);
315 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_script_path);
316
317 PrintPaddedMessageString(4439, nPaddedLength);
318 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_profile);
319
320 PrintPaddedMessageString(4436, nPaddedLength);
321 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_home_dir);
322
323 PrintPaddedMessageString(4430, nPaddedLength);
324 if (pUserInfo->usri4_last_logon == 0)
325 ConResPuts(StdOut, IDS_GENERIC_NEVER);
326 else
327 PrintDateTime(pUserInfo->usri4_last_logon);
328 ConPuts(StdOut, L"\n\n");
329
330 PrintPaddedMessageString(4432, nPaddedLength);
331 if (pUserInfo->usri4_logon_hours == NULL)
332 ConResPuts(StdOut, IDS_GENERIC_ALL);
333 ConPuts(StdOut, L"\n\n");
334
335 ConPuts(StdOut, L"\n");
336 PrintPaddedMessageString(4427, nPaddedLength);
337 if (dwLocalGroupTotal != 0 && pLocalGroupInfo != NULL)
338 {
339 for (i = 0; i < dwLocalGroupTotal; i++)
340 {
341 if (i != 0)
342 PrintPadding(L' ', nPaddedLength);
343 ConPrintf(StdOut, L"*%s\n", pLocalGroupInfo[i].lgrui0_name);
344 }
345 }
346 else
347 {
348 ConPuts(StdOut, L"\n");
349 }
350
351 PrintPaddedMessageString(4431, nPaddedLength);
352 if (dwGroupTotal != 0 && pGroupInfo != NULL)
353 {
354 for (i = 0; i < dwGroupTotal; i++)
355 {
356 if (i != 0)
357 PrintPadding(L' ', nPaddedLength);
358 ConPrintf(StdOut, L"*%s\n", pGroupInfo[i].grui0_name);
359 }
360 }
361 else
362 {
363 ConPuts(StdOut, L"\n");
364 }
365
366 done:
367 if (pGroupInfo != NULL)
368 NetApiBufferFree(pGroupInfo);
369
370 if (pLocalGroupInfo != NULL)
371 NetApiBufferFree(pLocalGroupInfo);
372
373 if (pUserModals != NULL)
374 NetApiBufferFree(pUserModals);
375
376 if (pUserInfo != NULL)
377 NetApiBufferFree(pUserInfo);
378
379 return NERR_Success;
380 }
381
382
383 static
384 VOID
385 ReadPassword(
386 LPWSTR *lpPassword,
387 LPBOOL lpAllocated)
388 {
389 WCHAR szPassword1[PWLEN + 1];
390 WCHAR szPassword2[PWLEN + 1];
391 LPWSTR ptr;
392
393 *lpAllocated = FALSE;
394
395 while (TRUE)
396 {
397 ConResPuts(StdOut, IDS_USER_ENTER_PASSWORD1);
398 ReadFromConsole(szPassword1, PWLEN + 1, FALSE);
399 ConPuts(StdOut, L"\n");
400
401 ConResPuts(StdOut, IDS_USER_ENTER_PASSWORD2);
402 ReadFromConsole(szPassword2, PWLEN + 1, FALSE);
403 ConPuts(StdOut, L"\n");
404
405 if (wcslen(szPassword1) == wcslen(szPassword2) &&
406 wcscmp(szPassword1, szPassword2) == 0)
407 {
408 ptr = HeapAlloc(GetProcessHeap(),
409 0,
410 (wcslen(szPassword1) + 1) * sizeof(WCHAR));
411 if (ptr != NULL)
412 {
413 wcscpy(ptr, szPassword1);
414 *lpPassword = ptr;
415 *lpAllocated = TRUE;
416 return;
417 }
418 }
419 else
420 {
421 ConPuts(StdOut, L"\n");
422 ConResPuts(StdOut, IDS_USER_NO_PASSWORD_MATCH);
423 ConPuts(StdOut, L"\n");
424 *lpPassword = NULL;
425 }
426 }
427 }
428
429
430 static
431 VOID
432 GenerateRandomPassword(
433 LPWSTR *lpPassword,
434 LPBOOL lpAllocated)
435 {
436 LPWSTR pPassword = NULL;
437 INT nCharsLen, i, nLength = 8;
438
439 srand(GetTickCount());
440
441 pPassword = HeapAlloc(GetProcessHeap(),
442 HEAP_ZERO_MEMORY,
443 (nLength + 1) * sizeof(WCHAR));
444 if (pPassword == NULL)
445 return;
446
447 nCharsLen = wcslen(szPasswordChars);
448
449 for (i = 0; i < nLength; i++)
450 {
451 pPassword[i] = szPasswordChars[rand() % nCharsLen];
452 }
453
454 *lpPassword = pPassword;
455 *lpAllocated = TRUE;
456 }
457
458
459 static
460 NET_API_STATUS
461 BuildWorkstationsList(
462 _Out_ PWSTR *pWorkstationsList,
463 _In_ PWSTR pRaw)
464 {
465 BOOL isLastSep, isSep;
466 INT i, j;
467 WCHAR c;
468 INT nLength = 0;
469 INT nArgs = 0;
470 INT nRawLength;
471 PWSTR pList;
472
473 /* Check for invalid characters in the raw string */
474 if (wcspbrk(pRaw, L"/[]=?\\+:.") != NULL)
475 return 3952;
476
477 /* Count the number of workstations in the list and
478 * the required buffer size */
479 isLastSep = FALSE;
480 isSep = FALSE;
481 nRawLength = wcslen(pRaw);
482 for (i = 0; i < nRawLength; i++)
483 {
484 c = pRaw[i];
485 if (c == L',' || c == L';')
486 isSep = TRUE;
487
488 if (isSep == TRUE)
489 {
490 if ((isLastSep == FALSE) && (i != 0) && (i != nRawLength - 1))
491 nLength++;
492 }
493 else
494 {
495 nLength++;
496
497 if (isLastSep == TRUE || (isLastSep == FALSE && i == 0))
498 nArgs++;
499 }
500
501 isLastSep = isSep;
502 isSep = FALSE;
503 }
504
505 nLength++;
506
507 /* Leave, if there are no workstations in the list */
508 if (nArgs == 0)
509 {
510 pWorkstationsList = NULL;
511 return NERR_Success;
512 }
513
514 /* Fail if there are more than eight workstations in the list */
515 if (nArgs > 8)
516 return 3951;
517
518 /* Allocate the buffer for the clean workstation list */
519 pList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
520 if (pList == NULL)
521 return ERROR_NOT_ENOUGH_MEMORY;
522
523 /* Build the clean workstation list */
524 isLastSep = FALSE;
525 isSep = FALSE;
526 nRawLength = wcslen(pRaw);
527 for (i = 0, j = 0; i < nRawLength; i++)
528 {
529 c = pRaw[i];
530 if (c == L',' || c == L';')
531 isSep = TRUE;
532
533 if (isSep == TRUE)
534 {
535 if ((isLastSep == FALSE) && (i != 0) && (i != nRawLength - 1))
536 {
537 pList[j] = L',';
538 j++;
539 }
540 }
541 else
542 {
543 pList[j] = c;
544 j++;
545
546 if (isLastSep == TRUE || (isLastSep == FALSE && i == 0))
547 nArgs++;
548 }
549
550 isLastSep = isSep;
551 isSep = FALSE;
552 }
553
554 *pWorkstationsList = pList;
555
556 return NERR_Success;
557 }
558
559
560 static
561 BOOL
562 ReadNumber(
563 PWSTR *s,
564 PWORD pwValue)
565 {
566 if (!iswdigit(**s))
567 return FALSE;
568
569 while (iswdigit(**s))
570 {
571 *pwValue = *pwValue * 10 + **s - L'0';
572 (*s)++;
573 }
574
575 return TRUE;
576 }
577
578
579 static
580 BOOL
581 ReadSeparator(
582 PWSTR *s)
583 {
584 if (**s == L'/' || **s == L'.')
585 {
586 (*s)++;
587 return TRUE;
588 }
589
590 return FALSE;
591 }
592
593
594 static
595 BOOL
596 ParseDate(
597 PWSTR s,
598 PULONG pSeconds)
599 {
600 SYSTEMTIME SystemTime = {0};
601 FILETIME LocalFileTime, FileTime;
602 LARGE_INTEGER Time;
603 INT nDateFormat = 0;
604 PWSTR p = s;
605
606 if (!*s)
607 return FALSE;
608
609 GetLocaleInfoW(LOCALE_USER_DEFAULT,
610 LOCALE_IDATE,
611 (PWSTR)&nDateFormat,
612 sizeof(INT));
613
614 switch (nDateFormat)
615 {
616 case 0: /* mmddyy */
617 default:
618 if (!ReadNumber(&p, &SystemTime.wMonth))
619 return FALSE;
620 if (!ReadSeparator(&p))
621 return FALSE;
622 if (!ReadNumber(&p, &SystemTime.wDay))
623 return FALSE;
624 if (!ReadSeparator(&p))
625 return FALSE;
626 if (!ReadNumber(&p, &SystemTime.wYear))
627 return FALSE;
628 break;
629
630 case 1: /* ddmmyy */
631 if (!ReadNumber(&p, &SystemTime.wDay))
632 return FALSE;
633 if (!ReadSeparator(&p))
634 return FALSE;
635 if (!ReadNumber(&p, &SystemTime.wMonth))
636 return FALSE;
637 if (!ReadSeparator(&p))
638 return FALSE;
639 if (!ReadNumber(&p, &SystemTime.wYear))
640 return FALSE;
641 break;
642
643 case 2: /* yymmdd */
644 if (!ReadNumber(&p, &SystemTime.wYear))
645 return FALSE;
646 if (!ReadSeparator(&p))
647 return FALSE;
648 if (!ReadNumber(&p, &SystemTime.wMonth))
649 return FALSE;
650 if (!ReadSeparator(&p))
651 return FALSE;
652 if (!ReadNumber(&p, &SystemTime.wDay))
653 return FALSE;
654 break;
655 }
656
657 /* if only entered two digits: */
658 /* assume 2000's if value less than 80 */
659 /* assume 1900's if value greater or equal 80 */
660 if (SystemTime.wYear <= 99)
661 {
662 if (SystemTime.wYear >= 80)
663 SystemTime.wYear += 1900;
664 else
665 SystemTime.wYear += 2000;
666 }
667
668 if (!SystemTimeToFileTime(&SystemTime, &LocalFileTime))
669 return FALSE;
670
671 if (!LocalFileTimeToFileTime(&LocalFileTime, &FileTime))
672 return FALSE;
673
674 Time.u.LowPart = FileTime.dwLowDateTime;
675 Time.u.HighPart = FileTime.dwHighDateTime;
676
677 if (!RtlTimeToSecondsSince1970(&Time, pSeconds))
678 return FALSE;
679
680 return TRUE;
681 }
682
683
684 INT
685 cmdUser(
686 INT argc,
687 WCHAR **argv)
688 {
689 INT i, j;
690 INT result = 0;
691 BOOL bAdd = FALSE;
692 BOOL bDelete = FALSE;
693 #if 0
694 BOOL bDomain = FALSE;
695 #endif
696 BOOL bRandomPassword = FALSE;
697 LPWSTR lpUserName = NULL;
698 LPWSTR lpPassword = NULL;
699 PUSER_INFO_4 pUserInfo = NULL;
700 USER_INFO_4 UserInfo;
701 LPWSTR pWorkstations = NULL;
702 LPWSTR p;
703 LPWSTR endptr;
704 DWORD value;
705 BOOL bPasswordAllocated = FALSE;
706 NET_API_STATUS Status;
707
708 i = 2;
709 if ((i < argc) && (argv[i][0] != L'/'))
710 {
711 lpUserName = argv[i];
712 // ConPrintf(StdOut, L"User: %s\n", lpUserName);
713 i++;
714 }
715
716 if ((i < argc) && (argv[i][0] != L'/'))
717 {
718 lpPassword = argv[i];
719 // ConPrintf(StdOut, L"Password: %s\n", lpPassword);
720 i++;
721 }
722
723 for (j = i; j < argc; j++)
724 {
725 if (_wcsicmp(argv[j], L"/help") == 0)
726 {
727 PrintNetMessage(MSG_USER_HELP);
728 return 0;
729 }
730 else if (_wcsicmp(argv[j], L"/add") == 0)
731 {
732 bAdd = TRUE;
733 }
734 else if (_wcsicmp(argv[j], L"/delete") == 0)
735 {
736 bDelete = TRUE;
737 }
738 else if (_wcsicmp(argv[j], L"/domain") == 0)
739 {
740 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/DOMAIN");
741 #if 0
742 bDomain = TRUE;
743 #endif
744 }
745 else if (_wcsicmp(argv[j], L"/random") == 0)
746 {
747 bRandomPassword = TRUE;
748 GenerateRandomPassword(&lpPassword,
749 &bPasswordAllocated);
750 }
751 }
752
753 if (lpUserName == NULL && lpPassword == NULL)
754 {
755 Status = EnumerateUsers();
756 ConPrintf(StdOut, L"Status: %lu\n", Status);
757 return 0;
758 }
759 else if (lpUserName != NULL && lpPassword == NULL)
760 {
761 Status = DisplayUser(lpUserName);
762 ConPrintf(StdOut, L"Status: %lu\n", Status);
763 return 0;
764 }
765
766 if (bAdd && bDelete)
767 {
768 result = 1;
769 goto done;
770 }
771
772 /* Interactive password input */
773 if (lpPassword != NULL && wcscmp(lpPassword, L"*") == 0)
774 {
775 ReadPassword(&lpPassword,
776 &bPasswordAllocated);
777 }
778
779 if (!bAdd && !bDelete)
780 {
781 /* Modify the user */
782 Status = NetUserGetInfo(NULL,
783 lpUserName,
784 4,
785 (LPBYTE*)&pUserInfo);
786 if (Status != NERR_Success)
787 {
788 ConPrintf(StdOut, L"Status: %lu\n", Status);
789 result = 1;
790 goto done;
791 }
792 }
793 else if (bAdd && !bDelete)
794 {
795 /* Add the user */
796 ZeroMemory(&UserInfo, sizeof(USER_INFO_4));
797
798 UserInfo.usri4_name = lpUserName;
799 UserInfo.usri4_password = lpPassword;
800 UserInfo.usri4_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT;
801 UserInfo.usri4_acct_expires = TIMEQ_FOREVER;
802 UserInfo.usri4_primary_group_id = DOMAIN_GROUP_RID_USERS;
803
804 pUserInfo = &UserInfo;
805 }
806
807 for (j = i; j < argc; j++)
808 {
809 if (_wcsnicmp(argv[j], L"/active:", 8) == 0)
810 {
811 p = &argv[i][8];
812 if (_wcsicmp(p, L"yes") == 0)
813 {
814 pUserInfo->usri4_flags &= ~UF_ACCOUNTDISABLE;
815 }
816 else if (_wcsicmp(p, L"no") == 0)
817 {
818 pUserInfo->usri4_flags |= UF_ACCOUNTDISABLE;
819 }
820 else
821 {
822 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/ACTIVE");
823 result = 1;
824 goto done;
825 }
826 }
827 else if (_wcsnicmp(argv[j], L"/comment:", 9) == 0)
828 {
829 pUserInfo->usri4_comment = &argv[j][9];
830 }
831 else if (_wcsnicmp(argv[j], L"/countrycode:", 13) == 0)
832 {
833 p = &argv[i][13];
834 value = wcstoul(p, &endptr, 10);
835 if (*endptr != 0)
836 {
837 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/COUNTRYCODE");
838 result = 1;
839 goto done;
840 }
841
842 /* Verify the country code */
843 if (GetCountryFromCountryCode(value, 0, NULL))
844 pUserInfo->usri4_country_code = value;
845 }
846 else if (_wcsnicmp(argv[j], L"/expires:", 9) == 0)
847 {
848 p = &argv[i][9];
849 if (_wcsicmp(p, L"never") == 0)
850 {
851 pUserInfo->usri4_acct_expires = TIMEQ_FOREVER;
852 }
853 else if (!ParseDate(p, &pUserInfo->usri4_acct_expires))
854 {
855 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/EXPIRES");
856 result = 1;
857 goto done;
858 }
859 }
860 else if (_wcsnicmp(argv[j], L"/fullname:", 10) == 0)
861 {
862 pUserInfo->usri4_full_name = &argv[j][10];
863 }
864 else if (_wcsnicmp(argv[j], L"/homedir:", 9) == 0)
865 {
866 pUserInfo->usri4_home_dir = &argv[j][9];
867 }
868 else if (_wcsnicmp(argv[j], L"/passwordchg:", 13) == 0)
869 {
870 p = &argv[i][13];
871 if (_wcsicmp(p, L"yes") == 0)
872 {
873 pUserInfo->usri4_flags &= ~UF_PASSWD_CANT_CHANGE;
874 }
875 else if (_wcsicmp(p, L"no") == 0)
876 {
877 pUserInfo->usri4_flags |= UF_PASSWD_CANT_CHANGE;
878 }
879 else
880 {
881 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDCHG");
882 result = 1;
883 goto done;
884 }
885 }
886 else if (_wcsnicmp(argv[j], L"/passwordreq:", 13) == 0)
887 {
888 p = &argv[i][13];
889 if (_wcsicmp(p, L"yes") == 0)
890 {
891 pUserInfo->usri4_flags &= ~UF_PASSWD_NOTREQD;
892 }
893 else if (_wcsicmp(p, L"no") == 0)
894 {
895 pUserInfo->usri4_flags |= UF_PASSWD_NOTREQD;
896 }
897 else
898 {
899 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDREQ");
900 result = 1;
901 goto done;
902 }
903 }
904 else if (_wcsnicmp(argv[j], L"/profilepath:", 13) == 0)
905 {
906 pUserInfo->usri4_profile = &argv[j][13];
907 }
908 else if (_wcsnicmp(argv[j], L"/scriptpath:", 12) == 0)
909 {
910 pUserInfo->usri4_script_path = &argv[j][12];
911 }
912 else if (_wcsnicmp(argv[j], L"/times:", 7) == 0)
913 {
914 /* FIXME */
915 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/TIMES");
916 }
917 else if (_wcsnicmp(argv[j], L"/usercomment:", 13) == 0)
918 {
919 pUserInfo->usri4_usr_comment = &argv[j][13];
920 }
921 else if (_wcsnicmp(argv[j], L"/workstations:", 14) == 0)
922 {
923 p = &argv[i][14];
924 if (wcscmp(p, L"*") == 0 || wcscmp(p, L"") == 0)
925 {
926 pUserInfo->usri4_workstations = NULL;
927 }
928 else
929 {
930 Status = BuildWorkstationsList(&pWorkstations, p);
931 if (Status == NERR_Success)
932 {
933 pUserInfo->usri4_workstations = pWorkstations;
934 }
935 else
936 {
937 ConPrintf(StdOut, L"Status %lu\n\n", Status);
938 result = 1;
939 goto done;
940 }
941 }
942 }
943 }
944
945 if (!bAdd && !bDelete)
946 {
947 /* Modify the user */
948 Status = NetUserSetInfo(NULL,
949 lpUserName,
950 4,
951 (LPBYTE)pUserInfo,
952 NULL);
953 ConPrintf(StdOut, L"Status: %lu\n", Status);
954 }
955 else if (bAdd && !bDelete)
956 {
957 /* Add the user */
958 Status = NetUserAdd(NULL,
959 4,
960 (LPBYTE)pUserInfo,
961 NULL);
962 ConPrintf(StdOut, L"Status: %lu\n", Status);
963 }
964 else if (!bAdd && bDelete)
965 {
966 /* Delete the user */
967 Status = NetUserDel(NULL,
968 lpUserName);
969 ConPrintf(StdOut, L"Status: %lu\n", Status);
970 }
971
972 if (Status == NERR_Success &&
973 lpPassword != NULL &&
974 bRandomPassword == TRUE)
975 {
976 ConPrintf(StdOut, L"The password for %s is: %s\n", lpUserName, lpPassword);
977 }
978
979 done:
980 if (pWorkstations != NULL)
981 HeapFree(GetProcessHeap(), 0, pWorkstations);
982
983 if ((bPasswordAllocated == TRUE) && (lpPassword != NULL))
984 HeapFree(GetProcessHeap(), 0, lpPassword);
985
986 if (!bAdd && !bDelete && pUserInfo != NULL)
987 NetApiBufferFree(pUserInfo);
988
989 if (result != 0)
990 {
991 ConResPuts(StdOut, IDS_GENERIC_SYNTAX);
992 PrintNetMessage(MSG_USER_SYNTAX);
993 }
994
995 return result;
996 }
997
998 /* EOF */