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