[NET] Implement a parser for the '/times' option of the 'user' command.
[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 #define SECONDS_PER_DAY (60 * 60 * 24)
14 #define SECONDS_PER_HOUR (60 * 60)
15 #define HOURS_PER_DAY 24
16 #define DAYS_PER_WEEK 7
17
18 typedef struct _COUNTY_TABLE
19 {
20 DWORD dwCountryCode;
21 DWORD dwMessageId;
22 } COUNTRY_TABLE, *PCOUNTRY_TABLE;
23
24
25 static WCHAR szPasswordChars[] = L"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@#$%_-+:";
26 static COUNTRY_TABLE CountryTable[] =
27 { { 0, 5080}, // System Default
28 { 1, 5081}, // United States
29 { 2, 5082}, // Canada (French)
30 { 3, 5083}, // Latin America
31 { 31, 5084}, // Netherlands
32 { 32, 5085}, // Belgium
33 { 33, 5086}, // France
34 { 34, 5090}, // Spain
35 { 39, 5087}, // Italy
36 { 41, 5088}, // Switzerland
37 { 44, 5089}, // United Kingdom
38 { 45, 5091}, // Denmark
39 { 46, 5092}, // Sweden
40 { 47, 5093}, // Norway
41 { 49, 5094}, // Germany
42 { 61, 5095}, // Australia
43 { 81, 5096}, // Japan
44 { 82, 5097}, // Korea
45 { 86, 5098}, // China (PRC)
46 { 88, 5099}, // Taiwan
47 { 99, 5100}, // Asia
48 {351, 5101}, // Portugal
49 {358, 5102}, // Finland
50 {785, 5103}, // Arabic
51 {972, 5104} }; // Hebrew
52
53 //static PWSTR DaysArray[] = {L"So", L"Mo", L"Di", L"Mi", L"Do", L"Fr", L"Sa"};
54 static PWSTR DaysArray[] = {L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat"};
55
56 static
57 int
58 CompareInfo(const void *a, const void *b)
59 {
60 return _wcsicmp(((PUSER_INFO_0)a)->usri0_name,
61 ((PUSER_INFO_0)b)->usri0_name);
62 }
63
64
65 static
66 NET_API_STATUS
67 EnumerateUsers(VOID)
68 {
69 PUSER_INFO_0 pBuffer = NULL;
70 PSERVER_INFO_100 pServer = NULL;
71 DWORD dwRead = 0, dwTotal = 0;
72 DWORD i;
73 DWORD ResumeHandle = 0;
74 NET_API_STATUS Status;
75
76 Status = NetServerGetInfo(NULL,
77 100,
78 (LPBYTE*)&pServer);
79 if (Status != NERR_Success)
80 return Status;
81
82 ConPuts(StdOut, L"\n");
83 PrintMessageStringV(4410, pServer->sv100_name);
84 ConPuts(StdOut, L"\n");
85 PrintPadding(L'-', 79);
86 ConPuts(StdOut, L"\n");
87
88 NetApiBufferFree(pServer);
89
90 do
91 {
92 Status = NetUserEnum(NULL,
93 0,
94 0,
95 (LPBYTE*)&pBuffer,
96 MAX_PREFERRED_LENGTH,
97 &dwRead,
98 &dwTotal,
99 &ResumeHandle);
100 if ((Status != NERR_Success) && (Status != ERROR_MORE_DATA))
101 return Status;
102
103 qsort(pBuffer,
104 dwRead,
105 sizeof(PUSER_INFO_0),
106 CompareInfo);
107
108 for (i = 0; i < dwRead; i++)
109 {
110 if (pBuffer[i].usri0_name)
111 ConPrintf(StdOut, L"%s\n", pBuffer[i].usri0_name);
112 }
113
114 NetApiBufferFree(pBuffer);
115 pBuffer = NULL;
116 }
117 while (Status == ERROR_MORE_DATA);
118
119 return NERR_Success;
120 }
121
122
123 static
124 VOID
125 PrintDateTime(DWORD dwSeconds)
126 {
127 LARGE_INTEGER Time;
128 FILETIME FileTime;
129 SYSTEMTIME SystemTime;
130 WCHAR DateBuffer[80];
131 WCHAR TimeBuffer[80];
132
133 RtlSecondsSince1970ToTime(dwSeconds, &Time);
134 FileTime.dwLowDateTime = Time.u.LowPart;
135 FileTime.dwHighDateTime = Time.u.HighPart;
136 FileTimeToLocalFileTime(&FileTime, &FileTime);
137 FileTimeToSystemTime(&FileTime, &SystemTime);
138
139 GetDateFormatW(LOCALE_USER_DEFAULT,
140 DATE_SHORTDATE,
141 &SystemTime,
142 NULL,
143 DateBuffer,
144 ARRAYSIZE(DateBuffer));
145
146 GetTimeFormatW(LOCALE_USER_DEFAULT,
147 TIME_NOSECONDS,
148 &SystemTime,
149 NULL,
150 TimeBuffer,
151 ARRAYSIZE(TimeBuffer));
152
153 ConPrintf(StdOut, L"%s %s", DateBuffer, TimeBuffer);
154 }
155
156
157 static
158 VOID
159 PrintLocalTime(DWORD dwSeconds)
160 {
161 LARGE_INTEGER Time;
162 FILETIME FileTime;
163 SYSTEMTIME SystemTime;
164 WCHAR TimeBuffer[80];
165
166 RtlSecondsSince1970ToTime(dwSeconds, &Time);
167 FileTime.dwLowDateTime = Time.u.LowPart;
168 FileTime.dwHighDateTime = Time.u.HighPart;
169 FileTimeToSystemTime(&FileTime, &SystemTime);
170
171 GetTimeFormatW(LOCALE_USER_DEFAULT,
172 TIME_NOSECONDS,
173 &SystemTime,
174 NULL,
175 TimeBuffer,
176 ARRAYSIZE(TimeBuffer));
177
178 ConPrintf(StdOut, L"%s", TimeBuffer);
179 }
180
181
182 static
183 DWORD
184 GetTimeInSeconds(VOID)
185 {
186 LARGE_INTEGER Time;
187 FILETIME FileTime;
188 DWORD dwSeconds;
189
190 GetSystemTimeAsFileTime(&FileTime);
191 Time.u.LowPart = FileTime.dwLowDateTime;
192 Time.u.HighPart = FileTime.dwHighDateTime;
193 RtlTimeToSecondsSince1970(&Time, &dwSeconds);
194
195 return dwSeconds;
196 }
197
198
199 static
200 BOOL
201 GetCountryFromCountryCode(
202 _In_ DWORD dwCountryCode,
203 _In_ DWORD dwCountryLength,
204 _Out_ PWSTR szCountryBuffer)
205 {
206 DWORD i;
207
208 for (i = 0; i < ARRAYSIZE(CountryTable); i++)
209 {
210 if (CountryTable[i].dwCountryCode == dwCountryCode)
211 {
212 if (szCountryBuffer != NULL && dwCountryLength > 0)
213 {
214 FormatMessageW(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS,
215 hModuleNetMsg,
216 CountryTable[i].dwMessageId,
217 LANG_USER_DEFAULT,
218 szCountryBuffer,
219 dwCountryLength,
220 NULL);
221 }
222
223 return TRUE;
224 }
225 }
226
227 return FALSE;
228 }
229
230
231 static
232 BOOL
233 GetBitValue(
234 PBYTE pBitmap,
235 DWORD dwBitNumber)
236 {
237 DWORD dwIndex = dwBitNumber / 8;
238 BYTE Mask = 1 << (dwBitNumber & 7);
239
240 return ((pBitmap[dwIndex] & Mask) != 0);
241 }
242
243
244 static
245 VOID
246 SetBitValue(
247 PBYTE pBitmap,
248 DWORD dwBitNumber)
249 {
250 DWORD dwIndex = dwBitNumber / 8;
251 BYTE Mask = 1 << (dwBitNumber & 7);
252
253 pBitmap[dwIndex] |= Mask;
254 }
255
256
257 static
258 VOID
259 PrintLogonHours(
260 DWORD dwUnitsPerWeek,
261 PBYTE pLogonHours,
262 INT nPaddedLength)
263 {
264 DWORD dwUnitsPerDay, dwBitNumber, dwSecondsPerUnit;
265 DWORD dwStartTime, dwEndTime, dwStartDay, dwEndDay;
266 BOOL bBitValue, bFirst = TRUE;
267
268 if ((dwUnitsPerWeek == 0) ||
269 ((dwUnitsPerWeek %7) != 0))
270 return;
271
272 dwUnitsPerDay = dwUnitsPerWeek / 7;
273
274 if (((dwUnitsPerDay % 24) != 0) ||
275 ((dwUnitsPerDay / 24) > 6))
276 return;
277
278 dwSecondsPerUnit = (SECONDS_PER_DAY) / dwUnitsPerDay;
279
280 for (dwBitNumber = 0; dwBitNumber < dwUnitsPerWeek; dwBitNumber++)
281 {
282 bBitValue = GetBitValue(pLogonHours, dwBitNumber);
283 if (bBitValue)
284 {
285 dwStartTime = dwSecondsPerUnit * dwBitNumber;
286
287 while (bBitValue != 0 && dwBitNumber < dwUnitsPerWeek)
288 {
289 dwBitNumber++;
290 if (dwBitNumber < dwUnitsPerWeek)
291 bBitValue = GetBitValue(pLogonHours, dwBitNumber);
292 }
293
294 dwEndTime = dwSecondsPerUnit * dwBitNumber;
295
296 if (!bFirst)
297 PrintPadding(L' ', nPaddedLength);
298
299 if (dwStartTime == 0 && dwEndTime == (SECONDS_PER_DAY * 7))
300 {
301 PrintMessageString(4302);
302 ConPuts(StdOut, L"\n");
303 }
304 else
305 {
306 dwStartDay = dwStartTime / SECONDS_PER_DAY;
307 dwEndDay = (dwEndTime / SECONDS_PER_DAY) % 7;
308
309 PrintMessageString(4307 + dwStartDay);
310 ConPuts(StdOut, L" ");
311
312 // FIXME: Check if this is a converion from GMT to local timezone
313 PrintLocalTime((dwStartTime % SECONDS_PER_DAY) + SECONDS_PER_HOUR);
314
315 ConPrintf(StdOut, L" - ");
316 if (dwStartDay != dwEndDay)
317 {
318 PrintMessageString(4307 + dwEndDay);
319 ConPuts(StdOut, L" ");
320 }
321
322 // FIXME: Check if this is a converion from GMT to local timezone
323 PrintLocalTime((dwEndTime % SECONDS_PER_DAY) + SECONDS_PER_HOUR);
324 ConPuts(StdOut, L"\n");
325 }
326
327 bFirst = FALSE;
328 }
329 }
330
331 if (bFirst)
332 {
333 /* No logon hours */
334 PrintMessageString(4434);
335 ConPuts(StdOut, L"\n");
336 }
337 }
338
339
340 static
341 NET_API_STATUS
342 DisplayUser(LPWSTR lpUserName)
343 {
344 PUSER_MODALS_INFO_0 pUserModals = NULL;
345 PUSER_INFO_4 pUserInfo = NULL;
346 PLOCALGROUP_USERS_INFO_0 pLocalGroupInfo = NULL;
347 PGROUP_USERS_INFO_0 pGroupInfo = NULL;
348 DWORD dwLocalGroupRead, dwLocalGroupTotal;
349 DWORD dwGroupRead, dwGroupTotal;
350 DWORD dwLastSet;
351 DWORD i;
352 WCHAR szCountry[40];
353 INT nPaddedLength = 36;
354 NET_API_STATUS Status;
355
356 /* Modify the user */
357 Status = NetUserGetInfo(NULL,
358 lpUserName,
359 4,
360 (LPBYTE*)&pUserInfo);
361 if (Status != NERR_Success)
362 return Status;
363
364 Status = NetUserModalsGet(NULL,
365 0,
366 (LPBYTE*)&pUserModals);
367 if (Status != NERR_Success)
368 goto done;
369
370 Status = NetUserGetLocalGroups(NULL,
371 lpUserName,
372 0,
373 0,
374 (LPBYTE*)&pLocalGroupInfo,
375 MAX_PREFERRED_LENGTH,
376 &dwLocalGroupRead,
377 &dwLocalGroupTotal);
378 if (Status != NERR_Success)
379 goto done;
380
381 Status = NetUserGetGroups(NULL,
382 lpUserName,
383 0,
384 (LPBYTE*)&pGroupInfo,
385 MAX_PREFERRED_LENGTH,
386 &dwGroupRead,
387 &dwGroupTotal);
388 if (Status != NERR_Success)
389 goto done;
390
391 PrintPaddedMessageString(4411, nPaddedLength);
392 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_name);
393
394 PrintPaddedMessageString(4412, nPaddedLength);
395 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_full_name);
396
397 PrintPaddedMessageString(4413, nPaddedLength);
398 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_comment);
399
400 PrintPaddedMessageString(4414, nPaddedLength);
401 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_usr_comment);
402
403 PrintPaddedMessageString(4416, nPaddedLength);
404 GetCountryFromCountryCode(pUserInfo->usri4_country_code,
405 ARRAYSIZE(szCountry), szCountry);
406 ConPrintf(StdOut, L"%03ld (%s)\n", pUserInfo->usri4_country_code, szCountry);
407
408 PrintPaddedMessageString(4419, nPaddedLength);
409 if (pUserInfo->usri4_flags & UF_ACCOUNTDISABLE)
410 PrintMessageString(4301);
411 else if (pUserInfo->usri4_flags & UF_LOCKOUT)
412 PrintMessageString(4440);
413 else
414 PrintMessageString(4300);
415 ConPuts(StdOut, L"\n");
416
417 PrintPaddedMessageString(4420, nPaddedLength);
418 if (pUserInfo->usri4_acct_expires == TIMEQ_FOREVER)
419 PrintMessageString(4305);
420 else
421 PrintDateTime(pUserInfo->usri4_acct_expires);
422 ConPuts(StdOut, L"\n\n");
423
424 PrintPaddedMessageString(4421, nPaddedLength);
425 dwLastSet = GetTimeInSeconds() - pUserInfo->usri4_password_age;
426 PrintDateTime(dwLastSet);
427 ConPuts(StdOut, L"\n");
428
429 PrintPaddedMessageString(4422, nPaddedLength);
430 if ((pUserInfo->usri4_flags & UF_DONT_EXPIRE_PASSWD) || pUserModals->usrmod0_max_passwd_age == TIMEQ_FOREVER)
431 PrintMessageString(4305);
432 else
433 PrintDateTime(dwLastSet + pUserModals->usrmod0_max_passwd_age);
434 ConPuts(StdOut, L"\n");
435
436 PrintPaddedMessageString(4423, nPaddedLength);
437 PrintDateTime(dwLastSet + pUserModals->usrmod0_min_passwd_age);
438 ConPuts(StdOut, L"\n");
439
440 PrintPaddedMessageString(4437, nPaddedLength);
441 PrintMessageString((pUserInfo->usri4_flags & UF_PASSWD_NOTREQD) ? 4301 : 4300);
442 ConPuts(StdOut, L"\n");
443
444 PrintPaddedMessageString(4438, nPaddedLength);
445 PrintMessageString((pUserInfo->usri4_flags & UF_PASSWD_CANT_CHANGE) ? 4301 : 4300);
446 ConPuts(StdOut, L"\n\n");
447
448 PrintPaddedMessageString(4424, nPaddedLength);
449 if (pUserInfo->usri4_workstations == NULL || wcslen(pUserInfo->usri4_workstations) == 0)
450 PrintMessageString(4302);
451 else
452 ConPrintf(StdOut, L"%s", pUserInfo->usri4_workstations);
453 ConPuts(StdOut, L"\n");
454
455 PrintPaddedMessageString(4429, nPaddedLength);
456 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_script_path);
457
458 PrintPaddedMessageString(4439, nPaddedLength);
459 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_profile);
460
461 PrintPaddedMessageString(4436, nPaddedLength);
462 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_home_dir);
463
464 PrintPaddedMessageString(4430, nPaddedLength);
465 if (pUserInfo->usri4_last_logon == 0)
466 PrintMessageString(4305);
467 else
468 PrintDateTime(pUserInfo->usri4_last_logon);
469 ConPuts(StdOut, L"\n\n");
470
471 PrintPaddedMessageString(4432, nPaddedLength);
472 if (pUserInfo->usri4_logon_hours == NULL)
473 {
474 PrintMessageString(4302);
475 ConPuts(StdOut, L"\n");
476 }
477 else
478 {
479 PrintLogonHours(pUserInfo->usri4_units_per_week,
480 pUserInfo->usri4_logon_hours,
481 nPaddedLength);
482 }
483
484 ConPuts(StdOut, L"\n");
485 PrintPaddedMessageString(4427, nPaddedLength);
486 if (dwLocalGroupTotal != 0 && pLocalGroupInfo != NULL)
487 {
488 for (i = 0; i < dwLocalGroupTotal; i++)
489 {
490 if (i != 0)
491 PrintPadding(L' ', nPaddedLength);
492 ConPrintf(StdOut, L"*%s\n", pLocalGroupInfo[i].lgrui0_name);
493 }
494 }
495 else
496 {
497 ConPuts(StdOut, L"\n");
498 }
499
500 PrintPaddedMessageString(4431, nPaddedLength);
501 if (dwGroupTotal != 0 && pGroupInfo != NULL)
502 {
503 for (i = 0; i < dwGroupTotal; i++)
504 {
505 if (i != 0)
506 PrintPadding(L' ', nPaddedLength);
507 ConPrintf(StdOut, L"*%s\n", pGroupInfo[i].grui0_name);
508 }
509 }
510 else
511 {
512 ConPuts(StdOut, L"\n");
513 }
514
515 done:
516 if (pGroupInfo != NULL)
517 NetApiBufferFree(pGroupInfo);
518
519 if (pLocalGroupInfo != NULL)
520 NetApiBufferFree(pLocalGroupInfo);
521
522 if (pUserModals != NULL)
523 NetApiBufferFree(pUserModals);
524
525 if (pUserInfo != NULL)
526 NetApiBufferFree(pUserInfo);
527
528 return NERR_Success;
529 }
530
531
532 static
533 VOID
534 ReadPassword(
535 LPWSTR *lpPassword,
536 LPBOOL lpAllocated)
537 {
538 WCHAR szPassword1[PWLEN + 1];
539 WCHAR szPassword2[PWLEN + 1];
540 LPWSTR ptr;
541
542 *lpAllocated = FALSE;
543
544 while (TRUE)
545 {
546 PrintMessageString(4358);
547 ReadFromConsole(szPassword1, PWLEN + 1, FALSE);
548 ConPuts(StdOut, L"\n");
549
550 PrintMessageString(4361);
551 ReadFromConsole(szPassword2, PWLEN + 1, FALSE);
552 ConPuts(StdOut, L"\n");
553
554 if (wcslen(szPassword1) == wcslen(szPassword2) &&
555 wcscmp(szPassword1, szPassword2) == 0)
556 {
557 ptr = HeapAlloc(GetProcessHeap(),
558 0,
559 (wcslen(szPassword1) + 1) * sizeof(WCHAR));
560 if (ptr != NULL)
561 {
562 wcscpy(ptr, szPassword1);
563 *lpPassword = ptr;
564 *lpAllocated = TRUE;
565 return;
566 }
567 }
568 else
569 {
570 ConPuts(StdOut, L"\n");
571 PrintMessageString(3728);
572 *lpPassword = NULL;
573 }
574 }
575 }
576
577
578 static
579 VOID
580 GenerateRandomPassword(
581 LPWSTR *lpPassword,
582 LPBOOL lpAllocated)
583 {
584 LPWSTR pPassword = NULL;
585 INT nCharsLen, i, nLength = 8;
586
587 srand(GetTickCount());
588
589 pPassword = HeapAlloc(GetProcessHeap(),
590 HEAP_ZERO_MEMORY,
591 (nLength + 1) * sizeof(WCHAR));
592 if (pPassword == NULL)
593 return;
594
595 nCharsLen = wcslen(szPasswordChars);
596
597 for (i = 0; i < nLength; i++)
598 {
599 pPassword[i] = szPasswordChars[rand() % nCharsLen];
600 }
601
602 *lpPassword = pPassword;
603 *lpAllocated = TRUE;
604 }
605
606
607 static
608 NET_API_STATUS
609 BuildWorkstationsList(
610 _Out_ PWSTR *pWorkstationsList,
611 _In_ PWSTR pRaw)
612 {
613 BOOL isLastSep, isSep;
614 INT i, j;
615 WCHAR c;
616 INT nLength = 0;
617 INT nArgs = 0;
618 INT nRawLength;
619 PWSTR pList;
620
621 /* Check for invalid characters in the raw string */
622 if (wcspbrk(pRaw, L"/[]=?\\+:.") != NULL)
623 return 3952;
624
625 /* Count the number of workstations in the list and
626 * the required buffer size */
627 isLastSep = FALSE;
628 isSep = FALSE;
629 nRawLength = wcslen(pRaw);
630 for (i = 0; i < nRawLength; i++)
631 {
632 c = pRaw[i];
633 if (c == L',' || c == L';')
634 isSep = TRUE;
635
636 if (isSep == TRUE)
637 {
638 if ((isLastSep == FALSE) && (i != 0) && (i != nRawLength - 1))
639 nLength++;
640 }
641 else
642 {
643 nLength++;
644
645 if (isLastSep == TRUE || (isLastSep == FALSE && i == 0))
646 nArgs++;
647 }
648
649 isLastSep = isSep;
650 isSep = FALSE;
651 }
652
653 nLength++;
654
655 /* Leave, if there are no workstations in the list */
656 if (nArgs == 0)
657 {
658 pWorkstationsList = NULL;
659 return NERR_Success;
660 }
661
662 /* Fail if there are more than eight workstations in the list */
663 if (nArgs > 8)
664 return 3951;
665
666 /* Allocate the buffer for the clean workstation list */
667 pList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
668 if (pList == NULL)
669 return ERROR_NOT_ENOUGH_MEMORY;
670
671 /* Build the clean workstation list */
672 isLastSep = FALSE;
673 isSep = FALSE;
674 nRawLength = wcslen(pRaw);
675 for (i = 0, j = 0; i < nRawLength; i++)
676 {
677 c = pRaw[i];
678 if (c == L',' || c == L';')
679 isSep = TRUE;
680
681 if (isSep == TRUE)
682 {
683 if ((isLastSep == FALSE) && (i != 0) && (i != nRawLength - 1))
684 {
685 pList[j] = L',';
686 j++;
687 }
688 }
689 else
690 {
691 pList[j] = c;
692 j++;
693
694 if (isLastSep == TRUE || (isLastSep == FALSE && i == 0))
695 nArgs++;
696 }
697
698 isLastSep = isSep;
699 isSep = FALSE;
700 }
701
702 *pWorkstationsList = pList;
703
704 return NERR_Success;
705 }
706
707
708 static
709 BOOL
710 ReadNumber(
711 PWSTR *s,
712 PWORD pwValue)
713 {
714 if (!iswdigit(**s))
715 return FALSE;
716
717 while (iswdigit(**s))
718 {
719 *pwValue = *pwValue * 10 + **s - L'0';
720 (*s)++;
721 }
722
723 return TRUE;
724 }
725
726
727 static
728 BOOL
729 ReadSeparator(
730 PWSTR *s)
731 {
732 if (**s == L'/' || **s == L'.')
733 {
734 (*s)++;
735 return TRUE;
736 }
737
738 return FALSE;
739 }
740
741
742 static
743 BOOL
744 ParseDate(
745 PWSTR s,
746 PULONG pSeconds)
747 {
748 SYSTEMTIME SystemTime = {0};
749 FILETIME LocalFileTime, FileTime;
750 LARGE_INTEGER Time;
751 INT nDateFormat = 0;
752 PWSTR p = s;
753
754 if (!*s)
755 return FALSE;
756
757 GetLocaleInfoW(LOCALE_USER_DEFAULT,
758 LOCALE_IDATE,
759 (PWSTR)&nDateFormat,
760 sizeof(INT));
761
762 switch (nDateFormat)
763 {
764 case 0: /* mmddyy */
765 default:
766 if (!ReadNumber(&p, &SystemTime.wMonth))
767 return FALSE;
768 if (!ReadSeparator(&p))
769 return FALSE;
770 if (!ReadNumber(&p, &SystemTime.wDay))
771 return FALSE;
772 if (!ReadSeparator(&p))
773 return FALSE;
774 if (!ReadNumber(&p, &SystemTime.wYear))
775 return FALSE;
776 break;
777
778 case 1: /* ddmmyy */
779 if (!ReadNumber(&p, &SystemTime.wDay))
780 return FALSE;
781 if (!ReadSeparator(&p))
782 return FALSE;
783 if (!ReadNumber(&p, &SystemTime.wMonth))
784 return FALSE;
785 if (!ReadSeparator(&p))
786 return FALSE;
787 if (!ReadNumber(&p, &SystemTime.wYear))
788 return FALSE;
789 break;
790
791 case 2: /* yymmdd */
792 if (!ReadNumber(&p, &SystemTime.wYear))
793 return FALSE;
794 if (!ReadSeparator(&p))
795 return FALSE;
796 if (!ReadNumber(&p, &SystemTime.wMonth))
797 return FALSE;
798 if (!ReadSeparator(&p))
799 return FALSE;
800 if (!ReadNumber(&p, &SystemTime.wDay))
801 return FALSE;
802 break;
803 }
804
805 /* if only entered two digits: */
806 /* assume 2000's if value less than 80 */
807 /* assume 1900's if value greater or equal 80 */
808 if (SystemTime.wYear <= 99)
809 {
810 if (SystemTime.wYear >= 80)
811 SystemTime.wYear += 1900;
812 else
813 SystemTime.wYear += 2000;
814 }
815
816 if (!SystemTimeToFileTime(&SystemTime, &LocalFileTime))
817 return FALSE;
818
819 if (!LocalFileTimeToFileTime(&LocalFileTime, &FileTime))
820 return FALSE;
821
822 Time.u.LowPart = FileTime.dwLowDateTime;
823 Time.u.HighPart = FileTime.dwHighDateTime;
824
825 if (!RtlTimeToSecondsSince1970(&Time, pSeconds))
826 return FALSE;
827
828 return TRUE;
829 }
830
831
832 static
833 BOOL
834 ParseHour(
835 PWSTR pszString,
836 PDWORD pdwHour)
837 {
838 PWCHAR pChar;
839 DWORD dwHour = 0;
840
841 if (!iswdigit(pszString[0]))
842 return FALSE;
843
844 pChar = pszString;
845 while (iswdigit(*pChar))
846 {
847 dwHour = dwHour * 10 + *pChar - L'0';
848 pChar++;
849 }
850
851 if (dwHour > 24)
852 return FALSE;
853
854 if (dwHour == 24)
855 dwHour = 0;
856
857 if ((*pChar != UNICODE_NULL) &&
858 (dwHour >= 1) &&
859 (dwHour <= 12))
860 {
861 if ((_wcsicmp(pChar, L"am") == 0) ||
862 (_wcsicmp(pChar, L"a.m.") == 0))
863 {
864 if (dwHour == 12)
865 dwHour = 0;
866 }
867 else if ((_wcsicmp(pChar, L"pm") == 0) ||
868 (_wcsicmp(pChar, L"p.m.") == 0))
869 {
870 if (dwHour != 12)
871 dwHour += 12;
872 }
873 else
874 {
875 return FALSE;
876 }
877 }
878
879 *pdwHour = dwHour;
880
881 return TRUE;
882 }
883
884
885 static
886 BOOL
887 ParseDay(
888 PWSTR pszString,
889 PDWORD pdwDay)
890 {
891 DWORD i;
892
893 for (i = 0; i < ARRAYSIZE(DaysArray); i++)
894 {
895 if (_wcsicmp(pszString, DaysArray[i]) == 0)
896 {
897 *pdwDay = i;
898 return TRUE;
899 }
900 }
901
902 return FALSE;
903 }
904
905
906 static
907 DWORD
908 ParseLogonHours(
909 PWSTR pszParams,
910 PBYTE *ppLogonBitmap,
911 PDWORD pdwUnitsPerWeek)
912 {
913 PBYTE pLogonBitmap = NULL;
914 DWORD dwError = ERROR_SUCCESS;
915 WCHAR szBuffer[32];
916 PWSTR ptr1, ptr2;
917 WCHAR prevSep, nextSep;
918 DWORD dwStartHour, dwEndHour, dwStartDay, dwEndDay, i, j;
919 BYTE DayBitmap;
920 BYTE HourBitmap[6];
921
922 pLogonBitmap = HeapAlloc(GetProcessHeap(),
923 HEAP_ZERO_MEMORY,
924 UNITS_PER_WEEK / 8);
925 if (pLogonBitmap == NULL)
926 return ERROR_OUTOFMEMORY;
927
928 if (*pszParams == UNICODE_NULL)
929 {
930 goto done;
931 }
932
933 if (wcsicmp(pszParams, L"all") == 0)
934 {
935 FillMemory(pLogonBitmap, UNITS_PER_WEEK / 8, 0xFF);
936 goto done;
937 }
938
939 ZeroMemory(&DayBitmap, sizeof(DayBitmap));
940 ZeroMemory(HourBitmap, sizeof(HourBitmap));
941
942 ZeroMemory(szBuffer, sizeof(szBuffer));
943 ptr1 = pszParams;
944 ptr2 = szBuffer;
945 prevSep = UNICODE_NULL;
946 nextSep = UNICODE_NULL;
947 for (;;)
948 {
949 if (*ptr1 != L'-' && *ptr1 != L',' && *ptr1 != L';' && *ptr1 != UNICODE_NULL)
950 {
951 *ptr2 = *ptr1;
952 ptr2++;
953 }
954 else
955 {
956 prevSep = nextSep;
957 nextSep = *ptr1;
958
959 // printf("Token: '%S'\n", szBuffer);
960 if (*ptr1 != UNICODE_NULL)
961 printf("Separator: '%C'\n", *ptr1);
962
963 if (prevSep != L'-')
964 {
965 // Set first value
966 if (iswdigit(szBuffer[0]))
967 {
968 // parse hour
969 if (!ParseHour(szBuffer, &dwStartHour))
970 {
971 dwError = 3769;
972 break;
973 }
974
975 // FIXME: Check if this is a converion from local timezone to GMT
976 if (dwStartHour > 0)
977 dwStartHour--;
978 else
979 dwStartHour = UNITS_PER_WEEK - 1;
980
981 SetBitValue(HourBitmap, dwStartHour);
982 }
983 else
984 {
985 // parse day
986 if (!ParseDay(szBuffer, &dwStartDay))
987 {
988 dwError = 3768;
989 break;
990 }
991
992 SetBitValue(&DayBitmap, dwStartDay);
993 }
994 }
995 else
996 {
997 // Set second value
998 if (iswdigit(szBuffer[0]))
999 {
1000 // parse hour
1001 if (!ParseHour(szBuffer, &dwEndHour))
1002 {
1003 dwError = 3769;
1004 break;
1005 }
1006
1007 if (dwEndHour < dwStartHour)
1008 dwEndHour += HOURS_PER_DAY;
1009 else if (dwEndHour == dwStartHour)
1010 dwEndHour = dwStartHour + HOURS_PER_DAY;
1011
1012 // FIXME: Check if this is a converion from local timezone to GMT
1013 if (dwEndHour > 0)
1014 dwEndHour--;
1015 else
1016 dwEndHour = UNITS_PER_WEEK - 1;
1017
1018 for (i = dwStartHour; i < dwEndHour; i++)
1019 SetBitValue(HourBitmap, i);
1020 }
1021 else
1022 {
1023 // parse day
1024 if (!ParseDay(szBuffer, &dwEndDay))
1025 {
1026 dwError = 3768;
1027 break;
1028 }
1029
1030 if (dwEndDay <= dwStartDay)
1031 dwEndDay += DAYS_PER_WEEK;
1032
1033 for (i = dwStartDay; i <= dwEndDay; i++)
1034 SetBitValue(&DayBitmap, i % DAYS_PER_WEEK);
1035 }
1036 }
1037
1038 if (*ptr1 == L';' || *ptr1 == UNICODE_NULL)
1039 {
1040 // Process the data
1041 // printf("DayBitmap: %02x HourBitmap: %02x%02x%02x%02x%02x%02x\n",
1042 // DayBitmap, HourBitmap[5], HourBitmap[4], HourBitmap[3], HourBitmap[2], HourBitmap[1], HourBitmap[0]);
1043
1044 for (i = 0; i < DAYS_PER_WEEK; i++)
1045 {
1046 if (GetBitValue(&DayBitmap, i))
1047 {
1048 for (j = 0; j < 48; j++)
1049 {
1050 if (GetBitValue(HourBitmap, j))
1051 SetBitValue(pLogonBitmap, ((i * HOURS_PER_DAY) + j) % UNITS_PER_WEEK);
1052 }
1053 }
1054 }
1055
1056 // Reset the Bitmaps
1057 ZeroMemory(&DayBitmap, sizeof(DayBitmap));
1058 ZeroMemory(HourBitmap, sizeof(HourBitmap));
1059 }
1060
1061 if (*ptr1 == UNICODE_NULL)
1062 {
1063 // printf("Done\n");
1064 break;
1065 }
1066
1067 ZeroMemory(szBuffer, sizeof(szBuffer));
1068 ptr2 = szBuffer;
1069 }
1070
1071 ptr1++;
1072 }
1073
1074 #if 0
1075 printf("LogonBitmap:\n");
1076 for (i = 0; i < DAYS_PER_WEEK; i++)
1077 {
1078 j = i * 3;
1079 printf("%lu: %02x%02x%02x\n", i, pLogonHours[j + 2], pLogonHours[j + 1], pLogonHours[j + 0]);
1080 }
1081 printf("\n");
1082 #endif
1083
1084 done:
1085 if (dwError == ERROR_SUCCESS)
1086 {
1087 *ppLogonBitmap = pLogonBitmap;
1088 *pdwUnitsPerWeek = UNITS_PER_WEEK;
1089 }
1090 else
1091 {
1092 if (pLogonBitmap != NULL)
1093 HeapFree(GetProcessHeap(), 0, pLogonBitmap);
1094 *ppLogonBitmap = NULL;
1095 *pdwUnitsPerWeek = 0;
1096 }
1097
1098 return dwError;
1099 }
1100
1101
1102 INT
1103 cmdUser(
1104 INT argc,
1105 WCHAR **argv)
1106 {
1107 INT i, j;
1108 INT result = 0;
1109 BOOL bAdd = FALSE;
1110 BOOL bDelete = FALSE;
1111 #if 0
1112 BOOL bDomain = FALSE;
1113 #endif
1114 BOOL bRandomPassword = FALSE;
1115 LPWSTR lpUserName = NULL;
1116 LPWSTR lpPassword = NULL;
1117 PUSER_INFO_4 pUserInfo = NULL;
1118 USER_INFO_4 UserInfo;
1119 LPWSTR pWorkstations = NULL;
1120 LPWSTR p;
1121 LPWSTR endptr;
1122 DWORD value;
1123 BOOL bPasswordAllocated = FALSE;
1124 PBYTE pLogonHours = NULL;
1125 DWORD dwUnitsPerWeek;
1126 NET_API_STATUS Status;
1127
1128 i = 2;
1129 if ((i < argc) && (argv[i][0] != L'/'))
1130 {
1131 lpUserName = argv[i];
1132 // ConPrintf(StdOut, L"User: %s\n", lpUserName);
1133 i++;
1134 }
1135
1136 if ((i < argc) && (argv[i][0] != L'/'))
1137 {
1138 lpPassword = argv[i];
1139 // ConPrintf(StdOut, L"Password: %s\n", lpPassword);
1140 i++;
1141 }
1142
1143 for (j = i; j < argc; j++)
1144 {
1145 if (_wcsicmp(argv[j], L"/help") == 0)
1146 {
1147 PrintNetMessage(MSG_USER_HELP);
1148 return 0;
1149 }
1150 else if (_wcsicmp(argv[j], L"/add") == 0)
1151 {
1152 bAdd = TRUE;
1153 }
1154 else if (_wcsicmp(argv[j], L"/delete") == 0)
1155 {
1156 bDelete = TRUE;
1157 }
1158 else if (_wcsicmp(argv[j], L"/domain") == 0)
1159 {
1160 ConPuts(StdErr, L"The /DOMAIN option is not supported yet.\n");
1161 #if 0
1162 bDomain = TRUE;
1163 #endif
1164 }
1165 else if (_wcsicmp(argv[j], L"/random") == 0)
1166 {
1167 bRandomPassword = TRUE;
1168 GenerateRandomPassword(&lpPassword,
1169 &bPasswordAllocated);
1170 }
1171 }
1172
1173 if (lpUserName == NULL && lpPassword == NULL)
1174 {
1175 Status = EnumerateUsers();
1176 ConPrintf(StdOut, L"Status: %lu\n", Status);
1177 return 0;
1178 }
1179 else if (lpUserName != NULL && lpPassword == NULL && argc == 3)
1180 {
1181 Status = DisplayUser(lpUserName);
1182 ConPrintf(StdOut, L"Status: %lu\n", Status);
1183 return 0;
1184 }
1185
1186 if (bAdd && bDelete)
1187 {
1188 result = 1;
1189 goto done;
1190 }
1191
1192 /* Interactive password input */
1193 if (lpPassword != NULL && wcscmp(lpPassword, L"*") == 0)
1194 {
1195 ReadPassword(&lpPassword,
1196 &bPasswordAllocated);
1197 }
1198
1199 if (!bAdd && !bDelete)
1200 {
1201 /* Modify the user */
1202 Status = NetUserGetInfo(NULL,
1203 lpUserName,
1204 4,
1205 (LPBYTE*)&pUserInfo);
1206 if (Status != NERR_Success)
1207 {
1208 ConPrintf(StdOut, L"Status: %lu\n", Status);
1209 result = 1;
1210 goto done;
1211 }
1212 }
1213 else if (bAdd && !bDelete)
1214 {
1215 /* Add the user */
1216 ZeroMemory(&UserInfo, sizeof(USER_INFO_4));
1217
1218 UserInfo.usri4_name = lpUserName;
1219 UserInfo.usri4_password = lpPassword;
1220 UserInfo.usri4_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT;
1221 UserInfo.usri4_acct_expires = TIMEQ_FOREVER;
1222 UserInfo.usri4_primary_group_id = DOMAIN_GROUP_RID_USERS;
1223
1224 pUserInfo = &UserInfo;
1225 }
1226
1227 for (j = i; j < argc; j++)
1228 {
1229 if (_wcsnicmp(argv[j], L"/active:", 8) == 0)
1230 {
1231 p = &argv[i][8];
1232 if (_wcsicmp(p, L"yes") == 0)
1233 {
1234 pUserInfo->usri4_flags &= ~UF_ACCOUNTDISABLE;
1235 }
1236 else if (_wcsicmp(p, L"no") == 0)
1237 {
1238 pUserInfo->usri4_flags |= UF_ACCOUNTDISABLE;
1239 }
1240 else
1241 {
1242 PrintMessageStringV(3952, L"/ACTIVE");
1243 result = 1;
1244 goto done;
1245 }
1246 }
1247 else if (_wcsnicmp(argv[j], L"/comment:", 9) == 0)
1248 {
1249 pUserInfo->usri4_comment = &argv[j][9];
1250 }
1251 else if (_wcsnicmp(argv[j], L"/countrycode:", 13) == 0)
1252 {
1253 p = &argv[i][13];
1254 value = wcstoul(p, &endptr, 10);
1255 if (*endptr != 0)
1256 {
1257 PrintMessageStringV(3952, L"/COUNTRYCODE");
1258 result = 1;
1259 goto done;
1260 }
1261
1262 /* Verify the country code */
1263 if (GetCountryFromCountryCode(value, 0, NULL))
1264 pUserInfo->usri4_country_code = value;
1265 }
1266 else if (_wcsnicmp(argv[j], L"/expires:", 9) == 0)
1267 {
1268 p = &argv[i][9];
1269 if (_wcsicmp(p, L"never") == 0)
1270 {
1271 pUserInfo->usri4_acct_expires = TIMEQ_FOREVER;
1272 }
1273 else if (!ParseDate(p, &pUserInfo->usri4_acct_expires))
1274 {
1275 PrintMessageStringV(3952, L"/EXPIRES");
1276 result = 1;
1277 goto done;
1278 }
1279 }
1280 else if (_wcsnicmp(argv[j], L"/fullname:", 10) == 0)
1281 {
1282 pUserInfo->usri4_full_name = &argv[j][10];
1283 }
1284 else if (_wcsnicmp(argv[j], L"/homedir:", 9) == 0)
1285 {
1286 pUserInfo->usri4_home_dir = &argv[j][9];
1287 }
1288 else if (_wcsnicmp(argv[j], L"/passwordchg:", 13) == 0)
1289 {
1290 p = &argv[i][13];
1291 if (_wcsicmp(p, L"yes") == 0)
1292 {
1293 pUserInfo->usri4_flags &= ~UF_PASSWD_CANT_CHANGE;
1294 }
1295 else if (_wcsicmp(p, L"no") == 0)
1296 {
1297 pUserInfo->usri4_flags |= UF_PASSWD_CANT_CHANGE;
1298 }
1299 else
1300 {
1301 PrintMessageStringV(3952, L"/PASSWORDCHG");
1302 result = 1;
1303 goto done;
1304 }
1305 }
1306 else if (_wcsnicmp(argv[j], L"/passwordreq:", 13) == 0)
1307 {
1308 p = &argv[i][13];
1309 if (_wcsicmp(p, L"yes") == 0)
1310 {
1311 pUserInfo->usri4_flags &= ~UF_PASSWD_NOTREQD;
1312 }
1313 else if (_wcsicmp(p, L"no") == 0)
1314 {
1315 pUserInfo->usri4_flags |= UF_PASSWD_NOTREQD;
1316 }
1317 else
1318 {
1319 PrintMessageStringV(3952, L"/PASSWORDREQ");
1320 result = 1;
1321 goto done;
1322 }
1323 }
1324 else if (_wcsnicmp(argv[j], L"/profilepath:", 13) == 0)
1325 {
1326 pUserInfo->usri4_profile = &argv[j][13];
1327 }
1328 else if (_wcsnicmp(argv[j], L"/scriptpath:", 12) == 0)
1329 {
1330 pUserInfo->usri4_script_path = &argv[j][12];
1331 }
1332 else if (_wcsnicmp(argv[j], L"/times:", 7) == 0)
1333 {
1334 Status = ParseLogonHours(&argv[j][7],
1335 &pLogonHours,
1336 &dwUnitsPerWeek);
1337 if (Status == ERROR_SUCCESS)
1338 {
1339 pUserInfo->usri4_logon_hours = pLogonHours;
1340 pUserInfo->usri4_units_per_week = dwUnitsPerWeek;
1341 }
1342 else
1343 {
1344 PrintMessageString(Status);
1345 goto done;
1346 }
1347 }
1348 else if (_wcsnicmp(argv[j], L"/usercomment:", 13) == 0)
1349 {
1350 pUserInfo->usri4_usr_comment = &argv[j][13];
1351 }
1352 else if (_wcsnicmp(argv[j], L"/workstations:", 14) == 0)
1353 {
1354 p = &argv[i][14];
1355 if (wcscmp(p, L"*") == 0 || wcscmp(p, L"") == 0)
1356 {
1357 pUserInfo->usri4_workstations = NULL;
1358 }
1359 else
1360 {
1361 Status = BuildWorkstationsList(&pWorkstations, p);
1362 if (Status == NERR_Success)
1363 {
1364 pUserInfo->usri4_workstations = pWorkstations;
1365 }
1366 else
1367 {
1368 ConPrintf(StdOut, L"Status %lu\n\n", Status);
1369 result = 1;
1370 goto done;
1371 }
1372 }
1373 }
1374 }
1375
1376 if (!bAdd && !bDelete)
1377 {
1378 /* Modify the user */
1379 Status = NetUserSetInfo(NULL,
1380 lpUserName,
1381 4,
1382 (LPBYTE)pUserInfo,
1383 NULL);
1384 ConPrintf(StdOut, L"Status: %lu\n", Status);
1385 }
1386 else if (bAdd && !bDelete)
1387 {
1388 /* Add the user */
1389 Status = NetUserAdd(NULL,
1390 4,
1391 (LPBYTE)pUserInfo,
1392 NULL);
1393 ConPrintf(StdOut, L"Status: %lu\n", Status);
1394 }
1395 else if (!bAdd && bDelete)
1396 {
1397 /* Delete the user */
1398 Status = NetUserDel(NULL,
1399 lpUserName);
1400 ConPrintf(StdOut, L"Status: %lu\n", Status);
1401 }
1402
1403 if (Status == NERR_Success &&
1404 lpPassword != NULL &&
1405 bRandomPassword == TRUE)
1406 {
1407 PrintMessageStringV(3968, lpUserName, lpPassword);
1408 }
1409
1410 done:
1411 if (pLogonHours != NULL)
1412 HeapFree(GetProcessHeap(), 0, pLogonHours);
1413
1414 if (pWorkstations != NULL)
1415 HeapFree(GetProcessHeap(), 0, pWorkstations);
1416
1417 if ((bPasswordAllocated == TRUE) && (lpPassword != NULL))
1418 HeapFree(GetProcessHeap(), 0, lpPassword);
1419
1420 if (!bAdd && !bDelete && pUserInfo != NULL)
1421 NetApiBufferFree(pUserInfo);
1422
1423 if (result != 0)
1424 {
1425 PrintMessageString(4381);
1426 ConPuts(StdOut, L"\n");
1427 PrintNetMessage(MSG_USER_SYNTAX);
1428 }
1429
1430 return result;
1431 }
1432
1433 /* EOF */