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