fd8450057a3806485dea1569d9bda7523b5f0a55
[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 static WCHAR szPasswordChars[] = L"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@#$%_-+:";
14
15 static
16 int
17 CompareInfo(const void *a, 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 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 ConPuts(StdOut, L"\n");
218
219 PrintPaddedResourceString(IDS_USER_PW_EXPIRES, nPaddedLength);
220 if ((pUserInfo->usri4_flags & UF_DONT_EXPIRE_PASSWD) || pUserModals->usrmod0_max_passwd_age == TIMEQ_FOREVER)
221 ConResPuts(StdOut, IDS_GENERIC_NEVER);
222 else
223 PrintDateTime(dwLastSet + pUserModals->usrmod0_max_passwd_age);
224 ConPuts(StdOut, L"\n");
225
226 PrintPaddedResourceString(IDS_USER_PW_CHANGEABLE, nPaddedLength);
227 PrintDateTime(dwLastSet + pUserModals->usrmod0_min_passwd_age);
228 ConPuts(StdOut, L"\n");
229
230 PrintPaddedResourceString(IDS_USER_PW_REQUIRED, nPaddedLength);
231 ConResPuts(StdOut, (pUserInfo->usri4_flags & UF_PASSWD_NOTREQD) ? IDS_GENERIC_NO : IDS_GENERIC_YES);
232 ConPuts(StdOut, L"\n");
233
234 PrintPaddedResourceString(IDS_USER_CHANGE_PW, nPaddedLength);
235 ConResPuts(StdOut, (pUserInfo->usri4_flags & UF_PASSWD_CANT_CHANGE) ? IDS_GENERIC_NO : IDS_GENERIC_YES);
236 ConPuts(StdOut, L"\n\n");
237
238 PrintPaddedResourceString(IDS_USER_WORKSTATIONS, nPaddedLength);
239 if (pUserInfo->usri4_workstations == NULL || wcslen(pUserInfo->usri4_workstations) == 0)
240 ConResPuts(StdOut, IDS_GENERIC_ALL);
241 else
242 ConPrintf(StdOut, L"%s", pUserInfo->usri4_workstations);
243 ConPuts(StdOut, L"\n");
244
245 PrintPaddedResourceString(IDS_USER_LOGON_SCRIPT, nPaddedLength);
246 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_script_path);
247
248 PrintPaddedResourceString(IDS_USER_PROFILE, nPaddedLength);
249 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_profile);
250
251 PrintPaddedResourceString(IDS_USER_HOME_DIR, nPaddedLength);
252 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_home_dir);
253
254 PrintPaddedResourceString(IDS_USER_LAST_LOGON, nPaddedLength);
255 if (pUserInfo->usri4_last_logon == 0)
256 ConResPuts(StdOut, IDS_GENERIC_NEVER);
257 else
258 PrintDateTime(pUserInfo->usri4_last_logon);
259 ConPuts(StdOut, L"\n\n");
260
261 PrintPaddedResourceString(IDS_USER_LOGON_HOURS, nPaddedLength);
262 if (pUserInfo->usri4_logon_hours == NULL)
263 ConResPuts(StdOut, IDS_GENERIC_ALL);
264 ConPuts(StdOut, L"\n\n");
265
266 ConPuts(StdOut, L"\n");
267 PrintPaddedResourceString(IDS_USER_LOCAL_GROUPS, nPaddedLength);
268 if (dwLocalGroupTotal != 0 && pLocalGroupInfo != NULL)
269 {
270 for (i = 0; i < dwLocalGroupTotal; i++)
271 {
272 if (i != 0)
273 PrintPadding(L' ', nPaddedLength);
274 ConPrintf(StdOut, L"*%s\n", pLocalGroupInfo[i].lgrui0_name);
275 }
276 }
277 else
278 {
279 ConPuts(StdOut, L"\n");
280 }
281
282 PrintPaddedResourceString(IDS_USER_GLOBAL_GROUPS, nPaddedLength);
283 if (dwGroupTotal != 0 && pGroupInfo != NULL)
284 {
285 for (i = 0; i < dwGroupTotal; i++)
286 {
287 if (i != 0)
288 PrintPadding(L' ', nPaddedLength);
289 ConPrintf(StdOut, L"*%s\n", pGroupInfo[i].grui0_name);
290 }
291 }
292 else
293 {
294 ConPuts(StdOut, L"\n");
295 }
296
297 done:
298 if (pGroupInfo != NULL)
299 NetApiBufferFree(pGroupInfo);
300
301 if (pLocalGroupInfo != NULL)
302 NetApiBufferFree(pLocalGroupInfo);
303
304 if (pUserModals != NULL)
305 NetApiBufferFree(pUserModals);
306
307 if (pUserInfo != NULL)
308 NetApiBufferFree(pUserInfo);
309
310 return NERR_Success;
311 }
312
313
314 static
315 VOID
316 ReadPassword(
317 LPWSTR *lpPassword,
318 LPBOOL lpAllocated)
319 {
320 WCHAR szPassword1[PWLEN + 1];
321 WCHAR szPassword2[PWLEN + 1];
322 LPWSTR ptr;
323
324 *lpAllocated = FALSE;
325
326 while (TRUE)
327 {
328 ConResPuts(StdOut, IDS_USER_ENTER_PASSWORD1);
329 ReadFromConsole(szPassword1, PWLEN + 1, FALSE);
330 ConPuts(StdOut, L"\n");
331
332 ConResPuts(StdOut, IDS_USER_ENTER_PASSWORD2);
333 ReadFromConsole(szPassword2, PWLEN + 1, FALSE);
334 ConPuts(StdOut, L"\n");
335
336 if (wcslen(szPassword1) == wcslen(szPassword2) &&
337 wcscmp(szPassword1, szPassword2) == 0)
338 {
339 ptr = HeapAlloc(GetProcessHeap(),
340 0,
341 (wcslen(szPassword1) + 1) * sizeof(WCHAR));
342 if (ptr != NULL)
343 {
344 wcscpy(ptr, szPassword1);
345 *lpPassword = ptr;
346 *lpAllocated = TRUE;
347 return;
348 }
349 }
350 else
351 {
352 ConPuts(StdOut, L"\n");
353 ConResPuts(StdOut, IDS_USER_NO_PASSWORD_MATCH);
354 ConPuts(StdOut, L"\n");
355 *lpPassword = NULL;
356 }
357 }
358 }
359
360
361 static
362 VOID
363 GenerateRandomPassword(
364 LPWSTR *lpPassword,
365 LPBOOL lpAllocated)
366 {
367 LPWSTR pPassword = NULL;
368 INT nCharsLen, i, nLength = 8;
369
370 srand(GetTickCount());
371
372 pPassword = HeapAlloc(GetProcessHeap(),
373 HEAP_ZERO_MEMORY,
374 (nLength + 1) * sizeof(WCHAR));
375 if (pPassword == NULL)
376 return;
377
378 nCharsLen = wcslen(szPasswordChars);
379
380 for (i = 0; i < nLength; i++)
381 {
382 pPassword[i] = szPasswordChars[rand() % nCharsLen];
383 }
384
385 *lpPassword = pPassword;
386 *lpAllocated = TRUE;
387 }
388
389
390 static
391 NET_API_STATUS
392 BuildWorkstationsList(
393 _Out_ PWSTR *pWorkstationsList,
394 _In_ PWSTR pRaw)
395 {
396 BOOL isLastSep, isSep;
397 INT i, j;
398 WCHAR c;
399 INT nLength = 0;
400 INT nArgs = 0;
401 INT nRawLength;
402 PWSTR pList;
403
404 /* Check for invalid characters in the raw string */
405 if (wcspbrk(pRaw, L"/[]=?\\+:.") != NULL)
406 return 3952;
407
408 /* Count the number of workstations in the list and
409 * the required buffer size */
410 isLastSep = FALSE;
411 isSep = FALSE;
412 nRawLength = wcslen(pRaw);
413 for (i = 0; i < nRawLength; i++)
414 {
415 c = pRaw[i];
416 if (c == L',' || c == L';')
417 isSep = TRUE;
418
419 if (isSep == TRUE)
420 {
421 if ((isLastSep == FALSE) && (i != 0) && (i != nRawLength - 1))
422 nLength++;
423 }
424 else
425 {
426 nLength++;
427
428 if (isLastSep == TRUE || (isLastSep == FALSE && i == 0))
429 nArgs++;
430 }
431
432 isLastSep = isSep;
433 isSep = FALSE;
434 }
435
436 nLength++;
437
438 /* Leave, if there are no workstations in the list */
439 if (nArgs == 0)
440 {
441 pWorkstationsList = NULL;
442 return NERR_Success;
443 }
444
445 /* Fail if there are more than eight workstations in the list */
446 if (nArgs > 8)
447 return 3951;
448
449 /* Allocate the buffer for the clean workstation list */
450 pList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
451 if (pList == NULL)
452 return ERROR_NOT_ENOUGH_MEMORY;
453
454 /* Build the clean workstation list */
455 isLastSep = FALSE;
456 isSep = FALSE;
457 nRawLength = wcslen(pRaw);
458 for (i = 0, j = 0; i < nRawLength; i++)
459 {
460 c = pRaw[i];
461 if (c == L',' || c == L';')
462 isSep = TRUE;
463
464 if (isSep == TRUE)
465 {
466 if ((isLastSep == FALSE) && (i != 0) && (i != nRawLength - 1))
467 {
468 pList[j] = L',';
469 j++;
470 }
471 }
472 else
473 {
474 pList[j] = c;
475 j++;
476
477 if (isLastSep == TRUE || (isLastSep == FALSE && i == 0))
478 nArgs++;
479 }
480
481 isLastSep = isSep;
482 isSep = FALSE;
483 }
484
485 *pWorkstationsList = pList;
486
487 return NERR_Success;
488 }
489
490
491 static
492 BOOL
493 ReadNumber(
494 PWSTR *s,
495 PWORD pwValue)
496 {
497 if (!iswdigit(**s))
498 return FALSE;
499
500 while (iswdigit(**s))
501 {
502 *pwValue = *pwValue * 10 + **s - L'0';
503 (*s)++;
504 }
505
506 return TRUE;
507 }
508
509
510 static
511 BOOL
512 ReadSeparator(
513 PWSTR *s)
514 {
515 if (**s == L'/' || **s == L'.')
516 {
517 (*s)++;
518 return TRUE;
519 }
520
521 return FALSE;
522 }
523
524
525 static
526 BOOL
527 ParseDate(
528 PWSTR s,
529 PULONG pSeconds)
530 {
531 SYSTEMTIME SystemTime = {0};
532 FILETIME LocalFileTime, FileTime;
533 LARGE_INTEGER Time;
534 INT nDateFormat = 0;
535 PWSTR p = s;
536
537 if (!*s)
538 return FALSE;
539
540 GetLocaleInfoW(LOCALE_USER_DEFAULT,
541 LOCALE_IDATE,
542 (PWSTR)&nDateFormat,
543 sizeof(INT));
544
545 switch (nDateFormat)
546 {
547 case 0: /* mmddyy */
548 default:
549 if (!ReadNumber(&p, &SystemTime.wMonth))
550 return FALSE;
551 if (!ReadSeparator(&p))
552 return FALSE;
553 if (!ReadNumber(&p, &SystemTime.wDay))
554 return FALSE;
555 if (!ReadSeparator(&p))
556 return FALSE;
557 if (!ReadNumber(&p, &SystemTime.wYear))
558 return FALSE;
559 break;
560
561 case 1: /* ddmmyy */
562 if (!ReadNumber(&p, &SystemTime.wDay))
563 return FALSE;
564 if (!ReadSeparator(&p))
565 return FALSE;
566 if (!ReadNumber(&p, &SystemTime.wMonth))
567 return FALSE;
568 if (!ReadSeparator(&p))
569 return FALSE;
570 if (!ReadNumber(&p, &SystemTime.wYear))
571 return FALSE;
572 break;
573
574 case 2: /* yymmdd */
575 if (!ReadNumber(&p, &SystemTime.wYear))
576 return FALSE;
577 if (!ReadSeparator(&p))
578 return FALSE;
579 if (!ReadNumber(&p, &SystemTime.wMonth))
580 return FALSE;
581 if (!ReadSeparator(&p))
582 return FALSE;
583 if (!ReadNumber(&p, &SystemTime.wDay))
584 return FALSE;
585 break;
586 }
587
588 /* if only entered two digits: */
589 /* assume 2000's if value less than 80 */
590 /* assume 1900's if value greater or equal 80 */
591 if (SystemTime.wYear <= 99)
592 {
593 if (SystemTime.wYear >= 80)
594 SystemTime.wYear += 1900;
595 else
596 SystemTime.wYear += 2000;
597 }
598
599 if (!SystemTimeToFileTime(&SystemTime, &LocalFileTime))
600 return FALSE;
601
602 if (!LocalFileTimeToFileTime(&LocalFileTime, &FileTime))
603 return FALSE;
604
605 Time.u.LowPart = FileTime.dwLowDateTime;
606 Time.u.HighPart = FileTime.dwHighDateTime;
607
608 if (!RtlTimeToSecondsSince1970(&Time, pSeconds))
609 return FALSE;
610
611 return TRUE;
612 }
613
614
615 INT
616 cmdUser(
617 INT argc,
618 WCHAR **argv)
619 {
620 INT i, j;
621 INT result = 0;
622 BOOL bAdd = FALSE;
623 BOOL bDelete = FALSE;
624 #if 0
625 BOOL bDomain = FALSE;
626 #endif
627 BOOL bRandomPassword = FALSE;
628 LPWSTR lpUserName = NULL;
629 LPWSTR lpPassword = NULL;
630 PUSER_INFO_4 pUserInfo = NULL;
631 USER_INFO_4 UserInfo;
632 LPWSTR pWorkstations = NULL;
633 LPWSTR p;
634 LPWSTR endptr;
635 DWORD value;
636 BOOL bPasswordAllocated = FALSE;
637 NET_API_STATUS Status;
638
639 if (argc == 2)
640 {
641 Status = EnumerateUsers();
642 ConPrintf(StdOut, L"Status: %lu\n", Status);
643 return 0;
644 }
645 else if (argc == 3)
646 {
647 Status = DisplayUser(argv[2]);
648 ConPrintf(StdOut, L"Status: %lu\n", Status);
649 return 0;
650 }
651
652 i = 2;
653 if (argv[i][0] != L'/')
654 {
655 lpUserName = argv[i];
656 // ConPrintf(StdOut, L"User: %s\n", lpUserName);
657 i++;
658 }
659
660 if (argv[i][0] != L'/')
661 {
662 lpPassword = argv[i];
663 // ConPrintf(StdOut, L"Password: %s\n", lpPassword);
664 i++;
665 }
666
667 for (j = i; j < argc; j++)
668 {
669 if (_wcsicmp(argv[j], L"/help") == 0)
670 {
671 ConResPuts(StdOut, IDS_USER_HELP);
672 return 0;
673 }
674 else if (_wcsicmp(argv[j], L"/add") == 0)
675 {
676 bAdd = TRUE;
677 }
678 else if (_wcsicmp(argv[j], L"/delete") == 0)
679 {
680 bDelete = TRUE;
681 }
682 else if (_wcsicmp(argv[j], L"/domain") == 0)
683 {
684 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/DOMAIN");
685 #if 0
686 bDomain = TRUE;
687 #endif
688 }
689 else if (_wcsicmp(argv[j], L"/random") == 0)
690 {
691 bRandomPassword = TRUE;
692 GenerateRandomPassword(&lpPassword,
693 &bPasswordAllocated);
694 }
695 }
696
697 if (bAdd && bDelete)
698 {
699 result = 1;
700 goto done;
701 }
702
703 /* Interactive password input */
704 if (lpPassword != NULL && wcscmp(lpPassword, L"*") == 0)
705 {
706 ReadPassword(&lpPassword,
707 &bPasswordAllocated);
708 }
709
710 if (!bAdd && !bDelete)
711 {
712 /* Modify the user */
713 Status = NetUserGetInfo(NULL,
714 lpUserName,
715 4,
716 (LPBYTE*)&pUserInfo);
717 if (Status != NERR_Success)
718 {
719 ConPrintf(StdOut, L"Status: %lu\n", Status);
720 result = 1;
721 goto done;
722 }
723 }
724 else if (bAdd && !bDelete)
725 {
726 /* Add the user */
727 ZeroMemory(&UserInfo, sizeof(USER_INFO_4));
728
729 UserInfo.usri4_name = lpUserName;
730 UserInfo.usri4_password = lpPassword;
731 UserInfo.usri4_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT;
732 UserInfo.usri4_acct_expires = TIMEQ_FOREVER;
733
734 pUserInfo = &UserInfo;
735 }
736
737 for (j = i; j < argc; j++)
738 {
739 if (_wcsnicmp(argv[j], L"/active:", 8) == 0)
740 {
741 p = &argv[i][8];
742 if (_wcsicmp(p, L"yes") == 0)
743 {
744 pUserInfo->usri4_flags &= ~UF_ACCOUNTDISABLE;
745 }
746 else if (_wcsicmp(p, L"no") == 0)
747 {
748 pUserInfo->usri4_flags |= UF_ACCOUNTDISABLE;
749 }
750 else
751 {
752 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/ACTIVE");
753 result = 1;
754 goto done;
755 }
756 }
757 else if (_wcsnicmp(argv[j], L"/comment:", 9) == 0)
758 {
759 pUserInfo->usri4_comment = &argv[j][9];
760 }
761 else if (_wcsnicmp(argv[j], L"/countrycode:", 13) == 0)
762 {
763 p = &argv[i][13];
764 value = wcstoul(p, &endptr, 10);
765 if (*endptr != 0)
766 {
767 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/COUNTRYCODE");
768 result = 1;
769 goto done;
770 }
771
772 /* FIXME: verify the country code */
773
774 pUserInfo->usri4_country_code = value;
775 }
776 else if (_wcsnicmp(argv[j], L"/expires:", 9) == 0)
777 {
778 p = &argv[i][9];
779 if (_wcsicmp(p, L"never") == 0)
780 {
781 pUserInfo->usri4_acct_expires = TIMEQ_FOREVER;
782 }
783 else if (!ParseDate(p, &pUserInfo->usri4_acct_expires))
784 {
785 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/EXPIRES");
786 result = 1;
787 goto done;
788
789 /* FIXME: Parse the date */
790 // ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/EXPIRES");
791 }
792 }
793 else if (_wcsnicmp(argv[j], L"/fullname:", 10) == 0)
794 {
795 pUserInfo->usri4_full_name = &argv[j][10];
796 }
797 else if (_wcsnicmp(argv[j], L"/homedir:", 9) == 0)
798 {
799 pUserInfo->usri4_home_dir = &argv[j][9];
800 }
801 else if (_wcsnicmp(argv[j], L"/passwordchg:", 13) == 0)
802 {
803 p = &argv[i][13];
804 if (_wcsicmp(p, L"yes") == 0)
805 {
806 pUserInfo->usri4_flags &= ~UF_PASSWD_CANT_CHANGE;
807 }
808 else if (_wcsicmp(p, L"no") == 0)
809 {
810 pUserInfo->usri4_flags |= UF_PASSWD_CANT_CHANGE;
811 }
812 else
813 {
814 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDCHG");
815 result = 1;
816 goto done;
817 }
818 }
819 else if (_wcsnicmp(argv[j], L"/passwordreq:", 13) == 0)
820 {
821 p = &argv[i][13];
822 if (_wcsicmp(p, L"yes") == 0)
823 {
824 pUserInfo->usri4_flags &= ~UF_PASSWD_NOTREQD;
825 }
826 else if (_wcsicmp(p, L"no") == 0)
827 {
828 pUserInfo->usri4_flags |= UF_PASSWD_NOTREQD;
829 }
830 else
831 {
832 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDREQ");
833 result = 1;
834 goto done;
835 }
836 }
837 else if (_wcsnicmp(argv[j], L"/profilepath:", 13) == 0)
838 {
839 pUserInfo->usri4_profile = &argv[j][13];
840 }
841 else if (_wcsnicmp(argv[j], L"/scriptpath:", 12) == 0)
842 {
843 pUserInfo->usri4_script_path = &argv[j][12];
844 }
845 else if (_wcsnicmp(argv[j], L"/times:", 7) == 0)
846 {
847 /* FIXME */
848 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/TIMES");
849 }
850 else if (_wcsnicmp(argv[j], L"/usercomment:", 13) == 0)
851 {
852 pUserInfo->usri4_usr_comment = &argv[j][13];
853 }
854 else if (_wcsnicmp(argv[j], L"/workstations:", 14) == 0)
855 {
856 p = &argv[i][14];
857 if (wcscmp(p, L"*") == 0 || wcscmp(p, L"") == 0)
858 {
859 pUserInfo->usri4_workstations = NULL;
860 }
861 else
862 {
863 Status = BuildWorkstationsList(&pWorkstations, p);
864 if (Status == NERR_Success)
865 {
866 pUserInfo->usri4_workstations = pWorkstations;
867 }
868 else
869 {
870 ConPrintf(StdOut, L"Status %lu\n\n", Status);
871 result = 1;
872 goto done;
873 }
874 }
875 }
876 }
877
878 if (!bAdd && !bDelete)
879 {
880 /* Modify the user */
881 Status = NetUserSetInfo(NULL,
882 lpUserName,
883 4,
884 (LPBYTE)pUserInfo,
885 NULL);
886 ConPrintf(StdOut, L"Status: %lu\n", Status);
887 }
888 else if (bAdd && !bDelete)
889 {
890 /* Add the user */
891 Status = NetUserAdd(NULL,
892 4,
893 (LPBYTE)pUserInfo,
894 NULL);
895 ConPrintf(StdOut, L"Status: %lu\n", Status);
896 }
897 else if (!bAdd && bDelete)
898 {
899 /* Delete the user */
900 Status = NetUserDel(NULL,
901 lpUserName);
902 ConPrintf(StdOut, L"Status: %lu\n", Status);
903 }
904
905 if (Status == NERR_Success &&
906 lpPassword != NULL &&
907 bRandomPassword == TRUE)
908 {
909 ConPrintf(StdOut, L"The password for %s is: %s\n", lpUserName, lpPassword);
910 }
911
912 done:
913 if (pWorkstations != NULL)
914 HeapFree(GetProcessHeap(), 0, pWorkstations);
915
916 if ((bPasswordAllocated == TRUE) && (lpPassword != NULL))
917 HeapFree(GetProcessHeap(), 0, lpPassword);
918
919 if (!bAdd && !bDelete && pUserInfo != NULL)
920 NetApiBufferFree(pUserInfo);
921
922 if (result != 0)
923 {
924 ConResPuts(StdOut, IDS_GENERIC_SYNTAX);
925 ConResPuts(StdOut, IDS_USER_SYNTAX);
926 }
927
928 return result;
929 }
930
931 /* EOF */