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