[NET] CompareInfo => CompareUserInfo. #179
[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
14 static
15 int
16 CompareUserInfo(const void *a,
17 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 CompareUserInfo);
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 INT
362 cmdUser(
363 INT argc,
364 WCHAR **argv)
365 {
366 INT i, j;
367 INT result = 0;
368 BOOL bAdd = FALSE;
369 BOOL bDelete = FALSE;
370 #if 0
371 BOOL bDomain = FALSE;
372 #endif
373 LPWSTR lpUserName = NULL;
374 LPWSTR lpPassword = NULL;
375 PUSER_INFO_4 pUserInfo = NULL;
376 USER_INFO_4 UserInfo;
377 LPWSTR p;
378 LPWSTR endptr;
379 DWORD value;
380 BOOL bPasswordAllocated = FALSE;
381 NET_API_STATUS Status;
382
383 if (argc == 2)
384 {
385 Status = EnumerateUsers();
386 ConPrintf(StdOut, L"Status: %lu\n", Status);
387 return 0;
388 }
389 else if (argc == 3)
390 {
391 Status = DisplayUser(argv[2]);
392 ConPrintf(StdOut, L"Status: %lu\n", Status);
393 return 0;
394 }
395
396 i = 2;
397 if (argv[i][0] != L'/')
398 {
399 lpUserName = argv[i];
400 // ConPrintf(StdOut, L"User: %s\n", lpUserName);
401 i++;
402 }
403
404 if (argv[i][0] != L'/')
405 {
406 lpPassword = argv[i];
407 // ConPrintf(StdOut, L"Password: %s\n", lpPassword);
408 i++;
409 }
410
411 for (j = i; j < argc; j++)
412 {
413 if (_wcsicmp(argv[j], L"/help") == 0)
414 {
415 ConResPuts(StdOut, IDS_USER_HELP);
416 return 0;
417 }
418 else if (_wcsicmp(argv[j], L"/add") == 0)
419 {
420 bAdd = TRUE;
421 }
422 else if (_wcsicmp(argv[j], L"/delete") == 0)
423 {
424 bDelete = TRUE;
425 }
426 else if (_wcsicmp(argv[j], L"/domain") == 0)
427 {
428 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/DOMAIN");
429 #if 0
430 bDomain = TRUE;
431 #endif
432 }
433 }
434
435 if (bAdd && bDelete)
436 {
437 result = 1;
438 goto done;
439 }
440
441 /* Interactive password input */
442 if (lpPassword != NULL && wcscmp(lpPassword, L"*") == 0)
443 {
444 ReadPassword(&lpPassword,
445 &bPasswordAllocated);
446 }
447
448 if (!bAdd && !bDelete)
449 {
450 /* Modify the user */
451 Status = NetUserGetInfo(NULL,
452 lpUserName,
453 4,
454 (LPBYTE*)&pUserInfo);
455 if (Status != NERR_Success)
456 {
457 ConPrintf(StdOut, L"Status: %lu\n", Status);
458 result = 1;
459 goto done;
460 }
461 }
462 else if (bAdd && !bDelete)
463 {
464 /* Add the user */
465 ZeroMemory(&UserInfo, sizeof(USER_INFO_4));
466
467 UserInfo.usri4_name = lpUserName;
468 UserInfo.usri4_password = lpPassword;
469 UserInfo.usri4_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT;
470
471 pUserInfo = &UserInfo;
472 }
473
474 for (j = i; j < argc; j++)
475 {
476 if (_wcsnicmp(argv[j], L"/active:", 8) == 0)
477 {
478 p = &argv[i][8];
479 if (_wcsicmp(p, L"yes") == 0)
480 {
481 pUserInfo->usri4_flags &= ~UF_ACCOUNTDISABLE;
482 }
483 else if (_wcsicmp(p, L"no") == 0)
484 {
485 pUserInfo->usri4_flags |= UF_ACCOUNTDISABLE;
486 }
487 else
488 {
489 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/ACTIVE");
490 result = 1;
491 goto done;
492 }
493 }
494 else if (_wcsnicmp(argv[j], L"/comment:", 9) == 0)
495 {
496 pUserInfo->usri4_comment = &argv[j][9];
497 }
498 else if (_wcsnicmp(argv[j], L"/countrycode:", 13) == 0)
499 {
500 p = &argv[i][13];
501 value = wcstoul(p, &endptr, 10);
502 if (*endptr != 0)
503 {
504 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/COUNTRYCODE");
505 result = 1;
506 goto done;
507 }
508
509 /* FIXME: verify the country code */
510
511 pUserInfo->usri4_country_code = value;
512 }
513 else if (_wcsnicmp(argv[j], L"/expires:", 9) == 0)
514 {
515 p = &argv[i][9];
516 if (_wcsicmp(p, L"never") == 0)
517 {
518 pUserInfo->usri4_acct_expires = TIMEQ_FOREVER;
519 }
520 else
521 {
522 /* FIXME: Parse the date */
523 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/EXPIRES");
524 }
525 }
526 else if (_wcsnicmp(argv[j], L"/fullname:", 10) == 0)
527 {
528 pUserInfo->usri4_full_name = &argv[j][10];
529 }
530 else if (_wcsnicmp(argv[j], L"/homedir:", 9) == 0)
531 {
532 pUserInfo->usri4_home_dir = &argv[j][9];
533 }
534 else if (_wcsnicmp(argv[j], L"/passwordchg:", 13) == 0)
535 {
536 p = &argv[i][13];
537 if (_wcsicmp(p, L"yes") == 0)
538 {
539 pUserInfo->usri4_flags &= ~UF_PASSWD_CANT_CHANGE;
540 }
541 else if (_wcsicmp(p, L"no") == 0)
542 {
543 pUserInfo->usri4_flags |= UF_PASSWD_CANT_CHANGE;
544 }
545 else
546 {
547 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDCHG");
548 result = 1;
549 goto done;
550 }
551 }
552 else if (_wcsnicmp(argv[j], L"/passwordreq:", 13) == 0)
553 {
554 p = &argv[i][13];
555 if (_wcsicmp(p, L"yes") == 0)
556 {
557 pUserInfo->usri4_flags &= ~UF_PASSWD_NOTREQD;
558 }
559 else if (_wcsicmp(p, L"no") == 0)
560 {
561 pUserInfo->usri4_flags |= UF_PASSWD_NOTREQD;
562 }
563 else
564 {
565 ConResPrintf(StdErr, IDS_ERROR_INVALID_OPTION_VALUE, L"/PASSWORDREQ");
566 result = 1;
567 goto done;
568 }
569 }
570 else if (_wcsnicmp(argv[j], L"/profilepath:", 13) == 0)
571 {
572 pUserInfo->usri4_profile = &argv[j][13];
573 }
574 else if (_wcsnicmp(argv[j], L"/scriptpath:", 12) == 0)
575 {
576 pUserInfo->usri4_script_path = &argv[j][12];
577 }
578 else if (_wcsnicmp(argv[j], L"/times:", 7) == 0)
579 {
580 /* FIXME */
581 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/TIMES");
582 }
583 else if (_wcsnicmp(argv[j], L"/usercomment:", 13) == 0)
584 {
585 pUserInfo->usri4_usr_comment = &argv[j][13];
586 }
587 else if (_wcsnicmp(argv[j], L"/workstations:", 14) == 0)
588 {
589 /* FIXME */
590 ConResPrintf(StdErr, IDS_ERROR_OPTION_NOT_SUPPORTED, L"/WORKSTATIONS");
591 }
592 }
593
594 if (!bAdd && !bDelete)
595 {
596 /* Modify the user */
597 Status = NetUserSetInfo(NULL,
598 lpUserName,
599 4,
600 (LPBYTE)pUserInfo,
601 NULL);
602 ConPrintf(StdOut, L"Status: %lu\n", Status);
603 }
604 else if (bAdd && !bDelete)
605 {
606 /* Add the user */
607 Status = NetUserAdd(NULL,
608 4,
609 (LPBYTE)pUserInfo,
610 NULL);
611 ConPrintf(StdOut, L"Status: %lu\n", Status);
612 }
613 else if (!bAdd && bDelete)
614 {
615 /* Delete the user */
616 Status = NetUserDel(NULL,
617 lpUserName);
618 ConPrintf(StdOut, L"Status: %lu\n", Status);
619 }
620
621 done:
622 if ((bPasswordAllocated != FALSE) && (lpPassword != NULL))
623 HeapFree(GetProcessHeap(), 0, lpPassword);
624
625 if (!bAdd && !bDelete && pUserInfo != NULL)
626 NetApiBufferFree(pUserInfo);
627
628 if (result != 0)
629 ConResPuts(StdOut, IDS_USER_SYNTAX);
630
631 return result;
632 }
633
634 /* EOF */