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 #define SECONDS_PER_DAY (60 * 60 * 24) 14 #define SECONDS_PER_HOUR (60 * 60) 15 #define HOURS_PER_DAY 24 16 #define DAYS_PER_WEEK 7 17 18 typedef struct _COUNTY_TABLE 19 { 20 DWORD dwCountryCode; 21 DWORD dwMessageId; 22 } COUNTRY_TABLE, *PCOUNTRY_TABLE; 23 24 25 static WCHAR szPasswordChars[] = L"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@#$%_-+:"; 26 static COUNTRY_TABLE CountryTable[] = 27 { { 0, 5080}, // System Default 28 { 1, 5081}, // United States 29 { 2, 5082}, // Canada (French) 30 { 3, 5083}, // Latin America 31 { 31, 5084}, // Netherlands 32 { 32, 5085}, // Belgium 33 { 33, 5086}, // France 34 { 34, 5090}, // Spain 35 { 39, 5087}, // Italy 36 { 41, 5088}, // Switzerland 37 { 44, 5089}, // United Kingdom 38 { 45, 5091}, // Denmark 39 { 46, 5092}, // Sweden 40 { 47, 5093}, // Norway 41 { 49, 5094}, // Germany 42 { 61, 5095}, // Australia 43 { 81, 5096}, // Japan 44 { 82, 5097}, // Korea 45 { 86, 5098}, // China (PRC) 46 { 88, 5099}, // Taiwan 47 { 99, 5100}, // Asia 48 {351, 5101}, // Portugal 49 {358, 5102}, // Finland 50 {785, 5103}, // Arabic 51 {972, 5104} }; // Hebrew 52 53 54 static 55 int 56 CompareInfo(const void *a, const void *b) 57 { 58 return _wcsicmp(((PUSER_INFO_0)a)->usri0_name, 59 ((PUSER_INFO_0)b)->usri0_name); 60 } 61 62 63 static 64 NET_API_STATUS 65 EnumerateUsers(VOID) 66 { 67 PUSER_INFO_0 pBuffer = NULL; 68 PSERVER_INFO_100 pServer = NULL; 69 DWORD dwRead = 0, dwTotal = 0; 70 DWORD i; 71 DWORD ResumeHandle = 0; 72 NET_API_STATUS Status; 73 74 Status = NetServerGetInfo(NULL, 75 100, 76 (LPBYTE*)&pServer); 77 if (Status != NERR_Success) 78 return Status; 79 80 ConPuts(StdOut, L"\n"); 81 PrintMessageStringV(4410, pServer->sv100_name); 82 ConPuts(StdOut, L"\n"); 83 PrintPadding(L'-', 79); 84 ConPuts(StdOut, L"\n"); 85 86 NetApiBufferFree(pServer); 87 88 do 89 { 90 Status = NetUserEnum(NULL, 91 0, 92 0, 93 (LPBYTE*)&pBuffer, 94 MAX_PREFERRED_LENGTH, 95 &dwRead, 96 &dwTotal, 97 &ResumeHandle); 98 if ((Status != NERR_Success) && (Status != ERROR_MORE_DATA)) 99 return Status; 100 101 qsort(pBuffer, 102 dwRead, 103 sizeof(PUSER_INFO_0), 104 CompareInfo); 105 106 for (i = 0; i < dwRead; i++) 107 { 108 if (pBuffer[i].usri0_name) 109 ConPrintf(StdOut, L"%s\n", pBuffer[i].usri0_name); 110 } 111 112 NetApiBufferFree(pBuffer); 113 pBuffer = NULL; 114 } 115 while (Status == ERROR_MORE_DATA); 116 117 return NERR_Success; 118 } 119 120 121 static 122 VOID 123 PrintDateTime(DWORD dwSeconds) 124 { 125 LARGE_INTEGER Time; 126 FILETIME FileTime; 127 SYSTEMTIME SystemTime; 128 WCHAR DateBuffer[80]; 129 WCHAR TimeBuffer[80]; 130 131 RtlSecondsSince1970ToTime(dwSeconds, &Time); 132 FileTime.dwLowDateTime = Time.u.LowPart; 133 FileTime.dwHighDateTime = Time.u.HighPart; 134 FileTimeToLocalFileTime(&FileTime, &FileTime); 135 FileTimeToSystemTime(&FileTime, &SystemTime); 136 137 GetDateFormatW(LOCALE_USER_DEFAULT, 138 DATE_SHORTDATE, 139 &SystemTime, 140 NULL, 141 DateBuffer, 142 ARRAYSIZE(DateBuffer)); 143 144 GetTimeFormatW(LOCALE_USER_DEFAULT, 145 TIME_NOSECONDS, 146 &SystemTime, 147 NULL, 148 TimeBuffer, 149 ARRAYSIZE(TimeBuffer)); 150 151 ConPrintf(StdOut, L"%s %s", DateBuffer, TimeBuffer); 152 } 153 154 155 static 156 VOID 157 PrintLocalTime(DWORD dwSeconds) 158 { 159 LARGE_INTEGER Time; 160 FILETIME FileTime; 161 SYSTEMTIME SystemTime; 162 WCHAR TimeBuffer[80]; 163 164 RtlSecondsSince1970ToTime(dwSeconds, &Time); 165 FileTime.dwLowDateTime = Time.u.LowPart; 166 FileTime.dwHighDateTime = Time.u.HighPart; 167 FileTimeToSystemTime(&FileTime, &SystemTime); 168 169 GetTimeFormatW(LOCALE_USER_DEFAULT, 170 TIME_NOSECONDS, 171 &SystemTime, 172 NULL, 173 TimeBuffer, 174 ARRAYSIZE(TimeBuffer)); 175 176 ConPrintf(StdOut, L"%s", TimeBuffer); 177 } 178 179 180 static 181 DWORD 182 GetTimeInSeconds(VOID) 183 { 184 LARGE_INTEGER Time; 185 FILETIME FileTime; 186 DWORD dwSeconds; 187 188 GetSystemTimeAsFileTime(&FileTime); 189 Time.u.LowPart = FileTime.dwLowDateTime; 190 Time.u.HighPart = FileTime.dwHighDateTime; 191 RtlTimeToSecondsSince1970(&Time, &dwSeconds); 192 193 return dwSeconds; 194 } 195 196 197 static 198 BOOL 199 GetCountryFromCountryCode( 200 _In_ DWORD dwCountryCode, 201 _In_ DWORD dwCountryLength, 202 _Out_ PWSTR szCountryBuffer) 203 { 204 DWORD i; 205 206 for (i = 0; i < ARRAYSIZE(CountryTable); i++) 207 { 208 if (CountryTable[i].dwCountryCode == dwCountryCode) 209 { 210 if (szCountryBuffer != NULL && dwCountryLength > 0) 211 { 212 FormatMessageW(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, 213 hModuleNetMsg, 214 CountryTable[i].dwMessageId, 215 LANG_USER_DEFAULT, 216 szCountryBuffer, 217 dwCountryLength, 218 NULL); 219 } 220 221 return TRUE; 222 } 223 } 224 225 return FALSE; 226 } 227 228 229 static 230 BOOL 231 GetBitValue( 232 PBYTE pBitmap, 233 DWORD dwBitNumber) 234 { 235 DWORD dwIndex = dwBitNumber / 8; 236 BYTE Mask = 1 << (dwBitNumber & 7); 237 238 return ((pBitmap[dwIndex] & Mask) != 0); 239 } 240 241 242 static 243 VOID 244 SetBitValue( 245 PBYTE pBitmap, 246 DWORD dwBitNumber) 247 { 248 DWORD dwIndex = dwBitNumber / 8; 249 BYTE Mask = 1 << (dwBitNumber & 7); 250 251 pBitmap[dwIndex] |= Mask; 252 } 253 254 255 static 256 VOID 257 PrintLogonHours( 258 DWORD dwUnitsPerWeek, 259 PBYTE pLogonHours, 260 INT nPaddedLength) 261 { 262 DWORD dwUnitsPerDay, dwBitNumber, dwSecondsPerUnit; 263 DWORD dwStartTime, dwEndTime, dwStartDay, dwEndDay, dwBias; 264 BOOL bBitValue, bFirst = TRUE; 265 TIME_ZONE_INFORMATION TimeZoneInformation; 266 267 GetTimeZoneInformation(&TimeZoneInformation); 268 dwBias = (TimeZoneInformation.Bias / 60) * SECONDS_PER_HOUR; 269 270 if ((dwUnitsPerWeek == 0) || 271 ((dwUnitsPerWeek %7) != 0)) 272 return; 273 274 dwUnitsPerDay = dwUnitsPerWeek / 7; 275 276 if (((dwUnitsPerDay % 24) != 0) || 277 ((dwUnitsPerDay / 24) > 6)) 278 return; 279 280 dwSecondsPerUnit = (SECONDS_PER_DAY) / dwUnitsPerDay; 281 282 for (dwBitNumber = 0; dwBitNumber < dwUnitsPerWeek; dwBitNumber++) 283 { 284 bBitValue = GetBitValue(pLogonHours, dwBitNumber); 285 if (bBitValue) 286 { 287 dwStartTime = dwSecondsPerUnit * dwBitNumber; 288 289 while (bBitValue != 0 && dwBitNumber < dwUnitsPerWeek) 290 { 291 dwBitNumber++; 292 if (dwBitNumber < dwUnitsPerWeek) 293 bBitValue = GetBitValue(pLogonHours, dwBitNumber); 294 } 295 296 dwEndTime = dwSecondsPerUnit * dwBitNumber; 297 298 if (!bFirst) 299 PrintPadding(L' ', nPaddedLength); 300 301 if (dwStartTime == 0 && dwEndTime == (SECONDS_PER_DAY * 7)) 302 { 303 PrintMessageString(4302); 304 ConPuts(StdOut, L"\n"); 305 } 306 else 307 { 308 dwStartDay = dwStartTime / SECONDS_PER_DAY; 309 dwEndDay = (dwEndTime / SECONDS_PER_DAY) % 7; 310 311 PrintMessageString(4307 + dwStartDay); 312 ConPuts(StdOut, L" "); 313 314 /* Convert from GMT to local timezone */ 315 PrintLocalTime((dwStartTime % SECONDS_PER_DAY) - dwBias); 316 317 ConPrintf(StdOut, L" - "); 318 if (dwStartDay != dwEndDay) 319 { 320 PrintMessageString(4307 + dwEndDay); 321 ConPuts(StdOut, L" "); 322 } 323 324 /* Convert from GMT to local timezone */ 325 PrintLocalTime((dwEndTime % SECONDS_PER_DAY) - dwBias); 326 ConPuts(StdOut, L"\n"); 327 } 328 329 bFirst = FALSE; 330 } 331 } 332 333 if (bFirst) 334 { 335 /* No logon hours */ 336 PrintMessageString(4434); 337 ConPuts(StdOut, L"\n"); 338 } 339 } 340 341 342 static 343 NET_API_STATUS 344 DisplayUser(LPWSTR lpUserName) 345 { 346 PUSER_MODALS_INFO_0 pUserModals = NULL; 347 PUSER_INFO_4 pUserInfo = NULL; 348 PLOCALGROUP_USERS_INFO_0 pLocalGroupInfo = NULL; 349 PGROUP_USERS_INFO_0 pGroupInfo = NULL; 350 DWORD dwLocalGroupRead, dwLocalGroupTotal; 351 DWORD dwGroupRead, dwGroupTotal; 352 DWORD dwLastSet; 353 DWORD i; 354 WCHAR szCountry[40]; 355 INT nPaddedLength = 36; 356 NET_API_STATUS Status; 357 358 /* Modify the user */ 359 Status = NetUserGetInfo(NULL, 360 lpUserName, 361 4, 362 (LPBYTE*)&pUserInfo); 363 if (Status != NERR_Success) 364 return Status; 365 366 Status = NetUserModalsGet(NULL, 367 0, 368 (LPBYTE*)&pUserModals); 369 if (Status != NERR_Success) 370 goto done; 371 372 Status = NetUserGetLocalGroups(NULL, 373 lpUserName, 374 0, 375 0, 376 (LPBYTE*)&pLocalGroupInfo, 377 MAX_PREFERRED_LENGTH, 378 &dwLocalGroupRead, 379 &dwLocalGroupTotal); 380 if (Status != NERR_Success) 381 goto done; 382 383 Status = NetUserGetGroups(NULL, 384 lpUserName, 385 0, 386 (LPBYTE*)&pGroupInfo, 387 MAX_PREFERRED_LENGTH, 388 &dwGroupRead, 389 &dwGroupTotal); 390 if (Status != NERR_Success) 391 goto done; 392 393 PrintPaddedMessageString(4411, nPaddedLength); 394 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_name); 395 396 PrintPaddedMessageString(4412, nPaddedLength); 397 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_full_name); 398 399 PrintPaddedMessageString(4413, nPaddedLength); 400 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_comment); 401 402 PrintPaddedMessageString(4414, nPaddedLength); 403 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_usr_comment); 404 405 PrintPaddedMessageString(4416, nPaddedLength); 406 GetCountryFromCountryCode(pUserInfo->usri4_country_code, 407 ARRAYSIZE(szCountry), szCountry); 408 ConPrintf(StdOut, L"%03ld (%s)\n", pUserInfo->usri4_country_code, szCountry); 409 410 PrintPaddedMessageString(4419, nPaddedLength); 411 if (pUserInfo->usri4_flags & UF_ACCOUNTDISABLE) 412 PrintMessageString(4301); 413 else if (pUserInfo->usri4_flags & UF_LOCKOUT) 414 PrintMessageString(4440); 415 else 416 PrintMessageString(4300); 417 ConPuts(StdOut, L"\n"); 418 419 PrintPaddedMessageString(4420, nPaddedLength); 420 if (pUserInfo->usri4_acct_expires == TIMEQ_FOREVER) 421 PrintMessageString(4305); 422 else 423 PrintDateTime(pUserInfo->usri4_acct_expires); 424 ConPuts(StdOut, L"\n\n"); 425 426 PrintPaddedMessageString(4421, nPaddedLength); 427 dwLastSet = GetTimeInSeconds() - pUserInfo->usri4_password_age; 428 PrintDateTime(dwLastSet); 429 ConPuts(StdOut, L"\n"); 430 431 PrintPaddedMessageString(4422, nPaddedLength); 432 if ((pUserInfo->usri4_flags & UF_DONT_EXPIRE_PASSWD) || pUserModals->usrmod0_max_passwd_age == TIMEQ_FOREVER) 433 PrintMessageString(4305); 434 else 435 PrintDateTime(dwLastSet + pUserModals->usrmod0_max_passwd_age); 436 ConPuts(StdOut, L"\n"); 437 438 PrintPaddedMessageString(4423, nPaddedLength); 439 PrintDateTime(dwLastSet + pUserModals->usrmod0_min_passwd_age); 440 ConPuts(StdOut, L"\n"); 441 442 PrintPaddedMessageString(4437, nPaddedLength); 443 PrintMessageString((pUserInfo->usri4_flags & UF_PASSWD_NOTREQD) ? 4301 : 4300); 444 ConPuts(StdOut, L"\n"); 445 446 PrintPaddedMessageString(4438, nPaddedLength); 447 PrintMessageString((pUserInfo->usri4_flags & UF_PASSWD_CANT_CHANGE) ? 4301 : 4300); 448 ConPuts(StdOut, L"\n\n"); 449 450 PrintPaddedMessageString(4424, nPaddedLength); 451 if (pUserInfo->usri4_workstations == NULL || wcslen(pUserInfo->usri4_workstations) == 0) 452 PrintMessageString(4302); 453 else 454 ConPrintf(StdOut, L"%s", pUserInfo->usri4_workstations); 455 ConPuts(StdOut, L"\n"); 456 457 PrintPaddedMessageString(4429, nPaddedLength); 458 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_script_path); 459 460 PrintPaddedMessageString(4439, nPaddedLength); 461 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_profile); 462 463 PrintPaddedMessageString(4436, nPaddedLength); 464 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_home_dir); 465 466 PrintPaddedMessageString(4430, nPaddedLength); 467 if (pUserInfo->usri4_last_logon == 0) 468 PrintMessageString(4305); 469 else 470 PrintDateTime(pUserInfo->usri4_last_logon); 471 ConPuts(StdOut, L"\n\n"); 472 473 PrintPaddedMessageString(4432, nPaddedLength); 474 if (pUserInfo->usri4_logon_hours == NULL) 475 { 476 PrintMessageString(4302); 477 ConPuts(StdOut, L"\n"); 478 } 479 else 480 { 481 PrintLogonHours(pUserInfo->usri4_units_per_week, 482 pUserInfo->usri4_logon_hours, 483 nPaddedLength); 484 } 485 486 ConPuts(StdOut, L"\n"); 487 PrintPaddedMessageString(4427, nPaddedLength); 488 if (dwLocalGroupTotal != 0 && pLocalGroupInfo != NULL) 489 { 490 for (i = 0; i < dwLocalGroupTotal; i++) 491 { 492 if (i != 0) 493 PrintPadding(L' ', nPaddedLength); 494 ConPrintf(StdOut, L"*%s\n", pLocalGroupInfo[i].lgrui0_name); 495 } 496 } 497 else 498 { 499 ConPuts(StdOut, L"\n"); 500 } 501 502 PrintPaddedMessageString(4431, nPaddedLength); 503 if (dwGroupTotal != 0 && pGroupInfo != NULL) 504 { 505 for (i = 0; i < dwGroupTotal; i++) 506 { 507 if (i != 0) 508 PrintPadding(L' ', nPaddedLength); 509 ConPrintf(StdOut, L"*%s\n", pGroupInfo[i].grui0_name); 510 } 511 } 512 else 513 { 514 ConPuts(StdOut, L"\n"); 515 } 516 517 done: 518 if (pGroupInfo != NULL) 519 NetApiBufferFree(pGroupInfo); 520 521 if (pLocalGroupInfo != NULL) 522 NetApiBufferFree(pLocalGroupInfo); 523 524 if (pUserModals != NULL) 525 NetApiBufferFree(pUserModals); 526 527 if (pUserInfo != NULL) 528 NetApiBufferFree(pUserInfo); 529 530 return NERR_Success; 531 } 532 533 534 static 535 VOID 536 ReadPassword( 537 LPWSTR *lpPassword, 538 LPBOOL lpAllocated) 539 { 540 WCHAR szPassword1[PWLEN + 1]; 541 WCHAR szPassword2[PWLEN + 1]; 542 LPWSTR ptr; 543 544 *lpAllocated = FALSE; 545 546 while (TRUE) 547 { 548 PrintMessageString(4358); 549 ReadFromConsole(szPassword1, PWLEN + 1, FALSE); 550 ConPuts(StdOut, L"\n"); 551 552 PrintMessageString(4361); 553 ReadFromConsole(szPassword2, PWLEN + 1, FALSE); 554 ConPuts(StdOut, L"\n"); 555 556 if (wcslen(szPassword1) == wcslen(szPassword2) && 557 wcscmp(szPassword1, szPassword2) == 0) 558 { 559 ptr = HeapAlloc(GetProcessHeap(), 560 0, 561 (wcslen(szPassword1) + 1) * sizeof(WCHAR)); 562 if (ptr != NULL) 563 { 564 wcscpy(ptr, szPassword1); 565 *lpPassword = ptr; 566 *lpAllocated = TRUE; 567 return; 568 } 569 } 570 else 571 { 572 ConPuts(StdOut, L"\n"); 573 PrintMessageString(3728); 574 *lpPassword = NULL; 575 } 576 } 577 } 578 579 580 static 581 VOID 582 GenerateRandomPassword( 583 LPWSTR *lpPassword, 584 LPBOOL lpAllocated) 585 { 586 LPWSTR pPassword = NULL; 587 INT nCharsLen, i, nLength = 8; 588 589 srand(GetTickCount()); 590 591 pPassword = HeapAlloc(GetProcessHeap(), 592 HEAP_ZERO_MEMORY, 593 (nLength + 1) * sizeof(WCHAR)); 594 if (pPassword == NULL) 595 return; 596 597 nCharsLen = wcslen(szPasswordChars); 598 599 for (i = 0; i < nLength; i++) 600 { 601 pPassword[i] = szPasswordChars[rand() % nCharsLen]; 602 } 603 604 *lpPassword = pPassword; 605 *lpAllocated = TRUE; 606 } 607 608 609 static 610 NET_API_STATUS 611 BuildWorkstationsList( 612 _Out_ PWSTR *pWorkstationsList, 613 _In_ PWSTR pRaw) 614 { 615 BOOL isLastSep, isSep; 616 INT i, j; 617 WCHAR c; 618 INT nLength = 0; 619 INT nArgs = 0; 620 INT nRawLength; 621 PWSTR pList; 622 623 /* Check for invalid characters in the raw string */ 624 if (wcspbrk(pRaw, L"/[]=?\\+:.") != NULL) 625 return 3952; 626 627 /* Count the number of workstations in the list and 628 * the required buffer size */ 629 isLastSep = FALSE; 630 isSep = FALSE; 631 nRawLength = wcslen(pRaw); 632 for (i = 0; i < nRawLength; i++) 633 { 634 c = pRaw[i]; 635 if (c == L',' || c == L';') 636 isSep = TRUE; 637 638 if (isSep == TRUE) 639 { 640 if ((isLastSep == FALSE) && (i != 0) && (i != nRawLength - 1)) 641 nLength++; 642 } 643 else 644 { 645 nLength++; 646 647 if (isLastSep == TRUE || (isLastSep == FALSE && i == 0)) 648 nArgs++; 649 } 650 651 isLastSep = isSep; 652 isSep = FALSE; 653 } 654 655 nLength++; 656 657 /* Leave, if there are no workstations in the list */ 658 if (nArgs == 0) 659 { 660 pWorkstationsList = NULL; 661 return NERR_Success; 662 } 663 664 /* Fail if there are more than eight workstations in the list */ 665 if (nArgs > 8) 666 return 3951; 667 668 /* Allocate the buffer for the clean workstation list */ 669 pList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR)); 670 if (pList == NULL) 671 return ERROR_NOT_ENOUGH_MEMORY; 672 673 /* Build the clean workstation list */ 674 isLastSep = FALSE; 675 isSep = FALSE; 676 nRawLength = wcslen(pRaw); 677 for (i = 0, j = 0; i < nRawLength; i++) 678 { 679 c = pRaw[i]; 680 if (c == L',' || c == L';') 681 isSep = TRUE; 682 683 if (isSep == TRUE) 684 { 685 if ((isLastSep == FALSE) && (i != 0) && (i != nRawLength - 1)) 686 { 687 pList[j] = L','; 688 j++; 689 } 690 } 691 else 692 { 693 pList[j] = c; 694 j++; 695 696 if (isLastSep == TRUE || (isLastSep == FALSE && i == 0)) 697 nArgs++; 698 } 699 700 isLastSep = isSep; 701 isSep = FALSE; 702 } 703 704 *pWorkstationsList = pList; 705 706 return NERR_Success; 707 } 708 709 710 static 711 BOOL 712 ReadNumber( 713 PWSTR *s, 714 PWORD pwValue) 715 { 716 if (!iswdigit(**s)) 717 return FALSE; 718 719 while (iswdigit(**s)) 720 { 721 *pwValue = *pwValue * 10 + **s - L'0'; 722 (*s)++; 723 } 724 725 return TRUE; 726 } 727 728 729 static 730 BOOL 731 ReadSeparator( 732 PWSTR *s) 733 { 734 if (**s == L'/' || **s == L'.') 735 { 736 (*s)++; 737 return TRUE; 738 } 739 740 return FALSE; 741 } 742 743 744 static 745 BOOL 746 ParseDate( 747 PWSTR s, 748 PULONG pSeconds) 749 { 750 SYSTEMTIME SystemTime = {0}; 751 FILETIME LocalFileTime, FileTime; 752 LARGE_INTEGER Time; 753 INT nDateFormat = 0; 754 PWSTR p = s; 755 756 if (!*s) 757 return FALSE; 758 759 GetLocaleInfoW(LOCALE_USER_DEFAULT, 760 LOCALE_IDATE, 761 (PWSTR)&nDateFormat, 762 sizeof(INT)); 763 764 switch (nDateFormat) 765 { 766 case 0: /* mmddyy */ 767 default: 768 if (!ReadNumber(&p, &SystemTime.wMonth)) 769 return FALSE; 770 if (!ReadSeparator(&p)) 771 return FALSE; 772 if (!ReadNumber(&p, &SystemTime.wDay)) 773 return FALSE; 774 if (!ReadSeparator(&p)) 775 return FALSE; 776 if (!ReadNumber(&p, &SystemTime.wYear)) 777 return FALSE; 778 break; 779 780 case 1: /* ddmmyy */ 781 if (!ReadNumber(&p, &SystemTime.wDay)) 782 return FALSE; 783 if (!ReadSeparator(&p)) 784 return FALSE; 785 if (!ReadNumber(&p, &SystemTime.wMonth)) 786 return FALSE; 787 if (!ReadSeparator(&p)) 788 return FALSE; 789 if (!ReadNumber(&p, &SystemTime.wYear)) 790 return FALSE; 791 break; 792 793 case 2: /* yymmdd */ 794 if (!ReadNumber(&p, &SystemTime.wYear)) 795 return FALSE; 796 if (!ReadSeparator(&p)) 797 return FALSE; 798 if (!ReadNumber(&p, &SystemTime.wMonth)) 799 return FALSE; 800 if (!ReadSeparator(&p)) 801 return FALSE; 802 if (!ReadNumber(&p, &SystemTime.wDay)) 803 return FALSE; 804 break; 805 } 806 807 /* if only entered two digits: */ 808 /* assume 2000's if value less than 80 */ 809 /* assume 1900's if value greater or equal 80 */ 810 if (SystemTime.wYear <= 99) 811 { 812 if (SystemTime.wYear >= 80) 813 SystemTime.wYear += 1900; 814 else 815 SystemTime.wYear += 2000; 816 } 817 818 if (!SystemTimeToFileTime(&SystemTime, &LocalFileTime)) 819 return FALSE; 820 821 if (!LocalFileTimeToFileTime(&LocalFileTime, &FileTime)) 822 return FALSE; 823 824 Time.u.LowPart = FileTime.dwLowDateTime; 825 Time.u.HighPart = FileTime.dwHighDateTime; 826 827 if (!RtlTimeToSecondsSince1970(&Time, pSeconds)) 828 return FALSE; 829 830 return TRUE; 831 } 832 833 834 static 835 BOOL 836 ParseHour( 837 PWSTR pszString, 838 PWSTR *AmPmArray, 839 PLONG plHour) 840 { 841 PWCHAR pChar; 842 LONG lHour = 0; 843 844 if (!iswdigit(pszString[0])) 845 return FALSE; 846 847 pChar = pszString; 848 while (iswdigit(*pChar)) 849 { 850 lHour = lHour * 10 + *pChar - L'0'; 851 pChar++; 852 } 853 854 if (lHour > 24) 855 return FALSE; 856 857 if (lHour == 24) 858 lHour = 0; 859 860 if ((*pChar != UNICODE_NULL) && 861 (lHour >= 1) && 862 (lHour <= 12)) 863 { 864 if ((_wcsicmp(pChar, AmPmArray[0]) == 0) || 865 (_wcsicmp(pChar, AmPmArray[1]) == 0)) 866 { 867 if (lHour == 12) 868 lHour = 0; 869 } 870 else if ((_wcsicmp(pChar, AmPmArray[2]) == 0) || 871 (_wcsicmp(pChar, AmPmArray[3]) == 0)) 872 { 873 if (lHour != 12) 874 lHour += 12; 875 } 876 else 877 { 878 return FALSE; 879 } 880 } 881 882 *plHour = lHour; 883 884 return TRUE; 885 } 886 887 888 static 889 BOOL 890 ParseDay( 891 PWSTR pszString, 892 PWSTR *ShortDays, 893 PWSTR *LongDays, 894 PDWORD pdwDay) 895 { 896 DWORD i; 897 898 for (i = 0; i < 7; i++) 899 { 900 if (_wcsicmp(pszString, ShortDays[i]) == 0 || 901 _wcsicmp(pszString, LongDays[i]) == 0) 902 { 903 *pdwDay = i; 904 return TRUE; 905 } 906 } 907 908 return FALSE; 909 } 910 911 912 static 913 DWORD 914 LocalToGmtHour( 915 LONG lLocalHour, 916 LONG lBias) 917 { 918 LONG lGmtHour; 919 920 lGmtHour = lLocalHour + lBias; 921 if (lGmtHour < 0) 922 lGmtHour += UNITS_PER_WEEK; 923 else if (lGmtHour > UNITS_PER_WEEK) 924 lGmtHour -= UNITS_PER_WEEK; 925 926 return (DWORD)lGmtHour; 927 } 928 929 930 static 931 DWORD 932 ParseLogonHours( 933 PWSTR pszParams, 934 PBYTE *ppLogonBitmap, 935 PDWORD pdwUnitsPerWeek) 936 { 937 TIME_ZONE_INFORMATION TimeZoneInformation; 938 PBYTE pLogonBitmap = NULL; 939 DWORD dwError = ERROR_SUCCESS; 940 WCHAR szBuffer[32]; 941 PWSTR ptr1, ptr2; 942 WCHAR prevSep, nextSep; 943 DWORD dwStartDay, dwEndDay, i, j; 944 LONG lStartHour, lEndHour, lBias; 945 BYTE DayBitmap; 946 BYTE HourBitmap[6]; 947 LPWSTR ShortDays[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; 948 LPWSTR LongDays[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; 949 LPWSTR AmPmArray[4] = {NULL, NULL, NULL, NULL}; 950 951 GetTimeZoneInformation(&TimeZoneInformation); 952 lBias = TimeZoneInformation.Bias / 60; 953 954 pLogonBitmap = HeapAlloc(GetProcessHeap(), 955 HEAP_ZERO_MEMORY, 956 UNITS_PER_WEEK / 8); 957 if (pLogonBitmap == NULL) 958 return ERROR_OUTOFMEMORY; 959 960 if (*pszParams == UNICODE_NULL) 961 { 962 goto done; 963 } 964 965 if (wcsicmp(pszParams, L"all") == 0) 966 { 967 FillMemory(pLogonBitmap, UNITS_PER_WEEK / 8, 0xFF); 968 goto done; 969 } 970 971 for (i = 0; i < 7; i++) 972 { 973 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | 974 FORMAT_MESSAGE_FROM_HMODULE | 975 FORMAT_MESSAGE_IGNORE_INSERTS, 976 hModuleNetMsg, 977 4314 + i, 978 LANG_USER_DEFAULT, 979 (LPWSTR)&ShortDays[i], 980 0, 981 NULL); 982 983 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | 984 FORMAT_MESSAGE_FROM_HMODULE | 985 FORMAT_MESSAGE_IGNORE_INSERTS, 986 hModuleNetMsg, 987 4307 + i, 988 LANG_USER_DEFAULT, 989 (LPWSTR)&LongDays[i], 990 0, 991 NULL); 992 } 993 994 for (i = 0; i < 4; i++) 995 { 996 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | 997 FORMAT_MESSAGE_FROM_HMODULE | 998 FORMAT_MESSAGE_IGNORE_INSERTS, 999 hModuleNetMsg, 1000 4322 + i, 1001 LANG_USER_DEFAULT, 1002 (LPWSTR)&AmPmArray[i], 1003 0, 1004 NULL); 1005 } 1006 1007 ZeroMemory(&DayBitmap, sizeof(DayBitmap)); 1008 ZeroMemory(HourBitmap, sizeof(HourBitmap)); 1009 1010 ZeroMemory(szBuffer, sizeof(szBuffer)); 1011 ptr1 = pszParams; 1012 ptr2 = szBuffer; 1013 prevSep = UNICODE_NULL; 1014 nextSep = UNICODE_NULL; 1015 for (;;) 1016 { 1017 if (*ptr1 != L'-' && *ptr1 != L',' && *ptr1 != L';' && *ptr1 != UNICODE_NULL) 1018 { 1019 *ptr2 = *ptr1; 1020 ptr2++; 1021 } 1022 else 1023 { 1024 prevSep = nextSep; 1025 nextSep = *ptr1; 1026 1027 if (prevSep != L'-') 1028 { 1029 /* Set first value */ 1030 if (iswdigit(szBuffer[0])) 1031 { 1032 /* Parse hour */ 1033 if (!ParseHour(szBuffer, AmPmArray, &lStartHour)) 1034 { 1035 dwError = 3769; 1036 break; 1037 } 1038 1039 SetBitValue(HourBitmap, LocalToGmtHour(lStartHour, lBias)); 1040 } 1041 else 1042 { 1043 /* Parse day */ 1044 if (!ParseDay(szBuffer, ShortDays, LongDays, &dwStartDay)) 1045 { 1046 dwError = 3768; 1047 break; 1048 } 1049 1050 SetBitValue(&DayBitmap, dwStartDay); 1051 } 1052 } 1053 else 1054 { 1055 /* Set second value */ 1056 if (iswdigit(szBuffer[0])) 1057 { 1058 /* Parse hour */ 1059 if (!ParseHour(szBuffer, AmPmArray, &lEndHour)) 1060 { 1061 dwError = 3769; 1062 break; 1063 } 1064 1065 if (lEndHour <= lStartHour) 1066 lEndHour += HOURS_PER_DAY; 1067 1068 for (i = LocalToGmtHour(lStartHour, lBias); i < LocalToGmtHour(lEndHour, lBias); i++) 1069 SetBitValue(HourBitmap, i); 1070 } 1071 else 1072 { 1073 /* Parse day */ 1074 if (!ParseDay(szBuffer, ShortDays, LongDays, &dwEndDay)) 1075 { 1076 dwError = 3768; 1077 break; 1078 } 1079 1080 if (dwEndDay <= dwStartDay) 1081 dwEndDay += DAYS_PER_WEEK; 1082 1083 for (i = dwStartDay; i <= dwEndDay; i++) 1084 SetBitValue(&DayBitmap, i % DAYS_PER_WEEK); 1085 } 1086 } 1087 1088 if (*ptr1 == L';' || *ptr1 == UNICODE_NULL) 1089 { 1090 /* Fill the logon hour bitmap */ 1091 for (i = 0; i < DAYS_PER_WEEK; i++) 1092 { 1093 if (GetBitValue(&DayBitmap, i)) 1094 { 1095 for (j = 0; j < 48; j++) 1096 { 1097 if (GetBitValue(HourBitmap, j)) 1098 SetBitValue(pLogonBitmap, ((i * HOURS_PER_DAY) + j) % UNITS_PER_WEEK); 1099 } 1100 } 1101 } 1102 1103 /* Reset the Bitmaps */ 1104 ZeroMemory(&DayBitmap, sizeof(DayBitmap)); 1105 ZeroMemory(HourBitmap, sizeof(HourBitmap)); 1106 } 1107 1108 if (*ptr1 == UNICODE_NULL) 1109 break; 1110 1111 ZeroMemory(szBuffer, sizeof(szBuffer)); 1112 ptr2 = szBuffer; 1113 } 1114 1115 ptr1++; 1116 } 1117 1118 done: 1119 for (i = 0; i < 7; i++) 1120 { 1121 LocalFree(ShortDays[i]); 1122 LocalFree(LongDays[i]); 1123 } 1124 1125 for (i = 0; i < 4; i++) 1126 { 1127 LocalFree(AmPmArray[i]); 1128 } 1129 1130 if (dwError == ERROR_SUCCESS) 1131 { 1132 *ppLogonBitmap = pLogonBitmap; 1133 *pdwUnitsPerWeek = UNITS_PER_WEEK; 1134 } 1135 else 1136 { 1137 if (pLogonBitmap != NULL) 1138 HeapFree(GetProcessHeap(), 0, pLogonBitmap); 1139 *ppLogonBitmap = NULL; 1140 *pdwUnitsPerWeek = 0; 1141 } 1142 1143 return dwError; 1144 } 1145 1146 1147 INT 1148 cmdUser( 1149 INT argc, 1150 WCHAR **argv) 1151 { 1152 INT i, j; 1153 INT result = 0; 1154 BOOL bAdd = FALSE; 1155 BOOL bDelete = FALSE; 1156 #if 0 1157 BOOL bDomain = FALSE; 1158 #endif 1159 BOOL bRandomPassword = FALSE; 1160 LPWSTR lpUserName = NULL; 1161 LPWSTR lpPassword = NULL; 1162 PUSER_INFO_4 pUserInfo = NULL; 1163 USER_INFO_4 UserInfo; 1164 LPWSTR pWorkstations = NULL; 1165 LPWSTR p; 1166 LPWSTR endptr; 1167 DWORD value; 1168 BOOL bPasswordAllocated = FALSE; 1169 PBYTE pLogonHours = NULL; 1170 DWORD dwUnitsPerWeek; 1171 NET_API_STATUS Status; 1172 1173 i = 2; 1174 if ((i < argc) && (argv[i][0] != L'/')) 1175 { 1176 lpUserName = argv[i]; 1177 // ConPrintf(StdOut, L"User: %s\n", lpUserName); 1178 i++; 1179 } 1180 1181 if ((i < argc) && (argv[i][0] != L'/')) 1182 { 1183 lpPassword = argv[i]; 1184 // ConPrintf(StdOut, L"Password: %s\n", lpPassword); 1185 i++; 1186 } 1187 1188 for (j = i; j < argc; j++) 1189 { 1190 if (_wcsicmp(argv[j], L"/help") == 0) 1191 { 1192 PrintNetMessage(MSG_USER_HELP); 1193 return 0; 1194 } 1195 else if (_wcsicmp(argv[j], L"/add") == 0) 1196 { 1197 bAdd = TRUE; 1198 } 1199 else if (_wcsicmp(argv[j], L"/delete") == 0) 1200 { 1201 bDelete = TRUE; 1202 } 1203 else if (_wcsicmp(argv[j], L"/domain") == 0) 1204 { 1205 ConPuts(StdErr, L"The /DOMAIN option is not supported yet.\n"); 1206 #if 0 1207 bDomain = TRUE; 1208 #endif 1209 } 1210 else if (_wcsicmp(argv[j], L"/random") == 0) 1211 { 1212 bRandomPassword = TRUE; 1213 GenerateRandomPassword(&lpPassword, 1214 &bPasswordAllocated); 1215 } 1216 } 1217 1218 if (lpUserName == NULL && lpPassword == NULL) 1219 { 1220 Status = EnumerateUsers(); 1221 PrintMessageString(TranslateAppMessage(Status)); 1222 return 0; 1223 } 1224 else if (lpUserName != NULL && lpPassword == NULL && argc == 3) 1225 { 1226 Status = DisplayUser(lpUserName); 1227 PrintMessageString(TranslateAppMessage(Status)); 1228 return 0; 1229 } 1230 1231 if (bAdd && bDelete) 1232 { 1233 result = 1; 1234 goto done; 1235 } 1236 1237 /* Interactive password input */ 1238 if (lpPassword != NULL && wcscmp(lpPassword, L"*") == 0) 1239 { 1240 ReadPassword(&lpPassword, 1241 &bPasswordAllocated); 1242 } 1243 1244 if (!bAdd && !bDelete) 1245 { 1246 /* Modify the user */ 1247 Status = NetUserGetInfo(NULL, 1248 lpUserName, 1249 4, 1250 (LPBYTE*)&pUserInfo); 1251 if (Status != NERR_Success) 1252 { 1253 PrintMessageString(TranslateAppMessage(Status)); 1254 result = 1; 1255 goto done; 1256 } 1257 } 1258 else if (bAdd) 1259 { 1260 /* Add the user */ 1261 ZeroMemory(&UserInfo, sizeof(USER_INFO_4)); 1262 1263 UserInfo.usri4_name = lpUserName; 1264 UserInfo.usri4_password = lpPassword; 1265 UserInfo.usri4_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT; 1266 UserInfo.usri4_acct_expires = TIMEQ_FOREVER; 1267 UserInfo.usri4_primary_group_id = DOMAIN_GROUP_RID_USERS; 1268 1269 pUserInfo = &UserInfo; 1270 } 1271 1272 for (j = i; j < argc; j++) 1273 { 1274 if (_wcsnicmp(argv[j], L"/active:", 8) == 0) 1275 { 1276 p = &argv[i][8]; 1277 if (_wcsicmp(p, L"yes") == 0) 1278 { 1279 pUserInfo->usri4_flags &= ~UF_ACCOUNTDISABLE; 1280 } 1281 else if (_wcsicmp(p, L"no") == 0) 1282 { 1283 pUserInfo->usri4_flags |= UF_ACCOUNTDISABLE; 1284 } 1285 else 1286 { 1287 PrintMessageStringV(3952, L"/ACTIVE"); 1288 result = 1; 1289 goto done; 1290 } 1291 } 1292 else if (_wcsnicmp(argv[j], L"/comment:", 9) == 0) 1293 { 1294 pUserInfo->usri4_comment = &argv[j][9]; 1295 } 1296 else if (_wcsnicmp(argv[j], L"/countrycode:", 13) == 0) 1297 { 1298 p = &argv[i][13]; 1299 value = wcstoul(p, &endptr, 10); 1300 if (*endptr != 0) 1301 { 1302 PrintMessageStringV(3952, L"/COUNTRYCODE"); 1303 result = 1; 1304 goto done; 1305 } 1306 1307 /* Verify the country code */ 1308 if (GetCountryFromCountryCode(value, 0, NULL)) 1309 pUserInfo->usri4_country_code = value; 1310 } 1311 else if (_wcsnicmp(argv[j], L"/expires:", 9) == 0) 1312 { 1313 p = &argv[i][9]; 1314 if (_wcsicmp(p, L"never") == 0) 1315 { 1316 pUserInfo->usri4_acct_expires = TIMEQ_FOREVER; 1317 } 1318 else if (!ParseDate(p, &pUserInfo->usri4_acct_expires)) 1319 { 1320 PrintMessageStringV(3952, L"/EXPIRES"); 1321 result = 1; 1322 goto done; 1323 } 1324 } 1325 else if (_wcsnicmp(argv[j], L"/fullname:", 10) == 0) 1326 { 1327 pUserInfo->usri4_full_name = &argv[j][10]; 1328 } 1329 else if (_wcsnicmp(argv[j], L"/homedir:", 9) == 0) 1330 { 1331 pUserInfo->usri4_home_dir = &argv[j][9]; 1332 } 1333 else if (_wcsnicmp(argv[j], L"/passwordchg:", 13) == 0) 1334 { 1335 p = &argv[i][13]; 1336 if (_wcsicmp(p, L"yes") == 0) 1337 { 1338 pUserInfo->usri4_flags &= ~UF_PASSWD_CANT_CHANGE; 1339 } 1340 else if (_wcsicmp(p, L"no") == 0) 1341 { 1342 pUserInfo->usri4_flags |= UF_PASSWD_CANT_CHANGE; 1343 } 1344 else 1345 { 1346 PrintMessageStringV(3952, L"/PASSWORDCHG"); 1347 result = 1; 1348 goto done; 1349 } 1350 } 1351 else if (_wcsnicmp(argv[j], L"/passwordreq:", 13) == 0) 1352 { 1353 p = &argv[i][13]; 1354 if (_wcsicmp(p, L"yes") == 0) 1355 { 1356 pUserInfo->usri4_flags &= ~UF_PASSWD_NOTREQD; 1357 } 1358 else if (_wcsicmp(p, L"no") == 0) 1359 { 1360 pUserInfo->usri4_flags |= UF_PASSWD_NOTREQD; 1361 } 1362 else 1363 { 1364 PrintMessageStringV(3952, L"/PASSWORDREQ"); 1365 result = 1; 1366 goto done; 1367 } 1368 } 1369 else if (_wcsnicmp(argv[j], L"/profilepath:", 13) == 0) 1370 { 1371 pUserInfo->usri4_profile = &argv[j][13]; 1372 } 1373 else if (_wcsnicmp(argv[j], L"/scriptpath:", 12) == 0) 1374 { 1375 pUserInfo->usri4_script_path = &argv[j][12]; 1376 } 1377 else if (_wcsnicmp(argv[j], L"/times:", 7) == 0) 1378 { 1379 Status = ParseLogonHours(&argv[j][7], 1380 &pLogonHours, 1381 &dwUnitsPerWeek); 1382 if (Status == ERROR_SUCCESS) 1383 { 1384 pUserInfo->usri4_logon_hours = pLogonHours; 1385 pUserInfo->usri4_units_per_week = dwUnitsPerWeek; 1386 } 1387 else 1388 { 1389 PrintMessageString(Status); 1390 goto done; 1391 } 1392 } 1393 else if (_wcsnicmp(argv[j], L"/usercomment:", 13) == 0) 1394 { 1395 pUserInfo->usri4_usr_comment = &argv[j][13]; 1396 } 1397 else if (_wcsnicmp(argv[j], L"/workstations:", 14) == 0) 1398 { 1399 p = &argv[i][14]; 1400 if (wcscmp(p, L"*") == 0 || wcscmp(p, L"") == 0) 1401 { 1402 pUserInfo->usri4_workstations = NULL; 1403 } 1404 else 1405 { 1406 Status = BuildWorkstationsList(&pWorkstations, p); 1407 if (Status == NERR_Success) 1408 { 1409 pUserInfo->usri4_workstations = pWorkstations; 1410 } 1411 else 1412 { 1413 PrintMessageString(TranslateAppMessage(Status)); 1414 result = 1; 1415 goto done; 1416 } 1417 } 1418 } 1419 } 1420 1421 if (!bAdd && !bDelete) 1422 { 1423 /* Modify the user */ 1424 Status = NetUserSetInfo(NULL, 1425 lpUserName, 1426 4, 1427 (LPBYTE)pUserInfo, 1428 NULL); 1429 } 1430 else if (bAdd) 1431 { 1432 /* Add the user */ 1433 Status = NetUserAdd(NULL, 1434 4, 1435 (LPBYTE)pUserInfo, 1436 NULL); 1437 } 1438 else if (bDelete) 1439 { 1440 /* Delete the user */ 1441 Status = NetUserDel(NULL, 1442 lpUserName); 1443 } 1444 1445 PrintMessageString(TranslateAppMessage(Status)); 1446 1447 if (Status == NERR_Success && 1448 lpPassword != NULL && 1449 bRandomPassword == TRUE) 1450 { 1451 PrintMessageStringV(3968, lpUserName, lpPassword); 1452 } 1453 1454 done: 1455 if (pLogonHours != NULL) 1456 HeapFree(GetProcessHeap(), 0, pLogonHours); 1457 1458 if (pWorkstations != NULL) 1459 HeapFree(GetProcessHeap(), 0, pWorkstations); 1460 1461 if ((bPasswordAllocated == TRUE) && (lpPassword != NULL)) 1462 HeapFree(GetProcessHeap(), 0, lpPassword); 1463 1464 if (!bAdd && !bDelete && pUserInfo != NULL) 1465 NetApiBufferFree(pUserInfo); 1466 1467 if (result != 0) 1468 { 1469 PrintMessageString(4381); 1470 ConPuts(StdOut, L"\n"); 1471 PrintNetMessage(MSG_USER_SYNTAX); 1472 } 1473 1474 return result; 1475 } 1476 1477 /* EOF */ 1478