[NET] Fix the timezone issue in the logon hours parser and display code of the USER...
[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, dwBias;
266 BOOL bBitValue, bFirst = TRUE;
267 TIME_ZONE_INFORMATION TimeZoneInformation;
268
269 GetTimeZoneInformation(&TimeZoneInformation);
270 dwBias = (TimeZoneInformation.Bias / 60) * SECONDS_PER_HOUR;
271
272 if ((dwUnitsPerWeek == 0) ||
273 ((dwUnitsPerWeek %7) != 0))
274 return;
275
276 dwUnitsPerDay = dwUnitsPerWeek / 7;
277
278 if (((dwUnitsPerDay % 24) != 0) ||
279 ((dwUnitsPerDay / 24) > 6))
280 return;
281
282 dwSecondsPerUnit = (SECONDS_PER_DAY) / dwUnitsPerDay;
283
284 for (dwBitNumber = 0; dwBitNumber < dwUnitsPerWeek; dwBitNumber++)
285 {
286 bBitValue = GetBitValue(pLogonHours, dwBitNumber);
287 if (bBitValue)
288 {
289 dwStartTime = dwSecondsPerUnit * dwBitNumber;
290
291 while (bBitValue != 0 && dwBitNumber < dwUnitsPerWeek)
292 {
293 dwBitNumber++;
294 if (dwBitNumber < dwUnitsPerWeek)
295 bBitValue = GetBitValue(pLogonHours, dwBitNumber);
296 }
297
298 dwEndTime = dwSecondsPerUnit * dwBitNumber;
299
300 if (!bFirst)
301 PrintPadding(L' ', nPaddedLength);
302
303 if (dwStartTime == 0 && dwEndTime == (SECONDS_PER_DAY * 7))
304 {
305 PrintMessageString(4302);
306 ConPuts(StdOut, L"\n");
307 }
308 else
309 {
310 dwStartDay = dwStartTime / SECONDS_PER_DAY;
311 dwEndDay = (dwEndTime / SECONDS_PER_DAY) % 7;
312
313 PrintMessageString(4307 + dwStartDay);
314 ConPuts(StdOut, L" ");
315
316 /* Convert from GMT to local timezone */
317 PrintLocalTime((dwStartTime % SECONDS_PER_DAY) - dwBias);
318
319 ConPrintf(StdOut, L" - ");
320 if (dwStartDay != dwEndDay)
321 {
322 PrintMessageString(4307 + dwEndDay);
323 ConPuts(StdOut, L" ");
324 }
325
326 /* Convert from GMT to local timezone */
327 PrintLocalTime((dwEndTime % SECONDS_PER_DAY) - dwBias);
328 ConPuts(StdOut, L"\n");
329 }
330
331 bFirst = FALSE;
332 }
333 }
334
335 if (bFirst)
336 {
337 /* No logon hours */
338 PrintMessageString(4434);
339 ConPuts(StdOut, L"\n");
340 }
341 }
342
343
344 static
345 NET_API_STATUS
346 DisplayUser(LPWSTR lpUserName)
347 {
348 PUSER_MODALS_INFO_0 pUserModals = NULL;
349 PUSER_INFO_4 pUserInfo = NULL;
350 PLOCALGROUP_USERS_INFO_0 pLocalGroupInfo = NULL;
351 PGROUP_USERS_INFO_0 pGroupInfo = NULL;
352 DWORD dwLocalGroupRead, dwLocalGroupTotal;
353 DWORD dwGroupRead, dwGroupTotal;
354 DWORD dwLastSet;
355 DWORD i;
356 WCHAR szCountry[40];
357 INT nPaddedLength = 36;
358 NET_API_STATUS Status;
359
360 /* Modify the user */
361 Status = NetUserGetInfo(NULL,
362 lpUserName,
363 4,
364 (LPBYTE*)&pUserInfo);
365 if (Status != NERR_Success)
366 return Status;
367
368 Status = NetUserModalsGet(NULL,
369 0,
370 (LPBYTE*)&pUserModals);
371 if (Status != NERR_Success)
372 goto done;
373
374 Status = NetUserGetLocalGroups(NULL,
375 lpUserName,
376 0,
377 0,
378 (LPBYTE*)&pLocalGroupInfo,
379 MAX_PREFERRED_LENGTH,
380 &dwLocalGroupRead,
381 &dwLocalGroupTotal);
382 if (Status != NERR_Success)
383 goto done;
384
385 Status = NetUserGetGroups(NULL,
386 lpUserName,
387 0,
388 (LPBYTE*)&pGroupInfo,
389 MAX_PREFERRED_LENGTH,
390 &dwGroupRead,
391 &dwGroupTotal);
392 if (Status != NERR_Success)
393 goto done;
394
395 PrintPaddedMessageString(4411, nPaddedLength);
396 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_name);
397
398 PrintPaddedMessageString(4412, nPaddedLength);
399 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_full_name);
400
401 PrintPaddedMessageString(4413, nPaddedLength);
402 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_comment);
403
404 PrintPaddedMessageString(4414, nPaddedLength);
405 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_usr_comment);
406
407 PrintPaddedMessageString(4416, nPaddedLength);
408 GetCountryFromCountryCode(pUserInfo->usri4_country_code,
409 ARRAYSIZE(szCountry), szCountry);
410 ConPrintf(StdOut, L"%03ld (%s)\n", pUserInfo->usri4_country_code, szCountry);
411
412 PrintPaddedMessageString(4419, nPaddedLength);
413 if (pUserInfo->usri4_flags & UF_ACCOUNTDISABLE)
414 PrintMessageString(4301);
415 else if (pUserInfo->usri4_flags & UF_LOCKOUT)
416 PrintMessageString(4440);
417 else
418 PrintMessageString(4300);
419 ConPuts(StdOut, L"\n");
420
421 PrintPaddedMessageString(4420, nPaddedLength);
422 if (pUserInfo->usri4_acct_expires == TIMEQ_FOREVER)
423 PrintMessageString(4305);
424 else
425 PrintDateTime(pUserInfo->usri4_acct_expires);
426 ConPuts(StdOut, L"\n\n");
427
428 PrintPaddedMessageString(4421, nPaddedLength);
429 dwLastSet = GetTimeInSeconds() - pUserInfo->usri4_password_age;
430 PrintDateTime(dwLastSet);
431 ConPuts(StdOut, L"\n");
432
433 PrintPaddedMessageString(4422, nPaddedLength);
434 if ((pUserInfo->usri4_flags & UF_DONT_EXPIRE_PASSWD) || pUserModals->usrmod0_max_passwd_age == TIMEQ_FOREVER)
435 PrintMessageString(4305);
436 else
437 PrintDateTime(dwLastSet + pUserModals->usrmod0_max_passwd_age);
438 ConPuts(StdOut, L"\n");
439
440 PrintPaddedMessageString(4423, nPaddedLength);
441 PrintDateTime(dwLastSet + pUserModals->usrmod0_min_passwd_age);
442 ConPuts(StdOut, L"\n");
443
444 PrintPaddedMessageString(4437, nPaddedLength);
445 PrintMessageString((pUserInfo->usri4_flags & UF_PASSWD_NOTREQD) ? 4301 : 4300);
446 ConPuts(StdOut, L"\n");
447
448 PrintPaddedMessageString(4438, nPaddedLength);
449 PrintMessageString((pUserInfo->usri4_flags & UF_PASSWD_CANT_CHANGE) ? 4301 : 4300);
450 ConPuts(StdOut, L"\n\n");
451
452 PrintPaddedMessageString(4424, nPaddedLength);
453 if (pUserInfo->usri4_workstations == NULL || wcslen(pUserInfo->usri4_workstations) == 0)
454 PrintMessageString(4302);
455 else
456 ConPrintf(StdOut, L"%s", pUserInfo->usri4_workstations);
457 ConPuts(StdOut, L"\n");
458
459 PrintPaddedMessageString(4429, nPaddedLength);
460 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_script_path);
461
462 PrintPaddedMessageString(4439, nPaddedLength);
463 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_profile);
464
465 PrintPaddedMessageString(4436, nPaddedLength);
466 ConPrintf(StdOut, L"%s\n", pUserInfo->usri4_home_dir);
467
468 PrintPaddedMessageString(4430, nPaddedLength);
469 if (pUserInfo->usri4_last_logon == 0)
470 PrintMessageString(4305);
471 else
472 PrintDateTime(pUserInfo->usri4_last_logon);
473 ConPuts(StdOut, L"\n\n");
474
475 PrintPaddedMessageString(4432, nPaddedLength);
476 if (pUserInfo->usri4_logon_hours == NULL)
477 {
478 PrintMessageString(4302);
479 ConPuts(StdOut, L"\n");
480 }
481 else
482 {
483 PrintLogonHours(pUserInfo->usri4_units_per_week,
484 pUserInfo->usri4_logon_hours,
485 nPaddedLength);
486 }
487
488 ConPuts(StdOut, L"\n");
489 PrintPaddedMessageString(4427, nPaddedLength);
490 if (dwLocalGroupTotal != 0 && pLocalGroupInfo != NULL)
491 {
492 for (i = 0; i < dwLocalGroupTotal; i++)
493 {
494 if (i != 0)
495 PrintPadding(L' ', nPaddedLength);
496 ConPrintf(StdOut, L"*%s\n", pLocalGroupInfo[i].lgrui0_name);
497 }
498 }
499 else
500 {
501 ConPuts(StdOut, L"\n");
502 }
503
504 PrintPaddedMessageString(4431, nPaddedLength);
505 if (dwGroupTotal != 0 && pGroupInfo != NULL)
506 {
507 for (i = 0; i < dwGroupTotal; i++)
508 {
509 if (i != 0)
510 PrintPadding(L' ', nPaddedLength);
511 ConPrintf(StdOut, L"*%s\n", pGroupInfo[i].grui0_name);
512 }
513 }
514 else
515 {
516 ConPuts(StdOut, L"\n");
517 }
518
519 done:
520 if (pGroupInfo != NULL)
521 NetApiBufferFree(pGroupInfo);
522
523 if (pLocalGroupInfo != NULL)
524 NetApiBufferFree(pLocalGroupInfo);
525
526 if (pUserModals != NULL)
527 NetApiBufferFree(pUserModals);
528
529 if (pUserInfo != NULL)
530 NetApiBufferFree(pUserInfo);
531
532 return NERR_Success;
533 }
534
535
536 static
537 VOID
538 ReadPassword(
539 LPWSTR *lpPassword,
540 LPBOOL lpAllocated)
541 {
542 WCHAR szPassword1[PWLEN + 1];
543 WCHAR szPassword2[PWLEN + 1];
544 LPWSTR ptr;
545
546 *lpAllocated = FALSE;
547
548 while (TRUE)
549 {
550 PrintMessageString(4358);
551 ReadFromConsole(szPassword1, PWLEN + 1, FALSE);
552 ConPuts(StdOut, L"\n");
553
554 PrintMessageString(4361);
555 ReadFromConsole(szPassword2, PWLEN + 1, FALSE);
556 ConPuts(StdOut, L"\n");
557
558 if (wcslen(szPassword1) == wcslen(szPassword2) &&
559 wcscmp(szPassword1, szPassword2) == 0)
560 {
561 ptr = HeapAlloc(GetProcessHeap(),
562 0,
563 (wcslen(szPassword1) + 1) * sizeof(WCHAR));
564 if (ptr != NULL)
565 {
566 wcscpy(ptr, szPassword1);
567 *lpPassword = ptr;
568 *lpAllocated = TRUE;
569 return;
570 }
571 }
572 else
573 {
574 ConPuts(StdOut, L"\n");
575 PrintMessageString(3728);
576 *lpPassword = NULL;
577 }
578 }
579 }
580
581
582 static
583 VOID
584 GenerateRandomPassword(
585 LPWSTR *lpPassword,
586 LPBOOL lpAllocated)
587 {
588 LPWSTR pPassword = NULL;
589 INT nCharsLen, i, nLength = 8;
590
591 srand(GetTickCount());
592
593 pPassword = HeapAlloc(GetProcessHeap(),
594 HEAP_ZERO_MEMORY,
595 (nLength + 1) * sizeof(WCHAR));
596 if (pPassword == NULL)
597 return;
598
599 nCharsLen = wcslen(szPasswordChars);
600
601 for (i = 0; i < nLength; i++)
602 {
603 pPassword[i] = szPasswordChars[rand() % nCharsLen];
604 }
605
606 *lpPassword = pPassword;
607 *lpAllocated = TRUE;
608 }
609
610
611 static
612 NET_API_STATUS
613 BuildWorkstationsList(
614 _Out_ PWSTR *pWorkstationsList,
615 _In_ PWSTR pRaw)
616 {
617 BOOL isLastSep, isSep;
618 INT i, j;
619 WCHAR c;
620 INT nLength = 0;
621 INT nArgs = 0;
622 INT nRawLength;
623 PWSTR pList;
624
625 /* Check for invalid characters in the raw string */
626 if (wcspbrk(pRaw, L"/[]=?\\+:.") != NULL)
627 return 3952;
628
629 /* Count the number of workstations in the list and
630 * the required buffer size */
631 isLastSep = FALSE;
632 isSep = FALSE;
633 nRawLength = wcslen(pRaw);
634 for (i = 0; i < nRawLength; i++)
635 {
636 c = pRaw[i];
637 if (c == L',' || c == L';')
638 isSep = TRUE;
639
640 if (isSep == TRUE)
641 {
642 if ((isLastSep == FALSE) && (i != 0) && (i != nRawLength - 1))
643 nLength++;
644 }
645 else
646 {
647 nLength++;
648
649 if (isLastSep == TRUE || (isLastSep == FALSE && i == 0))
650 nArgs++;
651 }
652
653 isLastSep = isSep;
654 isSep = FALSE;
655 }
656
657 nLength++;
658
659 /* Leave, if there are no workstations in the list */
660 if (nArgs == 0)
661 {
662 pWorkstationsList = NULL;
663 return NERR_Success;
664 }
665
666 /* Fail if there are more than eight workstations in the list */
667 if (nArgs > 8)
668 return 3951;
669
670 /* Allocate the buffer for the clean workstation list */
671 pList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
672 if (pList == NULL)
673 return ERROR_NOT_ENOUGH_MEMORY;
674
675 /* Build the clean workstation list */
676 isLastSep = FALSE;
677 isSep = FALSE;
678 nRawLength = wcslen(pRaw);
679 for (i = 0, j = 0; i < nRawLength; i++)
680 {
681 c = pRaw[i];
682 if (c == L',' || c == L';')
683 isSep = TRUE;
684
685 if (isSep == TRUE)
686 {
687 if ((isLastSep == FALSE) && (i != 0) && (i != nRawLength - 1))
688 {
689 pList[j] = L',';
690 j++;
691 }
692 }
693 else
694 {
695 pList[j] = c;
696 j++;
697
698 if (isLastSep == TRUE || (isLastSep == FALSE && i == 0))
699 nArgs++;
700 }
701
702 isLastSep = isSep;
703 isSep = FALSE;
704 }
705
706 *pWorkstationsList = pList;
707
708 return NERR_Success;
709 }
710
711
712 static
713 BOOL
714 ReadNumber(
715 PWSTR *s,
716 PWORD pwValue)
717 {
718 if (!iswdigit(**s))
719 return FALSE;
720
721 while (iswdigit(**s))
722 {
723 *pwValue = *pwValue * 10 + **s - L'0';
724 (*s)++;
725 }
726
727 return TRUE;
728 }
729
730
731 static
732 BOOL
733 ReadSeparator(
734 PWSTR *s)
735 {
736 if (**s == L'/' || **s == L'.')
737 {
738 (*s)++;
739 return TRUE;
740 }
741
742 return FALSE;
743 }
744
745
746 static
747 BOOL
748 ParseDate(
749 PWSTR s,
750 PULONG pSeconds)
751 {
752 SYSTEMTIME SystemTime = {0};
753 FILETIME LocalFileTime, FileTime;
754 LARGE_INTEGER Time;
755 INT nDateFormat = 0;
756 PWSTR p = s;
757
758 if (!*s)
759 return FALSE;
760
761 GetLocaleInfoW(LOCALE_USER_DEFAULT,
762 LOCALE_IDATE,
763 (PWSTR)&nDateFormat,
764 sizeof(INT));
765
766 switch (nDateFormat)
767 {
768 case 0: /* mmddyy */
769 default:
770 if (!ReadNumber(&p, &SystemTime.wMonth))
771 return FALSE;
772 if (!ReadSeparator(&p))
773 return FALSE;
774 if (!ReadNumber(&p, &SystemTime.wDay))
775 return FALSE;
776 if (!ReadSeparator(&p))
777 return FALSE;
778 if (!ReadNumber(&p, &SystemTime.wYear))
779 return FALSE;
780 break;
781
782 case 1: /* ddmmyy */
783 if (!ReadNumber(&p, &SystemTime.wDay))
784 return FALSE;
785 if (!ReadSeparator(&p))
786 return FALSE;
787 if (!ReadNumber(&p, &SystemTime.wMonth))
788 return FALSE;
789 if (!ReadSeparator(&p))
790 return FALSE;
791 if (!ReadNumber(&p, &SystemTime.wYear))
792 return FALSE;
793 break;
794
795 case 2: /* yymmdd */
796 if (!ReadNumber(&p, &SystemTime.wYear))
797 return FALSE;
798 if (!ReadSeparator(&p))
799 return FALSE;
800 if (!ReadNumber(&p, &SystemTime.wMonth))
801 return FALSE;
802 if (!ReadSeparator(&p))
803 return FALSE;
804 if (!ReadNumber(&p, &SystemTime.wDay))
805 return FALSE;
806 break;
807 }
808
809 /* if only entered two digits: */
810 /* assume 2000's if value less than 80 */
811 /* assume 1900's if value greater or equal 80 */
812 if (SystemTime.wYear <= 99)
813 {
814 if (SystemTime.wYear >= 80)
815 SystemTime.wYear += 1900;
816 else
817 SystemTime.wYear += 2000;
818 }
819
820 if (!SystemTimeToFileTime(&SystemTime, &LocalFileTime))
821 return FALSE;
822
823 if (!LocalFileTimeToFileTime(&LocalFileTime, &FileTime))
824 return FALSE;
825
826 Time.u.LowPart = FileTime.dwLowDateTime;
827 Time.u.HighPart = FileTime.dwHighDateTime;
828
829 if (!RtlTimeToSecondsSince1970(&Time, pSeconds))
830 return FALSE;
831
832 return TRUE;
833 }
834
835
836 static
837 BOOL
838 ParseHour(
839 PWSTR pszString,
840 PLONG plHour)
841 {
842 PWCHAR pChar;
843 LONG lHour = 0;
844
845 if (!iswdigit(pszString[0]))
846 return FALSE;
847
848 pChar = pszString;
849 while (iswdigit(*pChar))
850 {
851 lHour = lHour * 10 + *pChar - L'0';
852 pChar++;
853 }
854
855 if (lHour > 24)
856 return FALSE;
857
858 if (lHour == 24)
859 lHour = 0;
860
861 if ((*pChar != UNICODE_NULL) &&
862 (lHour >= 1) &&
863 (lHour <= 12))
864 {
865 if ((_wcsicmp(pChar, L"am") == 0) ||
866 (_wcsicmp(pChar, L"a.m.") == 0))
867 {
868 if (lHour == 12)
869 lHour = 0;
870 }
871 else if ((_wcsicmp(pChar, L"pm") == 0) ||
872 (_wcsicmp(pChar, L"p.m.") == 0))
873 {
874 if (lHour != 12)
875 lHour += 12;
876 }
877 else
878 {
879 return FALSE;
880 }
881 }
882
883 *plHour = lHour;
884
885 return TRUE;
886 }
887
888
889 static
890 BOOL
891 ParseDay(
892 PWSTR pszString,
893 PDWORD pdwDay)
894 {
895 DWORD i;
896
897 for (i = 0; i < ARRAYSIZE(DaysArray); i++)
898 {
899 if (_wcsicmp(pszString, DaysArray[i]) == 0)
900 {
901 *pdwDay = i;
902 return TRUE;
903 }
904 }
905
906 return FALSE;
907 }
908
909
910 static
911 DWORD
912 ParseLogonHours(
913 PWSTR pszParams,
914 PBYTE *ppLogonBitmap,
915 PDWORD pdwUnitsPerWeek)
916 {
917 TIME_ZONE_INFORMATION TimeZoneInformation;
918 PBYTE pLogonBitmap = NULL;
919 DWORD dwError = ERROR_SUCCESS;
920 WCHAR szBuffer[32];
921 PWSTR ptr1, ptr2;
922 WCHAR prevSep, nextSep;
923 DWORD dwStartDay, dwEndDay, i, j;
924 LONG lStartHour, lEndHour, lBias;
925 BYTE DayBitmap;
926 BYTE HourBitmap[6];
927
928 GetTimeZoneInformation(&TimeZoneInformation);
929 lBias = TimeZoneInformation.Bias / 60;
930
931 pLogonBitmap = HeapAlloc(GetProcessHeap(),
932 HEAP_ZERO_MEMORY,
933 UNITS_PER_WEEK / 8);
934 if (pLogonBitmap == NULL)
935 return ERROR_OUTOFMEMORY;
936
937 if (*pszParams == UNICODE_NULL)
938 {
939 goto done;
940 }
941
942 if (wcsicmp(pszParams, L"all") == 0)
943 {
944 FillMemory(pLogonBitmap, UNITS_PER_WEEK / 8, 0xFF);
945 goto done;
946 }
947
948 ZeroMemory(&DayBitmap, sizeof(DayBitmap));
949 ZeroMemory(HourBitmap, sizeof(HourBitmap));
950
951 ZeroMemory(szBuffer, sizeof(szBuffer));
952 ptr1 = pszParams;
953 ptr2 = szBuffer;
954 prevSep = UNICODE_NULL;
955 nextSep = UNICODE_NULL;
956 for (;;)
957 {
958 if (*ptr1 != L'-' && *ptr1 != L',' && *ptr1 != L';' && *ptr1 != UNICODE_NULL)
959 {
960 *ptr2 = *ptr1;
961 ptr2++;
962 }
963 else
964 {
965 prevSep = nextSep;
966 nextSep = *ptr1;
967
968 if (prevSep != L'-')
969 {
970 /* Set first value */
971 if (iswdigit(szBuffer[0]))
972 {
973 /* Parse hour */
974 if (!ParseHour(szBuffer, &lStartHour))
975 {
976 dwError = 3769;
977 break;
978 }
979
980 /* Convert from local timezone to GMT */
981 lStartHour += lBias;
982 if (lStartHour < 0)
983 lStartHour += UNITS_PER_WEEK;
984 else if (lStartHour > UNITS_PER_WEEK)
985 lStartHour -= UNITS_PER_WEEK;
986
987 SetBitValue(HourBitmap, (DWORD)lStartHour);
988 }
989 else
990 {
991 /* Parse day */
992 if (!ParseDay(szBuffer, &dwStartDay))
993 {
994 dwError = 3768;
995 break;
996 }
997
998 SetBitValue(&DayBitmap, dwStartDay);
999 }
1000 }
1001 else
1002 {
1003 /* Set second value */
1004 if (iswdigit(szBuffer[0]))
1005 {
1006 /* Parse hour */
1007 if (!ParseHour(szBuffer, &lEndHour))
1008 {
1009 dwError = 3769;
1010 break;
1011 }
1012
1013 if (lEndHour < lStartHour)
1014 lEndHour += HOURS_PER_DAY;
1015 else if (lEndHour == lStartHour)
1016 lEndHour = lStartHour + HOURS_PER_DAY;
1017
1018 /* Convert from local timezone to GMT */
1019 lEndHour += lBias;
1020 if (lEndHour < 0)
1021 lEndHour += UNITS_PER_WEEK;
1022 else if (lEndHour > UNITS_PER_WEEK)
1023 lEndHour -= UNITS_PER_WEEK;
1024
1025 for (i = (DWORD)lStartHour; i < (DWORD)lEndHour; i++)
1026 SetBitValue(HourBitmap, i);
1027 }
1028 else
1029 {
1030 /* Parse day */
1031 if (!ParseDay(szBuffer, &dwEndDay))
1032 {
1033 dwError = 3768;
1034 break;
1035 }
1036
1037 if (dwEndDay <= dwStartDay)
1038 dwEndDay += DAYS_PER_WEEK;
1039
1040 for (i = dwStartDay; i <= dwEndDay; i++)
1041 SetBitValue(&DayBitmap, i % DAYS_PER_WEEK);
1042 }
1043 }
1044
1045 if (*ptr1 == L';' || *ptr1 == UNICODE_NULL)
1046 {
1047 /* Fill the logon hour bitmap */
1048 for (i = 0; i < DAYS_PER_WEEK; i++)
1049 {
1050 if (GetBitValue(&DayBitmap, i))
1051 {
1052 for (j = 0; j < 48; j++)
1053 {
1054 if (GetBitValue(HourBitmap, j))
1055 SetBitValue(pLogonBitmap, ((i * HOURS_PER_DAY) + j) % UNITS_PER_WEEK);
1056 }
1057 }
1058 }
1059
1060 /* Reset the Bitmaps */
1061 ZeroMemory(&DayBitmap, sizeof(DayBitmap));
1062 ZeroMemory(HourBitmap, sizeof(HourBitmap));
1063 }
1064
1065 if (*ptr1 == UNICODE_NULL)
1066 break;
1067
1068 ZeroMemory(szBuffer, sizeof(szBuffer));
1069 ptr2 = szBuffer;
1070 }
1071
1072 ptr1++;
1073 }
1074
1075 #if 0
1076 printf("LogonBitmap:\n");
1077 for (i = 0; i < DAYS_PER_WEEK; i++)
1078 {
1079 j = i * 3;
1080 printf("%lu: %02x%02x%02x\n", i, pLogonHours[j + 2], pLogonHours[j + 1], pLogonHours[j + 0]);
1081 }
1082 printf("\n");
1083 #endif
1084
1085 done:
1086 if (dwError == ERROR_SUCCESS)
1087 {
1088 *ppLogonBitmap = pLogonBitmap;
1089 *pdwUnitsPerWeek = UNITS_PER_WEEK;
1090 }
1091 else
1092 {
1093 if (pLogonBitmap != NULL)
1094 HeapFree(GetProcessHeap(), 0, pLogonBitmap);
1095 *ppLogonBitmap = NULL;
1096 *pdwUnitsPerWeek = 0;
1097 }
1098
1099 return dwError;
1100 }
1101
1102
1103 INT
1104 cmdUser(
1105 INT argc,
1106 WCHAR **argv)
1107 {
1108 INT i, j;
1109 INT result = 0;
1110 BOOL bAdd = FALSE;
1111 BOOL bDelete = FALSE;
1112 #if 0
1113 BOOL bDomain = FALSE;
1114 #endif
1115 BOOL bRandomPassword = FALSE;
1116 LPWSTR lpUserName = NULL;
1117 LPWSTR lpPassword = NULL;
1118 PUSER_INFO_4 pUserInfo = NULL;
1119 USER_INFO_4 UserInfo;
1120 LPWSTR pWorkstations = NULL;
1121 LPWSTR p;
1122 LPWSTR endptr;
1123 DWORD value;
1124 BOOL bPasswordAllocated = FALSE;
1125 PBYTE pLogonHours = NULL;
1126 DWORD dwUnitsPerWeek;
1127 NET_API_STATUS Status;
1128
1129 i = 2;
1130 if ((i < argc) && (argv[i][0] != L'/'))
1131 {
1132 lpUserName = argv[i];
1133 // ConPrintf(StdOut, L"User: %s\n", lpUserName);
1134 i++;
1135 }
1136
1137 if ((i < argc) && (argv[i][0] != L'/'))
1138 {
1139 lpPassword = argv[i];
1140 // ConPrintf(StdOut, L"Password: %s\n", lpPassword);
1141 i++;
1142 }
1143
1144 for (j = i; j < argc; j++)
1145 {
1146 if (_wcsicmp(argv[j], L"/help") == 0)
1147 {
1148 PrintNetMessage(MSG_USER_HELP);
1149 return 0;
1150 }
1151 else if (_wcsicmp(argv[j], L"/add") == 0)
1152 {
1153 bAdd = TRUE;
1154 }
1155 else if (_wcsicmp(argv[j], L"/delete") == 0)
1156 {
1157 bDelete = TRUE;
1158 }
1159 else if (_wcsicmp(argv[j], L"/domain") == 0)
1160 {
1161 ConPuts(StdErr, L"The /DOMAIN option is not supported yet.\n");
1162 #if 0
1163 bDomain = TRUE;
1164 #endif
1165 }
1166 else if (_wcsicmp(argv[j], L"/random") == 0)
1167 {
1168 bRandomPassword = TRUE;
1169 GenerateRandomPassword(&lpPassword,
1170 &bPasswordAllocated);
1171 }
1172 }
1173
1174 if (lpUserName == NULL && lpPassword == NULL)
1175 {
1176 Status = EnumerateUsers();
1177 ConPrintf(StdOut, L"Status: %lu\n", Status);
1178 return 0;
1179 }
1180 else if (lpUserName != NULL && lpPassword == NULL && argc == 3)
1181 {
1182 Status = DisplayUser(lpUserName);
1183 ConPrintf(StdOut, L"Status: %lu\n", Status);
1184 return 0;
1185 }
1186
1187 if (bAdd && bDelete)
1188 {
1189 result = 1;
1190 goto done;
1191 }
1192
1193 /* Interactive password input */
1194 if (lpPassword != NULL && wcscmp(lpPassword, L"*") == 0)
1195 {
1196 ReadPassword(&lpPassword,
1197 &bPasswordAllocated);
1198 }
1199
1200 if (!bAdd && !bDelete)
1201 {
1202 /* Modify the user */
1203 Status = NetUserGetInfo(NULL,
1204 lpUserName,
1205 4,
1206 (LPBYTE*)&pUserInfo);
1207 if (Status != NERR_Success)
1208 {
1209 ConPrintf(StdOut, L"Status: %lu\n", Status);
1210 result = 1;
1211 goto done;
1212 }
1213 }
1214 else if (bAdd && !bDelete)
1215 {
1216 /* Add the user */
1217 ZeroMemory(&UserInfo, sizeof(USER_INFO_4));
1218
1219 UserInfo.usri4_name = lpUserName;
1220 UserInfo.usri4_password = lpPassword;
1221 UserInfo.usri4_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT;
1222 UserInfo.usri4_acct_expires = TIMEQ_FOREVER;
1223 UserInfo.usri4_primary_group_id = DOMAIN_GROUP_RID_USERS;
1224
1225 pUserInfo = &UserInfo;
1226 }
1227
1228 for (j = i; j < argc; j++)
1229 {
1230 if (_wcsnicmp(argv[j], L"/active:", 8) == 0)
1231 {
1232 p = &argv[i][8];
1233 if (_wcsicmp(p, L"yes") == 0)
1234 {
1235 pUserInfo->usri4_flags &= ~UF_ACCOUNTDISABLE;
1236 }
1237 else if (_wcsicmp(p, L"no") == 0)
1238 {
1239 pUserInfo->usri4_flags |= UF_ACCOUNTDISABLE;
1240 }
1241 else
1242 {
1243 PrintMessageStringV(3952, L"/ACTIVE");
1244 result = 1;
1245 goto done;
1246 }
1247 }
1248 else if (_wcsnicmp(argv[j], L"/comment:", 9) == 0)
1249 {
1250 pUserInfo->usri4_comment = &argv[j][9];
1251 }
1252 else if (_wcsnicmp(argv[j], L"/countrycode:", 13) == 0)
1253 {
1254 p = &argv[i][13];
1255 value = wcstoul(p, &endptr, 10);
1256 if (*endptr != 0)
1257 {
1258 PrintMessageStringV(3952, L"/COUNTRYCODE");
1259 result = 1;
1260 goto done;
1261 }
1262
1263 /* Verify the country code */
1264 if (GetCountryFromCountryCode(value, 0, NULL))
1265 pUserInfo->usri4_country_code = value;
1266 }
1267 else if (_wcsnicmp(argv[j], L"/expires:", 9) == 0)
1268 {
1269 p = &argv[i][9];
1270 if (_wcsicmp(p, L"never") == 0)
1271 {
1272 pUserInfo->usri4_acct_expires = TIMEQ_FOREVER;
1273 }
1274 else if (!ParseDate(p, &pUserInfo->usri4_acct_expires))
1275 {
1276 PrintMessageStringV(3952, L"/EXPIRES");
1277 result = 1;
1278 goto done;
1279 }
1280 }
1281 else if (_wcsnicmp(argv[j], L"/fullname:", 10) == 0)
1282 {
1283 pUserInfo->usri4_full_name = &argv[j][10];
1284 }
1285 else if (_wcsnicmp(argv[j], L"/homedir:", 9) == 0)
1286 {
1287 pUserInfo->usri4_home_dir = &argv[j][9];
1288 }
1289 else if (_wcsnicmp(argv[j], L"/passwordchg:", 13) == 0)
1290 {
1291 p = &argv[i][13];
1292 if (_wcsicmp(p, L"yes") == 0)
1293 {
1294 pUserInfo->usri4_flags &= ~UF_PASSWD_CANT_CHANGE;
1295 }
1296 else if (_wcsicmp(p, L"no") == 0)
1297 {
1298 pUserInfo->usri4_flags |= UF_PASSWD_CANT_CHANGE;
1299 }
1300 else
1301 {
1302 PrintMessageStringV(3952, L"/PASSWORDCHG");
1303 result = 1;
1304 goto done;
1305 }
1306 }
1307 else if (_wcsnicmp(argv[j], L"/passwordreq:", 13) == 0)
1308 {
1309 p = &argv[i][13];
1310 if (_wcsicmp(p, L"yes") == 0)
1311 {
1312 pUserInfo->usri4_flags &= ~UF_PASSWD_NOTREQD;
1313 }
1314 else if (_wcsicmp(p, L"no") == 0)
1315 {
1316 pUserInfo->usri4_flags |= UF_PASSWD_NOTREQD;
1317 }
1318 else
1319 {
1320 PrintMessageStringV(3952, L"/PASSWORDREQ");
1321 result = 1;
1322 goto done;
1323 }
1324 }
1325 else if (_wcsnicmp(argv[j], L"/profilepath:", 13) == 0)
1326 {
1327 pUserInfo->usri4_profile = &argv[j][13];
1328 }
1329 else if (_wcsnicmp(argv[j], L"/scriptpath:", 12) == 0)
1330 {
1331 pUserInfo->usri4_script_path = &argv[j][12];
1332 }
1333 else if (_wcsnicmp(argv[j], L"/times:", 7) == 0)
1334 {
1335 Status = ParseLogonHours(&argv[j][7],
1336 &pLogonHours,
1337 &dwUnitsPerWeek);
1338 if (Status == ERROR_SUCCESS)
1339 {
1340 pUserInfo->usri4_logon_hours = pLogonHours;
1341 pUserInfo->usri4_units_per_week = dwUnitsPerWeek;
1342 }
1343 else
1344 {
1345 PrintMessageString(Status);
1346 goto done;
1347 }
1348 }
1349 else if (_wcsnicmp(argv[j], L"/usercomment:", 13) == 0)
1350 {
1351 pUserInfo->usri4_usr_comment = &argv[j][13];
1352 }
1353 else if (_wcsnicmp(argv[j], L"/workstations:", 14) == 0)
1354 {
1355 p = &argv[i][14];
1356 if (wcscmp(p, L"*") == 0 || wcscmp(p, L"") == 0)
1357 {
1358 pUserInfo->usri4_workstations = NULL;
1359 }
1360 else
1361 {
1362 Status = BuildWorkstationsList(&pWorkstations, p);
1363 if (Status == NERR_Success)
1364 {
1365 pUserInfo->usri4_workstations = pWorkstations;
1366 }
1367 else
1368 {
1369 ConPrintf(StdOut, L"Status %lu\n\n", Status);
1370 result = 1;
1371 goto done;
1372 }
1373 }
1374 }
1375 }
1376
1377 if (!bAdd && !bDelete)
1378 {
1379 /* Modify the user */
1380 Status = NetUserSetInfo(NULL,
1381 lpUserName,
1382 4,
1383 (LPBYTE)pUserInfo,
1384 NULL);
1385 ConPrintf(StdOut, L"Status: %lu\n", Status);
1386 }
1387 else if (bAdd && !bDelete)
1388 {
1389 /* Add the user */
1390 Status = NetUserAdd(NULL,
1391 4,
1392 (LPBYTE)pUserInfo,
1393 NULL);
1394 ConPrintf(StdOut, L"Status: %lu\n", Status);
1395 }
1396 else if (!bAdd && bDelete)
1397 {
1398 /* Delete the user */
1399 Status = NetUserDel(NULL,
1400 lpUserName);
1401 ConPrintf(StdOut, L"Status: %lu\n", Status);
1402 }
1403
1404 if (Status == NERR_Success &&
1405 lpPassword != NULL &&
1406 bRandomPassword == TRUE)
1407 {
1408 PrintMessageStringV(3968, lpUserName, lpPassword);
1409 }
1410
1411 done:
1412 if (pLogonHours != NULL)
1413 HeapFree(GetProcessHeap(), 0, pLogonHours);
1414
1415 if (pWorkstations != NULL)
1416 HeapFree(GetProcessHeap(), 0, pWorkstations);
1417
1418 if ((bPasswordAllocated == TRUE) && (lpPassword != NULL))
1419 HeapFree(GetProcessHeap(), 0, lpPassword);
1420
1421 if (!bAdd && !bDelete && pUserInfo != NULL)
1422 NetApiBufferFree(pUserInfo);
1423
1424 if (result != 0)
1425 {
1426 PrintMessageString(4381);
1427 ConPuts(StdOut, L"\n");
1428 PrintNetMessage(MSG_USER_SYNTAX);
1429 }
1430
1431 return result;
1432 }
1433
1434 /* EOF */