[NET][MC] Move generic strings from net.exe to netmsg.dll.
[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 PrintMessageString(4301);
270 else if (pUserInfo->usri4_flags & UF_LOCKOUT)
271 PrintMessageString(4440);
272 else
273 PrintMessageString(4300);
274 ConPuts(StdOut, L"\n");
275
276 PrintPaddedMessageString(4420, nPaddedLength);
277 if (pUserInfo->usri4_acct_expires == TIMEQ_FOREVER)
278 PrintMessageString(4305);
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 PrintMessageString(4305);
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 PrintMessageString((pUserInfo->usri4_flags & UF_PASSWD_NOTREQD) ? 4301 : 4300);
301 ConPuts(StdOut, L"\n");
302
303 PrintPaddedMessageString(4438, nPaddedLength);
304 PrintMessageString((pUserInfo->usri4_flags & UF_PASSWD_CANT_CHANGE) ? 4301 : 4300);
305 ConPuts(StdOut, L"\n\n");
306
307 PrintPaddedMessageString(4424, nPaddedLength);
308 if (pUserInfo->usri4_workstations == NULL || wcslen(pUserInfo->usri4_workstations) == 0)
309 PrintMessageString(4302);
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 PrintMessageString(4305);
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 PrintMessageString(4302);
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 PrintMessageString(4358);
398 ReadFromConsole(szPassword1, PWLEN + 1, FALSE);
399 ConPuts(StdOut, L"\n");
400
401 PrintMessageString(4361);
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 PrintMessageString(3728);
423 *lpPassword = NULL;
424 }
425 }
426 }
427
428
429 static
430 VOID
431 GenerateRandomPassword(
432 LPWSTR *lpPassword,
433 LPBOOL lpAllocated)
434 {
435 LPWSTR pPassword = NULL;
436 INT nCharsLen, i, nLength = 8;
437
438 srand(GetTickCount());
439
440 pPassword = HeapAlloc(GetProcessHeap(),
441 HEAP_ZERO_MEMORY,
442 (nLength + 1) * sizeof(WCHAR));
443 if (pPassword == NULL)
444 return;
445
446 nCharsLen = wcslen(szPasswordChars);
447
448 for (i = 0; i < nLength; i++)
449 {
450 pPassword[i] = szPasswordChars[rand() % nCharsLen];
451 }
452
453 *lpPassword = pPassword;
454 *lpAllocated = TRUE;
455 }
456
457
458 static
459 NET_API_STATUS
460 BuildWorkstationsList(
461 _Out_ PWSTR *pWorkstationsList,
462 _In_ PWSTR pRaw)
463 {
464 BOOL isLastSep, isSep;
465 INT i, j;
466 WCHAR c;
467 INT nLength = 0;
468 INT nArgs = 0;
469 INT nRawLength;
470 PWSTR pList;
471
472 /* Check for invalid characters in the raw string */
473 if (wcspbrk(pRaw, L"/[]=?\\+:.") != NULL)
474 return 3952;
475
476 /* Count the number of workstations in the list and
477 * the required buffer size */
478 isLastSep = FALSE;
479 isSep = FALSE;
480 nRawLength = wcslen(pRaw);
481 for (i = 0; i < nRawLength; i++)
482 {
483 c = pRaw[i];
484 if (c == L',' || c == L';')
485 isSep = TRUE;
486
487 if (isSep == TRUE)
488 {
489 if ((isLastSep == FALSE) && (i != 0) && (i != nRawLength - 1))
490 nLength++;
491 }
492 else
493 {
494 nLength++;
495
496 if (isLastSep == TRUE || (isLastSep == FALSE && i == 0))
497 nArgs++;
498 }
499
500 isLastSep = isSep;
501 isSep = FALSE;
502 }
503
504 nLength++;
505
506 /* Leave, if there are no workstations in the list */
507 if (nArgs == 0)
508 {
509 pWorkstationsList = NULL;
510 return NERR_Success;
511 }
512
513 /* Fail if there are more than eight workstations in the list */
514 if (nArgs > 8)
515 return 3951;
516
517 /* Allocate the buffer for the clean workstation list */
518 pList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
519 if (pList == NULL)
520 return ERROR_NOT_ENOUGH_MEMORY;
521
522 /* Build the clean workstation list */
523 isLastSep = FALSE;
524 isSep = FALSE;
525 nRawLength = wcslen(pRaw);
526 for (i = 0, j = 0; i < nRawLength; i++)
527 {
528 c = pRaw[i];
529 if (c == L',' || c == L';')
530 isSep = TRUE;
531
532 if (isSep == TRUE)
533 {
534 if ((isLastSep == FALSE) && (i != 0) && (i != nRawLength - 1))
535 {
536 pList[j] = L',';
537 j++;
538 }
539 }
540 else
541 {
542 pList[j] = c;
543 j++;
544
545 if (isLastSep == TRUE || (isLastSep == FALSE && i == 0))
546 nArgs++;
547 }
548
549 isLastSep = isSep;
550 isSep = FALSE;
551 }
552
553 *pWorkstationsList = pList;
554
555 return NERR_Success;
556 }
557
558
559 static
560 BOOL
561 ReadNumber(
562 PWSTR *s,
563 PWORD pwValue)
564 {
565 if (!iswdigit(**s))
566 return FALSE;
567
568 while (iswdigit(**s))
569 {
570 *pwValue = *pwValue * 10 + **s - L'0';
571 (*s)++;
572 }
573
574 return TRUE;
575 }
576
577
578 static
579 BOOL
580 ReadSeparator(
581 PWSTR *s)
582 {
583 if (**s == L'/' || **s == L'.')
584 {
585 (*s)++;
586 return TRUE;
587 }
588
589 return FALSE;
590 }
591
592
593 static
594 BOOL
595 ParseDate(
596 PWSTR s,
597 PULONG pSeconds)
598 {
599 SYSTEMTIME SystemTime = {0};
600 FILETIME LocalFileTime, FileTime;
601 LARGE_INTEGER Time;
602 INT nDateFormat = 0;
603 PWSTR p = s;
604
605 if (!*s)
606 return FALSE;
607
608 GetLocaleInfoW(LOCALE_USER_DEFAULT,
609 LOCALE_IDATE,
610 (PWSTR)&nDateFormat,
611 sizeof(INT));
612
613 switch (nDateFormat)
614 {
615 case 0: /* mmddyy */
616 default:
617 if (!ReadNumber(&p, &SystemTime.wMonth))
618 return FALSE;
619 if (!ReadSeparator(&p))
620 return FALSE;
621 if (!ReadNumber(&p, &SystemTime.wDay))
622 return FALSE;
623 if (!ReadSeparator(&p))
624 return FALSE;
625 if (!ReadNumber(&p, &SystemTime.wYear))
626 return FALSE;
627 break;
628
629 case 1: /* ddmmyy */
630 if (!ReadNumber(&p, &SystemTime.wDay))
631 return FALSE;
632 if (!ReadSeparator(&p))
633 return FALSE;
634 if (!ReadNumber(&p, &SystemTime.wMonth))
635 return FALSE;
636 if (!ReadSeparator(&p))
637 return FALSE;
638 if (!ReadNumber(&p, &SystemTime.wYear))
639 return FALSE;
640 break;
641
642 case 2: /* yymmdd */
643 if (!ReadNumber(&p, &SystemTime.wYear))
644 return FALSE;
645 if (!ReadSeparator(&p))
646 return FALSE;
647 if (!ReadNumber(&p, &SystemTime.wMonth))
648 return FALSE;
649 if (!ReadSeparator(&p))
650 return FALSE;
651 if (!ReadNumber(&p, &SystemTime.wDay))
652 return FALSE;
653 break;
654 }
655
656 /* if only entered two digits: */
657 /* assume 2000's if value less than 80 */
658 /* assume 1900's if value greater or equal 80 */
659 if (SystemTime.wYear <= 99)
660 {
661 if (SystemTime.wYear >= 80)
662 SystemTime.wYear += 1900;
663 else
664 SystemTime.wYear += 2000;
665 }
666
667 if (!SystemTimeToFileTime(&SystemTime, &LocalFileTime))
668 return FALSE;
669
670 if (!LocalFileTimeToFileTime(&LocalFileTime, &FileTime))
671 return FALSE;
672
673 Time.u.LowPart = FileTime.dwLowDateTime;
674 Time.u.HighPart = FileTime.dwHighDateTime;
675
676 if (!RtlTimeToSecondsSince1970(&Time, pSeconds))
677 return FALSE;
678
679 return TRUE;
680 }
681
682
683 INT
684 cmdUser(
685 INT argc,
686 WCHAR **argv)
687 {
688 INT i, j;
689 INT result = 0;
690 BOOL bAdd = FALSE;
691 BOOL bDelete = FALSE;
692 #if 0
693 BOOL bDomain = FALSE;
694 #endif
695 BOOL bRandomPassword = FALSE;
696 LPWSTR lpUserName = NULL;
697 LPWSTR lpPassword = NULL;
698 PUSER_INFO_4 pUserInfo = NULL;
699 USER_INFO_4 UserInfo;
700 LPWSTR pWorkstations = NULL;
701 LPWSTR p;
702 LPWSTR endptr;
703 DWORD value;
704 BOOL bPasswordAllocated = FALSE;
705 NET_API_STATUS Status;
706
707 i = 2;
708 if ((i < argc) && (argv[i][0] != L'/'))
709 {
710 lpUserName = argv[i];
711 // ConPrintf(StdOut, L"User: %s\n", lpUserName);
712 i++;
713 }
714
715 if ((i < argc) && (argv[i][0] != L'/'))
716 {
717 lpPassword = argv[i];
718 // ConPrintf(StdOut, L"Password: %s\n", lpPassword);
719 i++;
720 }
721
722 for (j = i; j < argc; j++)
723 {
724 if (_wcsicmp(argv[j], L"/help") == 0)
725 {
726 PrintNetMessage(MSG_USER_HELP);
727 return 0;
728 }
729 else if (_wcsicmp(argv[j], L"/add") == 0)
730 {
731 bAdd = TRUE;
732 }
733 else if (_wcsicmp(argv[j], L"/delete") == 0)
734 {
735 bDelete = TRUE;
736 }
737 else if (_wcsicmp(argv[j], L"/domain") == 0)
738 {
739 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/DOMAIN");
740 #if 0
741 bDomain = TRUE;
742 #endif
743 }
744 else if (_wcsicmp(argv[j], L"/random") == 0)
745 {
746 bRandomPassword = TRUE;
747 GenerateRandomPassword(&lpPassword,
748 &bPasswordAllocated);
749 }
750 }
751
752 if (lpUserName == NULL && lpPassword == NULL)
753 {
754 Status = EnumerateUsers();
755 ConPrintf(StdOut, L"Status: %lu\n", Status);
756 return 0;
757 }
758 else if (lpUserName != NULL && lpPassword == NULL)
759 {
760 Status = DisplayUser(lpUserName);
761 ConPrintf(StdOut, L"Status: %lu\n", Status);
762 return 0;
763 }
764
765 if (bAdd && bDelete)
766 {
767 result = 1;
768 goto done;
769 }
770
771 /* Interactive password input */
772 if (lpPassword != NULL && wcscmp(lpPassword, L"*") == 0)
773 {
774 ReadPassword(&lpPassword,
775 &bPasswordAllocated);
776 }
777
778 if (!bAdd && !bDelete)
779 {
780 /* Modify the user */
781 Status = NetUserGetInfo(NULL,
782 lpUserName,
783 4,
784 (LPBYTE*)&pUserInfo);
785 if (Status != NERR_Success)
786 {
787 ConPrintf(StdOut, L"Status: %lu\n", Status);
788 result = 1;
789 goto done;
790 }
791 }
792 else if (bAdd && !bDelete)
793 {
794 /* Add the user */
795 ZeroMemory(&UserInfo, sizeof(USER_INFO_4));
796
797 UserInfo.usri4_name = lpUserName;
798 UserInfo.usri4_password = lpPassword;
799 UserInfo.usri4_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT;
800 UserInfo.usri4_acct_expires = TIMEQ_FOREVER;
801 UserInfo.usri4_primary_group_id = DOMAIN_GROUP_RID_USERS;
802
803 pUserInfo = &UserInfo;
804 }
805
806 for (j = i; j < argc; j++)
807 {
808 if (_wcsnicmp(argv[j], L"/active:", 8) == 0)
809 {
810 p = &argv[i][8];
811 if (_wcsicmp(p, L"yes") == 0)
812 {
813 pUserInfo->usri4_flags &= ~UF_ACCOUNTDISABLE;
814 }
815 else if (_wcsicmp(p, L"no") == 0)
816 {
817 pUserInfo->usri4_flags |= UF_ACCOUNTDISABLE;
818 }
819 else
820 {
821 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/ACTIVE");
822 result = 1;
823 goto done;
824 }
825 }
826 else if (_wcsnicmp(argv[j], L"/comment:", 9) == 0)
827 {
828 pUserInfo->usri4_comment = &argv[j][9];
829 }
830 else if (_wcsnicmp(argv[j], L"/countrycode:", 13) == 0)
831 {
832 p = &argv[i][13];
833 value = wcstoul(p, &endptr, 10);
834 if (*endptr != 0)
835 {
836 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/COUNTRYCODE");
837 result = 1;
838 goto done;
839 }
840
841 /* Verify the country code */
842 if (GetCountryFromCountryCode(value, 0, NULL))
843 pUserInfo->usri4_country_code = value;
844 }
845 else if (_wcsnicmp(argv[j], L"/expires:", 9) == 0)
846 {
847 p = &argv[i][9];
848 if (_wcsicmp(p, L"never") == 0)
849 {
850 pUserInfo->usri4_acct_expires = TIMEQ_FOREVER;
851 }
852 else if (!ParseDate(p, &pUserInfo->usri4_acct_expires))
853 {
854 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/EXPIRES");
855 result = 1;
856 goto done;
857 }
858 }
859 else if (_wcsnicmp(argv[j], L"/fullname:", 10) == 0)
860 {
861 pUserInfo->usri4_full_name = &argv[j][10];
862 }
863 else if (_wcsnicmp(argv[j], L"/homedir:", 9) == 0)
864 {
865 pUserInfo->usri4_home_dir = &argv[j][9];
866 }
867 else if (_wcsnicmp(argv[j], L"/passwordchg:", 13) == 0)
868 {
869 p = &argv[i][13];
870 if (_wcsicmp(p, L"yes") == 0)
871 {
872 pUserInfo->usri4_flags &= ~UF_PASSWD_CANT_CHANGE;
873 }
874 else if (_wcsicmp(p, L"no") == 0)
875 {
876 pUserInfo->usri4_flags |= UF_PASSWD_CANT_CHANGE;
877 }
878 else
879 {
880 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDCHG");
881 result = 1;
882 goto done;
883 }
884 }
885 else if (_wcsnicmp(argv[j], L"/passwordreq:", 13) == 0)
886 {
887 p = &argv[i][13];
888 if (_wcsicmp(p, L"yes") == 0)
889 {
890 pUserInfo->usri4_flags &= ~UF_PASSWD_NOTREQD;
891 }
892 else if (_wcsicmp(p, L"no") == 0)
893 {
894 pUserInfo->usri4_flags |= UF_PASSWD_NOTREQD;
895 }
896 else
897 {
898 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDREQ");
899 result = 1;
900 goto done;
901 }
902 }
903 else if (_wcsnicmp(argv[j], L"/profilepath:", 13) == 0)
904 {
905 pUserInfo->usri4_profile = &argv[j][13];
906 }
907 else if (_wcsnicmp(argv[j], L"/scriptpath:", 12) == 0)
908 {
909 pUserInfo->usri4_script_path = &argv[j][12];
910 }
911 else if (_wcsnicmp(argv[j], L"/times:", 7) == 0)
912 {
913 /* FIXME */
914 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/TIMES");
915 }
916 else if (_wcsnicmp(argv[j], L"/usercomment:", 13) == 0)
917 {
918 pUserInfo->usri4_usr_comment = &argv[j][13];
919 }
920 else if (_wcsnicmp(argv[j], L"/workstations:", 14) == 0)
921 {
922 p = &argv[i][14];
923 if (wcscmp(p, L"*") == 0 || wcscmp(p, L"") == 0)
924 {
925 pUserInfo->usri4_workstations = NULL;
926 }
927 else
928 {
929 Status = BuildWorkstationsList(&pWorkstations, p);
930 if (Status == NERR_Success)
931 {
932 pUserInfo->usri4_workstations = pWorkstations;
933 }
934 else
935 {
936 ConPrintf(StdOut, L"Status %lu\n\n", Status);
937 result = 1;
938 goto done;
939 }
940 }
941 }
942 }
943
944 if (!bAdd && !bDelete)
945 {
946 /* Modify the user */
947 Status = NetUserSetInfo(NULL,
948 lpUserName,
949 4,
950 (LPBYTE)pUserInfo,
951 NULL);
952 ConPrintf(StdOut, L"Status: %lu\n", Status);
953 }
954 else if (bAdd && !bDelete)
955 {
956 /* Add the user */
957 Status = NetUserAdd(NULL,
958 4,
959 (LPBYTE)pUserInfo,
960 NULL);
961 ConPrintf(StdOut, L"Status: %lu\n", Status);
962 }
963 else if (!bAdd && bDelete)
964 {
965 /* Delete the user */
966 Status = NetUserDel(NULL,
967 lpUserName);
968 ConPrintf(StdOut, L"Status: %lu\n", Status);
969 }
970
971 if (Status == NERR_Success &&
972 lpPassword != NULL &&
973 bRandomPassword == TRUE)
974 {
975 PrintMessageStringV(3968, lpUserName, lpPassword);
976 }
977
978 done:
979 if (pWorkstations != NULL)
980 HeapFree(GetProcessHeap(), 0, pWorkstations);
981
982 if ((bPasswordAllocated == TRUE) && (lpPassword != NULL))
983 HeapFree(GetProcessHeap(), 0, lpPassword);
984
985 if (!bAdd && !bDelete && pUserInfo != NULL)
986 NetApiBufferFree(pUserInfo);
987
988 if (result != 0)
989 {
990 ConResPuts(StdOut, IDS_GENERIC_SYNTAX);
991 PrintNetMessage(MSG_USER_SYNTAX);
992 }
993
994 return result;
995 }
996
997 /* EOF */