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 14 int 15 CompareUserInfo(const void *a, const void *b) 16 { 17 return _wcsicmp(((PUSER_INFO_0)a)->usri0_name, 18 ((PUSER_INFO_0)b)->usri0_name); 19 } 20 21 22 static 23 NET_API_STATUS 24 EnumerateUsers(VOID) 25 { 26 PUSER_INFO_0 pBuffer = NULL; 27 PSERVER_INFO_100 pServer = NULL; 28 DWORD dwRead = 0, dwTotal = 0; 29 DWORD i; 30 DWORD_PTR ResumeHandle = 0; 31 NET_API_STATUS Status; 32 33 Status = NetServerGetInfo(NULL, 34 100, 35 (LPBYTE*)&pServer); 36 if (Status != NERR_Success) 37 return Status; 38 39 ConPuts(StdOut, L"\n"); 40 ConResPrintf(StdOut, IDS_USER_ACCOUNTS, pServer->sv100_name); 41 ConPuts(StdOut, L"\n\n"); 42 PrintPadding(L'-', 79); 43 ConPuts(StdOut, L"\n"); 44 45 NetApiBufferFree(pServer); 46 47 do 48 { 49 Status = NetUserEnum(NULL, 50 0, 51 0, 52 (LPBYTE*)&pBuffer, 53 MAX_PREFERRED_LENGTH, 54 &dwRead, 55 &dwTotal, 56 &ResumeHandle); 57 if ((Status != NERR_Success) && (Status != ERROR_MORE_DATA)) 58 return Status; 59 60 qsort(pBuffer, 61 dwRead, 62 sizeof(PUSER_INFO_0), 63 CompareUserInfo); 64 65 for (i = 0; i < dwRead; i++) 66 { 67 if (pBuffer[i].usri0_name) 68 ConPrintf(StdOut, L"%s\n", pBuffer[i].usri0_name); 69 } 70 71 NetApiBufferFree(pBuffer); 72 pBuffer = NULL; 73 } 74 while (Status == ERROR_MORE_DATA); 75 76 return NERR_Success; 77 } 78 79 80 static 81 VOID 82 PrintDateTime(DWORD dwSeconds) 83 { 84 LARGE_INTEGER Time; 85 FILETIME FileTime; 86 SYSTEMTIME SystemTime; 87 WCHAR DateBuffer[80]; 88 WCHAR TimeBuffer[80]; 89 90 RtlSecondsSince1970ToTime(dwSeconds, &Time); 91 FileTime.dwLowDateTime = Time.u.LowPart; 92 FileTime.dwHighDateTime = Time.u.HighPart; 93 FileTimeToLocalFileTime(&FileTime, &FileTime); 94 FileTimeToSystemTime(&FileTime, &SystemTime); 95 96 GetDateFormatW(LOCALE_USER_DEFAULT, 97 DATE_SHORTDATE, 98 &SystemTime, 99 NULL, 100 DateBuffer, 101 80); 102 103 GetTimeFormatW(LOCALE_USER_DEFAULT, 104 TIME_NOSECONDS, 105 &SystemTime, 106 NULL, 107 TimeBuffer, 108 80); 109 110 ConPrintf(StdOut, L"%s %s", DateBuffer, TimeBuffer); 111 } 112 113 114 static 115 DWORD 116 GetTimeInSeconds(VOID) 117 { 118 LARGE_INTEGER Time; 119 FILETIME FileTime; 120 DWORD dwSeconds; 121 122 GetSystemTimeAsFileTime(&FileTime); 123 Time.u.LowPart = FileTime.dwLowDateTime; 124 Time.u.HighPart = FileTime.dwHighDateTime; 125 RtlTimeToSecondsSince1970(&Time, &dwSeconds); 126 127 return dwSeconds; 128 } 129 130 131 static 132 NET_API_STATUS 133 DisplayUser(LPWSTR lpUserName) 134 { 135 PUSER_MODALS_INFO_0 pUserModals = NULL; 136 PUSER_INFO_4 pUserInfo = NULL; 137 PLOCALGROUP_USERS_INFO_0 pLocalGroupInfo = NULL; 138 PGROUP_USERS_INFO_0 pGroupInfo = NULL; 139 DWORD dwLocalGroupRead, dwLocalGroupTotal; 140 DWORD dwGroupRead, dwGroupTotal; 141 DWORD dwLastSet; 142 DWORD i; 143 INT nPaddedLength = 29; 144 NET_API_STATUS Status; 145 146 /* Modify the user */ 147 Status = NetUserGetInfo(NULL, 148 lpUserName, 149 4, 150 (LPBYTE*)&pUserInfo); 151 if (Status != NERR_Success) 152 return Status; 153 154 Status = NetUserModalsGet(NULL, 155 0, 156 (LPBYTE*)&pUserModals); 157 if (Status != NERR_Success) 158 goto done; 159 160 Status = NetUserGetLocalGroups(NULL, 161 lpUserName, 162 0, 163 0, 164 (LPBYTE*)&pLocalGroupInfo, 165 MAX_PREFERRED_LENGTH, 166 &dwLocalGroupRead, 167 &dwLocalGroupTotal); 168 if (Status != NERR_Success) 169 goto done; 170 171 Status = NetUserGetGroups(NULL, 172 lpUserName, 173 0, 174 (LPBYTE*)&pGroupInfo, 175 MAX_PREFERRED_LENGTH, 176 &dwGroupRead, 177 &dwGroupTotal); 178 if (Status != NERR_Success) 179 goto done; 180 181 PrintPaddedResourceString(IDS_USER_NAME, nPaddedLength); 182 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_name); 183 184 PrintPaddedResourceString(IDS_USER_FULL_NAME, nPaddedLength); 185 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_full_name); 186 187 PrintPaddedResourceString(IDS_USER_COMMENT, nPaddedLength); 188 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_comment); 189 190 PrintPaddedResourceString(IDS_USER_USER_COMMENT, nPaddedLength); 191 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_usr_comment); 192 193 PrintPaddedResourceString(IDS_USER_COUNTRY_CODE, nPaddedLength); 194 ConPrintf(StdOut, L"%03ld ()\n", pUserInfo->usri4_country_code); 195 196 PrintPaddedResourceString(IDS_USER_ACCOUNT_ACTIVE, nPaddedLength); 197 if (pUserInfo->usri4_flags & UF_ACCOUNTDISABLE) 198 ConResPuts(StdOut, IDS_GENERIC_NO); 199 else if (pUserInfo->usri4_flags & UF_LOCKOUT) 200 ConResPuts(StdOut, IDS_GENERIC_LOCKED); 201 else 202 ConResPuts(StdOut, IDS_GENERIC_YES); 203 ConPuts(StdOut, L"\n"); 204 205 PrintPaddedResourceString(IDS_USER_ACCOUNT_EXPIRES, nPaddedLength); 206 if (pUserInfo->usri4_acct_expires == TIMEQ_FOREVER) 207 ConResPuts(StdOut, IDS_GENERIC_NEVER); 208 else 209 PrintDateTime(pUserInfo->usri4_acct_expires); 210 ConPuts(StdOut, L"\n\n"); 211 212 PrintPaddedResourceString(IDS_USER_PW_LAST_SET, nPaddedLength); 213 dwLastSet = GetTimeInSeconds() - pUserInfo->usri4_password_age; 214 PrintDateTime(dwLastSet); 215 ConPuts(StdOut, L"\n"); 216 217 PrintPaddedResourceString(IDS_USER_PW_EXPIRES, nPaddedLength); 218 if ((pUserInfo->usri4_flags & UF_DONT_EXPIRE_PASSWD) || pUserModals->usrmod0_max_passwd_age == TIMEQ_FOREVER) 219 ConResPuts(StdOut, IDS_GENERIC_NEVER); 220 else 221 PrintDateTime(dwLastSet + pUserModals->usrmod0_max_passwd_age); 222 ConPuts(StdOut, L"\n"); 223 224 PrintPaddedResourceString(IDS_USER_PW_CHANGEABLE, nPaddedLength); 225 PrintDateTime(dwLastSet + pUserModals->usrmod0_min_passwd_age); 226 ConPuts(StdOut, L"\n"); 227 228 PrintPaddedResourceString(IDS_USER_PW_REQUIRED, nPaddedLength); 229 ConResPuts(StdOut, (pUserInfo->usri4_flags & UF_PASSWD_NOTREQD) ? IDS_GENERIC_NO : IDS_GENERIC_YES); 230 ConPuts(StdOut, L"\n"); 231 232 PrintPaddedResourceString(IDS_USER_CHANGE_PW, nPaddedLength); 233 ConResPuts(StdOut, (pUserInfo->usri4_flags & UF_PASSWD_CANT_CHANGE) ? IDS_GENERIC_NO : IDS_GENERIC_YES); 234 ConPuts(StdOut, L"\n\n"); 235 236 PrintPaddedResourceString(IDS_USER_WORKSTATIONS, nPaddedLength); 237 if (pUserInfo->usri4_workstations == NULL || wcslen(pUserInfo->usri4_workstations) == 0) 238 ConResPuts(StdOut, IDS_GENERIC_ALL); 239 else 240 ConPrintf(StdOut, L"%s", pUserInfo->usri4_workstations); 241 ConPuts(StdOut, L"\n"); 242 243 PrintPaddedResourceString(IDS_USER_LOGON_SCRIPT, nPaddedLength); 244 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_script_path); 245 246 PrintPaddedResourceString(IDS_USER_PROFILE, nPaddedLength); 247 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_profile); 248 249 PrintPaddedResourceString(IDS_USER_HOME_DIR, nPaddedLength); 250 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_home_dir); 251 252 PrintPaddedResourceString(IDS_USER_LAST_LOGON, nPaddedLength); 253 if (pUserInfo->usri4_last_logon == 0) 254 ConResPuts(StdOut, IDS_GENERIC_NEVER); 255 else 256 PrintDateTime(pUserInfo->usri4_last_logon); 257 ConPuts(StdOut, L"\n\n"); 258 259 PrintPaddedResourceString(IDS_USER_LOGON_HOURS, nPaddedLength); 260 if (pUserInfo->usri4_logon_hours == NULL) 261 ConResPuts(StdOut, IDS_GENERIC_ALL); 262 ConPuts(StdOut, L"\n\n"); 263 264 ConPuts(StdOut, L"\n"); 265 PrintPaddedResourceString(IDS_USER_LOCAL_GROUPS, nPaddedLength); 266 if (dwLocalGroupTotal != 0 && pLocalGroupInfo != NULL) 267 { 268 for (i = 0; i < dwLocalGroupTotal; i++) 269 { 270 if (i != 0) 271 PrintPadding(L' ', nPaddedLength); 272 ConPrintf(StdOut, L"*%s\n", pLocalGroupInfo[i].lgrui0_name); 273 } 274 } 275 else 276 { 277 ConPuts(StdOut, L"\n"); 278 } 279 280 PrintPaddedResourceString(IDS_USER_GLOBAL_GROUPS, nPaddedLength); 281 if (dwGroupTotal != 0 && pGroupInfo != NULL) 282 { 283 for (i = 0; i < dwGroupTotal; i++) 284 { 285 if (i != 0) 286 PrintPadding(L' ', nPaddedLength); 287 ConPrintf(StdOut, L"*%s\n", pGroupInfo[i].grui0_name); 288 } 289 } 290 else 291 { 292 ConPuts(StdOut, L"\n"); 293 } 294 295 done: 296 if (pGroupInfo != NULL) 297 NetApiBufferFree(pGroupInfo); 298 299 if (pLocalGroupInfo != NULL) 300 NetApiBufferFree(pLocalGroupInfo); 301 302 if (pUserModals != NULL) 303 NetApiBufferFree(pUserModals); 304 305 if (pUserInfo != NULL) 306 NetApiBufferFree(pUserInfo); 307 308 return NERR_Success; 309 } 310 311 312 static 313 VOID 314 ReadPassword( 315 LPWSTR *lpPassword, 316 LPBOOL lpAllocated) 317 { 318 WCHAR szPassword1[PWLEN + 1]; 319 WCHAR szPassword2[PWLEN + 1]; 320 LPWSTR ptr; 321 322 *lpAllocated = FALSE; 323 324 while (TRUE) 325 { 326 ConResPuts(StdOut, IDS_USER_ENTER_PASSWORD1); 327 ReadFromConsole(szPassword1, PWLEN + 1, FALSE); 328 ConPuts(StdOut, L"\n"); 329 330 ConResPuts(StdOut, IDS_USER_ENTER_PASSWORD2); 331 ReadFromConsole(szPassword2, PWLEN + 1, FALSE); 332 ConPuts(StdOut, L"\n"); 333 334 if (wcslen(szPassword1) == wcslen(szPassword2) && 335 wcscmp(szPassword1, szPassword2) == 0) 336 { 337 ptr = HeapAlloc(GetProcessHeap(), 338 0, 339 (wcslen(szPassword1) + 1) * sizeof(WCHAR)); 340 if (ptr != NULL) 341 { 342 wcscpy(ptr, szPassword1); 343 *lpPassword = ptr; 344 *lpAllocated = TRUE; 345 return; 346 } 347 } 348 else 349 { 350 ConPuts(StdOut, L"\n"); 351 ConResPuts(StdOut, IDS_USER_NO_PASSWORD_MATCH); 352 ConPuts(StdOut, L"\n"); 353 *lpPassword = NULL; 354 } 355 } 356 } 357 358 359 INT 360 cmdUser( 361 INT argc, 362 WCHAR **argv) 363 { 364 INT i, j; 365 INT result = 0; 366 BOOL bAdd = FALSE; 367 BOOL bDelete = FALSE; 368 #if 0 369 BOOL bDomain = FALSE; 370 #endif 371 LPWSTR lpUserName = NULL; 372 LPWSTR lpPassword = NULL; 373 PUSER_INFO_4 pUserInfo = NULL; 374 USER_INFO_4 UserInfo; 375 LPWSTR p; 376 LPWSTR endptr; 377 DWORD value; 378 BOOL bPasswordAllocated = FALSE; 379 NET_API_STATUS Status; 380 381 if (argc == 2) 382 { 383 Status = EnumerateUsers(); 384 ConPrintf(StdOut, L"Status: %lu\n", Status); 385 return 0; 386 } 387 else if (argc == 3) 388 { 389 Status = DisplayUser(argv[2]); 390 ConPrintf(StdOut, L"Status: %lu\n", Status); 391 return 0; 392 } 393 394 i = 2; 395 if (argv[i][0] != L'/') 396 { 397 lpUserName = argv[i]; 398 // ConPrintf(StdOut, L"User: %s\n", lpUserName); 399 i++; 400 } 401 402 if (argv[i][0] != L'/') 403 { 404 lpPassword = argv[i]; 405 // ConPrintf(StdOut, L"Password: %s\n", lpPassword); 406 i++; 407 } 408 409 for (j = i; j < argc; j++) 410 { 411 if (_wcsicmp(argv[j], L"/help") == 0) 412 { 413 ConResPuts(StdOut, IDS_USER_HELP); 414 return 0; 415 } 416 else if (_wcsicmp(argv[j], L"/add") == 0) 417 { 418 bAdd = TRUE; 419 } 420 else if (_wcsicmp(argv[j], L"/delete") == 0) 421 { 422 bDelete = TRUE; 423 } 424 else if (_wcsicmp(argv[j], L"/domain") == 0) 425 { 426 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/DOMAIN"); 427 #if 0 428 bDomain = TRUE; 429 #endif 430 } 431 } 432 433 if (bAdd && bDelete) 434 { 435 result = 1; 436 goto done; 437 } 438 439 /* Interactive password input */ 440 if (lpPassword != NULL && wcscmp(lpPassword, L"*") == 0) 441 { 442 ReadPassword(&lpPassword, 443 &bPasswordAllocated); 444 } 445 446 if (!bAdd && !bDelete) 447 { 448 /* Modify the user */ 449 Status = NetUserGetInfo(NULL, 450 lpUserName, 451 4, 452 (LPBYTE*)&pUserInfo); 453 if (Status != NERR_Success) 454 { 455 ConPrintf(StdOut, L"Status: %lu\n", Status); 456 result = 1; 457 goto done; 458 } 459 } 460 else if (bAdd && !bDelete) 461 { 462 /* Add the user */ 463 ZeroMemory(&UserInfo, sizeof(USER_INFO_4)); 464 465 UserInfo.usri4_name = lpUserName; 466 UserInfo.usri4_password = lpPassword; 467 UserInfo.usri4_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT; 468 469 pUserInfo = &UserInfo; 470 } 471 472 for (j = i; j < argc; j++) 473 { 474 if (_wcsnicmp(argv[j], L"/active:", 8) == 0) 475 { 476 p = &argv[i][8]; 477 if (_wcsicmp(p, L"yes") == 0) 478 { 479 pUserInfo->usri4_flags &= ~UF_ACCOUNTDISABLE; 480 } 481 else if (_wcsicmp(p, L"no") == 0) 482 { 483 pUserInfo->usri4_flags |= UF_ACCOUNTDISABLE; 484 } 485 else 486 { 487 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/ACTIVE"); 488 result = 1; 489 goto done; 490 } 491 } 492 else if (_wcsnicmp(argv[j], L"/comment:", 9) == 0) 493 { 494 pUserInfo->usri4_comment = &argv[j][9]; 495 } 496 else if (_wcsnicmp(argv[j], L"/countrycode:", 13) == 0) 497 { 498 p = &argv[i][13]; 499 value = wcstoul(p, &endptr, 10); 500 if (*endptr != 0) 501 { 502 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/COUNTRYCODE"); 503 result = 1; 504 goto done; 505 } 506 507 /* FIXME: verify the country code */ 508 509 pUserInfo->usri4_country_code = value; 510 } 511 else if (_wcsnicmp(argv[j], L"/expires:", 9) == 0) 512 { 513 p = &argv[i][9]; 514 if (_wcsicmp(p, L"never") == 0) 515 { 516 pUserInfo->usri4_acct_expires = TIMEQ_FOREVER; 517 } 518 else 519 { 520 /* FIXME: Parse the date */ 521 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/EXPIRES"); 522 } 523 } 524 else if (_wcsnicmp(argv[j], L"/fullname:", 10) == 0) 525 { 526 pUserInfo->usri4_full_name = &argv[j][10]; 527 } 528 else if (_wcsnicmp(argv[j], L"/homedir:", 9) == 0) 529 { 530 pUserInfo->usri4_home_dir = &argv[j][9]; 531 } 532 else if (_wcsnicmp(argv[j], L"/passwordchg:", 13) == 0) 533 { 534 p = &argv[i][13]; 535 if (_wcsicmp(p, L"yes") == 0) 536 { 537 pUserInfo->usri4_flags &= ~UF_PASSWD_CANT_CHANGE; 538 } 539 else if (_wcsicmp(p, L"no") == 0) 540 { 541 pUserInfo->usri4_flags |= UF_PASSWD_CANT_CHANGE; 542 } 543 else 544 { 545 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDCHG"); 546 result = 1; 547 goto done; 548 } 549 } 550 else if (_wcsnicmp(argv[j], L"/passwordreq:", 13) == 0) 551 { 552 p = &argv[i][13]; 553 if (_wcsicmp(p, L"yes") == 0) 554 { 555 pUserInfo->usri4_flags &= ~UF_PASSWD_NOTREQD; 556 } 557 else if (_wcsicmp(p, L"no") == 0) 558 { 559 pUserInfo->usri4_flags |= UF_PASSWD_NOTREQD; 560 } 561 else 562 { 563 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDREQ"); 564 result = 1; 565 goto done; 566 } 567 } 568 else if (_wcsnicmp(argv[j], L"/profilepath:", 13) == 0) 569 { 570 pUserInfo->usri4_profile = &argv[j][13]; 571 } 572 else if (_wcsnicmp(argv[j], L"/scriptpath:", 12) == 0) 573 { 574 pUserInfo->usri4_script_path = &argv[j][12]; 575 } 576 else if (_wcsnicmp(argv[j], L"/times:", 7) == 0) 577 { 578 /* FIXME */ 579 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/TIMES"); 580 } 581 else if (_wcsnicmp(argv[j], L"/usercomment:", 13) == 0) 582 { 583 pUserInfo->usri4_usr_comment = &argv[j][13]; 584 } 585 else if (_wcsnicmp(argv[j], L"/workstations:", 14) == 0) 586 { 587 /* FIXME */ 588 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/WORKSTATIONS"); 589 } 590 } 591 592 if (!bAdd && !bDelete) 593 { 594 /* Modify the user */ 595 Status = NetUserSetInfo(NULL, 596 lpUserName, 597 4, 598 (LPBYTE)pUserInfo, 599 NULL); 600 ConPrintf(StdOut, L"Status: %lu\n", Status); 601 } 602 else if (bAdd && !bDelete) 603 { 604 /* Add the user */ 605 Status = NetUserAdd(NULL, 606 4, 607 (LPBYTE)pUserInfo, 608 NULL); 609 ConPrintf(StdOut, L"Status: %lu\n", Status); 610 } 611 else if (!bAdd && bDelete) 612 { 613 /* Delete the user */ 614 Status = NetUserDel(NULL, 615 lpUserName); 616 ConPrintf(StdOut, L"Status: %lu\n", Status); 617 } 618 619 done: 620 if ((bPasswordAllocated != FALSE) && (lpPassword != NULL)) 621 HeapFree(GetProcessHeap(), 0, lpPassword); 622 623 if (!bAdd && !bDelete && pUserInfo != NULL) 624 NetApiBufferFree(pUserInfo); 625 626 if (result != 0) 627 { 628 ConResPuts(StdOut, IDS_GENERIC_SYNTAX); 629 ConResPuts(StdOut, IDS_USER_SYNTAX); 630 } 631 632 return result; 633 } 634 635 /* EOF */ 636