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 UserInfo.usri4_primary_group_id = DOMAIN_GROUP_RID_USERS; 734 735 pUserInfo = &UserInfo; 736 } 737 738 for (j = i; j < argc; j++) 739 { 740 if (_wcsnicmp(argv[j], L"/active:", 8) == 0) 741 { 742 p = &argv[i][8]; 743 if (_wcsicmp(p, L"yes") == 0) 744 { 745 pUserInfo->usri4_flags &= ~UF_ACCOUNTDISABLE; 746 } 747 else if (_wcsicmp(p, L"no") == 0) 748 { 749 pUserInfo->usri4_flags |= UF_ACCOUNTDISABLE; 750 } 751 else 752 { 753 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/ACTIVE"); 754 result = 1; 755 goto done; 756 } 757 } 758 else if (_wcsnicmp(argv[j], L"/comment:", 9) == 0) 759 { 760 pUserInfo->usri4_comment = &argv[j][9]; 761 } 762 else if (_wcsnicmp(argv[j], L"/countrycode:", 13) == 0) 763 { 764 p = &argv[i][13]; 765 value = wcstoul(p, &endptr, 10); 766 if (*endptr != 0) 767 { 768 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/COUNTRYCODE"); 769 result = 1; 770 goto done; 771 } 772 773 /* FIXME: verify the country code */ 774 775 pUserInfo->usri4_country_code = value; 776 } 777 else if (_wcsnicmp(argv[j], L"/expires:", 9) == 0) 778 { 779 p = &argv[i][9]; 780 if (_wcsicmp(p, L"never") == 0) 781 { 782 pUserInfo->usri4_acct_expires = TIMEQ_FOREVER; 783 } 784 else if (!ParseDate(p, &pUserInfo->usri4_acct_expires)) 785 { 786 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/EXPIRES"); 787 result = 1; 788 goto done; 789 790 /* FIXME: Parse the date */ 791 // ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/EXPIRES"); 792 } 793 } 794 else if (_wcsnicmp(argv[j], L"/fullname:", 10) == 0) 795 { 796 pUserInfo->usri4_full_name = &argv[j][10]; 797 } 798 else if (_wcsnicmp(argv[j], L"/homedir:", 9) == 0) 799 { 800 pUserInfo->usri4_home_dir = &argv[j][9]; 801 } 802 else if (_wcsnicmp(argv[j], L"/passwordchg:", 13) == 0) 803 { 804 p = &argv[i][13]; 805 if (_wcsicmp(p, L"yes") == 0) 806 { 807 pUserInfo->usri4_flags &= ~UF_PASSWD_CANT_CHANGE; 808 } 809 else if (_wcsicmp(p, L"no") == 0) 810 { 811 pUserInfo->usri4_flags |= UF_PASSWD_CANT_CHANGE; 812 } 813 else 814 { 815 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDCHG"); 816 result = 1; 817 goto done; 818 } 819 } 820 else if (_wcsnicmp(argv[j], L"/passwordreq:", 13) == 0) 821 { 822 p = &argv[i][13]; 823 if (_wcsicmp(p, L"yes") == 0) 824 { 825 pUserInfo->usri4_flags &= ~UF_PASSWD_NOTREQD; 826 } 827 else if (_wcsicmp(p, L"no") == 0) 828 { 829 pUserInfo->usri4_flags |= UF_PASSWD_NOTREQD; 830 } 831 else 832 { 833 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDREQ"); 834 result = 1; 835 goto done; 836 } 837 } 838 else if (_wcsnicmp(argv[j], L"/profilepath:", 13) == 0) 839 { 840 pUserInfo->usri4_profile = &argv[j][13]; 841 } 842 else if (_wcsnicmp(argv[j], L"/scriptpath:", 12) == 0) 843 { 844 pUserInfo->usri4_script_path = &argv[j][12]; 845 } 846 else if (_wcsnicmp(argv[j], L"/times:", 7) == 0) 847 { 848 /* FIXME */ 849 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/TIMES"); 850 } 851 else if (_wcsnicmp(argv[j], L"/usercomment:", 13) == 0) 852 { 853 pUserInfo->usri4_usr_comment = &argv[j][13]; 854 } 855 else if (_wcsnicmp(argv[j], L"/workstations:", 14) == 0) 856 { 857 p = &argv[i][14]; 858 if (wcscmp(p, L"*") == 0 || wcscmp(p, L"") == 0) 859 { 860 pUserInfo->usri4_workstations = NULL; 861 } 862 else 863 { 864 Status = BuildWorkstationsList(&pWorkstations, p); 865 if (Status == NERR_Success) 866 { 867 pUserInfo->usri4_workstations = pWorkstations; 868 } 869 else 870 { 871 ConPrintf(StdOut, L"Status %lu\n\n", Status); 872 result = 1; 873 goto done; 874 } 875 } 876 } 877 } 878 879 if (!bAdd && !bDelete) 880 { 881 /* Modify the user */ 882 Status = NetUserSetInfo(NULL, 883 lpUserName, 884 4, 885 (LPBYTE)pUserInfo, 886 NULL); 887 ConPrintf(StdOut, L"Status: %lu\n", Status); 888 } 889 else if (bAdd && !bDelete) 890 { 891 /* Add the user */ 892 Status = NetUserAdd(NULL, 893 4, 894 (LPBYTE)pUserInfo, 895 NULL); 896 ConPrintf(StdOut, L"Status: %lu\n", Status); 897 } 898 else if (!bAdd && bDelete) 899 { 900 /* Delete the user */ 901 Status = NetUserDel(NULL, 902 lpUserName); 903 ConPrintf(StdOut, L"Status: %lu\n", Status); 904 } 905 906 if (Status == NERR_Success && 907 lpPassword != NULL && 908 bRandomPassword == TRUE) 909 { 910 ConPrintf(StdOut, L"The password for %s is: %s\n", lpUserName, lpPassword); 911 } 912 913 done: 914 if (pWorkstations != NULL) 915 HeapFree(GetProcessHeap(), 0, pWorkstations); 916 917 if ((bPasswordAllocated == TRUE) && (lpPassword != NULL)) 918 HeapFree(GetProcessHeap(), 0, lpPassword); 919 920 if (!bAdd && !bDelete && pUserInfo != NULL) 921 NetApiBufferFree(pUserInfo); 922 923 if (result != 0) 924 { 925 ConResPuts(StdOut, IDS_GENERIC_SYNTAX); 926 ConResPuts(StdOut, IDS_USER_SYNTAX); 927 } 928 929 return result; 930 } 931 932 /* EOF */ 933