[NET] Add the workstations option to the user command
[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_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 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 INT
492 cmdUser(
493 INT argc,
494 WCHAR **argv)
495 {
496 INT i, j;
497 INT result = 0;
498 BOOL bAdd = FALSE;
499 BOOL bDelete = FALSE;
500 #if 0
501 BOOL bDomain = FALSE;
502 #endif
503 BOOL bRandomPassword = FALSE;
504 LPWSTR lpUserName = NULL;
505 LPWSTR lpPassword = NULL;
506 PUSER_INFO_4 pUserInfo = NULL;
507 USER_INFO_4 UserInfo;
508 LPWSTR pWorkstations = NULL;
509 LPWSTR p;
510 LPWSTR endptr;
511 DWORD value;
512 BOOL bPasswordAllocated = FALSE;
513 NET_API_STATUS Status;
514
515 if (argc == 2)
516 {
517 Status = EnumerateUsers();
518 ConPrintf(StdOut, L"Status: %lu\n", Status);
519 return 0;
520 }
521 else if (argc == 3)
522 {
523 Status = DisplayUser(argv[2]);
524 ConPrintf(StdOut, L"Status: %lu\n", Status);
525 return 0;
526 }
527
528 i = 2;
529 if (argv[i][0] != L'/')
530 {
531 lpUserName = argv[i];
532 // ConPrintf(StdOut, L"User: %s\n", lpUserName);
533 i++;
534 }
535
536 if (argv[i][0] != L'/')
537 {
538 lpPassword = argv[i];
539 // ConPrintf(StdOut, L"Password: %s\n", lpPassword);
540 i++;
541 }
542
543 for (j = i; j < argc; j++)
544 {
545 if (_wcsicmp(argv[j], L"/help") == 0)
546 {
547 ConResPuts(StdOut, IDS_USER_HELP);
548 return 0;
549 }
550 else if (_wcsicmp(argv[j], L"/add") == 0)
551 {
552 bAdd = TRUE;
553 }
554 else if (_wcsicmp(argv[j], L"/delete") == 0)
555 {
556 bDelete = TRUE;
557 }
558 else if (_wcsicmp(argv[j], L"/domain") == 0)
559 {
560 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/DOMAIN");
561 #if 0
562 bDomain = TRUE;
563 #endif
564 }
565 else if (_wcsicmp(argv[j], L"/random") == 0)
566 {
567 bRandomPassword = TRUE;
568 GenerateRandomPassword(&lpPassword,
569 &bPasswordAllocated);
570 }
571 }
572
573 if (bAdd && bDelete)
574 {
575 result = 1;
576 goto done;
577 }
578
579 /* Interactive password input */
580 if (lpPassword != NULL && wcscmp(lpPassword, L"*") == 0)
581 {
582 ReadPassword(&lpPassword,
583 &bPasswordAllocated);
584 }
585
586 if (!bAdd && !bDelete)
587 {
588 /* Modify the user */
589 Status = NetUserGetInfo(NULL,
590 lpUserName,
591 4,
592 (LPBYTE*)&pUserInfo);
593 if (Status != NERR_Success)
594 {
595 ConPrintf(StdOut, L"Status: %lu\n", Status);
596 result = 1;
597 goto done;
598 }
599 }
600 else if (bAdd && !bDelete)
601 {
602 /* Add the user */
603 ZeroMemory(&UserInfo, sizeof(USER_INFO_4));
604
605 UserInfo.usri4_name = lpUserName;
606 UserInfo.usri4_password = lpPassword;
607 UserInfo.usri4_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT;
608
609 pUserInfo = &UserInfo;
610 }
611
612 for (j = i; j < argc; j++)
613 {
614 if (_wcsnicmp(argv[j], L"/active:", 8) == 0)
615 {
616 p = &argv[i][8];
617 if (_wcsicmp(p, L"yes") == 0)
618 {
619 pUserInfo->usri4_flags &= ~UF_ACCOUNTDISABLE;
620 }
621 else if (_wcsicmp(p, L"no") == 0)
622 {
623 pUserInfo->usri4_flags |= UF_ACCOUNTDISABLE;
624 }
625 else
626 {
627 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/ACTIVE");
628 result = 1;
629 goto done;
630 }
631 }
632 else if (_wcsnicmp(argv[j], L"/comment:", 9) == 0)
633 {
634 pUserInfo->usri4_comment = &argv[j][9];
635 }
636 else if (_wcsnicmp(argv[j], L"/countrycode:", 13) == 0)
637 {
638 p = &argv[i][13];
639 value = wcstoul(p, &endptr, 10);
640 if (*endptr != 0)
641 {
642 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/COUNTRYCODE");
643 result = 1;
644 goto done;
645 }
646
647 /* FIXME: verify the country code */
648
649 pUserInfo->usri4_country_code = value;
650 }
651 else if (_wcsnicmp(argv[j], L"/expires:", 9) == 0)
652 {
653 p = &argv[i][9];
654 if (_wcsicmp(p, L"never") == 0)
655 {
656 pUserInfo->usri4_acct_expires = TIMEQ_FOREVER;
657 }
658 else
659 {
660 /* FIXME: Parse the date */
661 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/EXPIRES");
662 }
663 }
664 else if (_wcsnicmp(argv[j], L"/fullname:", 10) == 0)
665 {
666 pUserInfo->usri4_full_name = &argv[j][10];
667 }
668 else if (_wcsnicmp(argv[j], L"/homedir:", 9) == 0)
669 {
670 pUserInfo->usri4_home_dir = &argv[j][9];
671 }
672 else if (_wcsnicmp(argv[j], L"/passwordchg:", 13) == 0)
673 {
674 p = &argv[i][13];
675 if (_wcsicmp(p, L"yes") == 0)
676 {
677 pUserInfo->usri4_flags &= ~UF_PASSWD_CANT_CHANGE;
678 }
679 else if (_wcsicmp(p, L"no") == 0)
680 {
681 pUserInfo->usri4_flags |= UF_PASSWD_CANT_CHANGE;
682 }
683 else
684 {
685 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDCHG");
686 result = 1;
687 goto done;
688 }
689 }
690 else if (_wcsnicmp(argv[j], L"/passwordreq:", 13) == 0)
691 {
692 p = &argv[i][13];
693 if (_wcsicmp(p, L"yes") == 0)
694 {
695 pUserInfo->usri4_flags &= ~UF_PASSWD_NOTREQD;
696 }
697 else if (_wcsicmp(p, L"no") == 0)
698 {
699 pUserInfo->usri4_flags |= UF_PASSWD_NOTREQD;
700 }
701 else
702 {
703 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDREQ");
704 result = 1;
705 goto done;
706 }
707 }
708 else if (_wcsnicmp(argv[j], L"/profilepath:", 13) == 0)
709 {
710 pUserInfo->usri4_profile = &argv[j][13];
711 }
712 else if (_wcsnicmp(argv[j], L"/scriptpath:", 12) == 0)
713 {
714 pUserInfo->usri4_script_path = &argv[j][12];
715 }
716 else if (_wcsnicmp(argv[j], L"/times:", 7) == 0)
717 {
718 /* FIXME */
719 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/TIMES");
720 }
721 else if (_wcsnicmp(argv[j], L"/usercomment:", 13) == 0)
722 {
723 pUserInfo->usri4_usr_comment = &argv[j][13];
724 }
725 else if (_wcsnicmp(argv[j], L"/workstations:", 14) == 0)
726 {
727 p = &argv[i][14];
728 if (wcscmp(p, L"*") == 0 || wcscmp(p, L"") == 0)
729 {
730 pUserInfo->usri4_workstations = NULL;
731 }
732 else
733 {
734 Status = BuildWorkstationsList(&pWorkstations, p);
735 if (Status == NERR_Success)
736 {
737 pUserInfo->usri4_workstations = pWorkstations;
738 }
739 else
740 {
741 ConPrintf(StdOut, L"Status %lu\n\n", Status);
742 result = 1;
743 goto done;
744 }
745 }
746 }
747 }
748
749 if (!bAdd && !bDelete)
750 {
751 /* Modify the user */
752 Status = NetUserSetInfo(NULL,
753 lpUserName,
754 4,
755 (LPBYTE)pUserInfo,
756 NULL);
757 ConPrintf(StdOut, L"Status: %lu\n", Status);
758 }
759 else if (bAdd && !bDelete)
760 {
761 /* Add the user */
762 Status = NetUserAdd(NULL,
763 4,
764 (LPBYTE)pUserInfo,
765 NULL);
766 ConPrintf(StdOut, L"Status: %lu\n", Status);
767 }
768 else if (!bAdd && bDelete)
769 {
770 /* Delete the user */
771 Status = NetUserDel(NULL,
772 lpUserName);
773 ConPrintf(StdOut, L"Status: %lu\n", Status);
774 }
775
776 if (Status == NERR_Success &&
777 lpPassword != NULL &&
778 bRandomPassword == TRUE)
779 {
780 ConPrintf(StdOut, L"The password for %s is: %s\n", lpUserName, lpPassword);
781 }
782
783 done:
784 if (pWorkstations != NULL)
785 HeapFree(GetProcessHeap(), 0, pWorkstations);
786
787 if ((bPasswordAllocated == TRUE) && (lpPassword != NULL))
788 HeapFree(GetProcessHeap(), 0, lpPassword);
789
790 if (!bAdd && !bDelete && pUserInfo != NULL)
791 NetApiBufferFree(pUserInfo);
792
793 if (result != 0)
794 {
795 ConResPuts(StdOut, IDS_GENERIC_SYNTAX);
796 ConResPuts(StdOut, IDS_USER_SYNTAX);
797 }
798
799 return result;
800 }
801
802 /* EOF */