]> sourceware.org Git - newlib-cygwin.git/blob - winsup/utils/mkpasswd.c
2003-03-01 Pierre Humblet <pierre.humblet@ieee.org>
[newlib-cygwin.git] / winsup / utils / mkpasswd.c
1 /* mkpasswd.c:
2
3 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include <ctype.h>
12 #include <stdlib.h>
13 #include <wchar.h>
14 #include <stdio.h>
15 #include <windows.h>
16 #include <io.h>
17 #include <unistd.h>
18 #include <sys/cygwin.h>
19 #include <getopt.h>
20 #include <lmaccess.h>
21 #include <lmapibuf.h>
22 #include <sys/fcntl.h>
23 #include <lmerr.h>
24 #include <lmcons.h>
25
26 static const char version[] = "$Revision$";
27
28 SID_IDENTIFIER_AUTHORITY sid_world_auth = {SECURITY_WORLD_SID_AUTHORITY};
29 SID_IDENTIFIER_AUTHORITY sid_nt_auth = {SECURITY_NT_AUTHORITY};
30
31 NET_API_STATUS WINAPI (*netapibufferfree)(PVOID);
32 NET_API_STATUS WINAPI (*netuserenum)(LPWSTR,DWORD,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD);
33 NET_API_STATUS WINAPI (*netlocalgroupenum)(LPWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD);
34 NET_API_STATUS WINAPI (*netgetdcname)(LPWSTR,LPWSTR,PBYTE*);
35 NET_API_STATUS WINAPI (*netusergetinfo)(LPWSTR,LPWSTR,DWORD,PBYTE*);
36
37 #ifndef min
38 #define min(a,b) (((a)<(b))?(a):(b))
39 #endif
40
41 BOOL
42 load_netapi ()
43 {
44 HANDLE h = LoadLibrary ("netapi32.dll");
45
46 if (!h)
47 return FALSE;
48
49 if (!(netapibufferfree = (void *) GetProcAddress (h, "NetApiBufferFree")))
50 return FALSE;
51 if (!(netuserenum = (void *) GetProcAddress (h, "NetUserEnum")))
52 return FALSE;
53 if (!(netlocalgroupenum = (void *) GetProcAddress (h, "NetLocalGroupEnum")))
54 return FALSE;
55 if (!(netgetdcname = (void *) GetProcAddress (h, "NetGetDCName")))
56 return FALSE;
57 if (!(netusergetinfo = (void *) GetProcAddress (h, "NetUserGetInfo")))
58 return FALSE;
59
60 return TRUE;
61 }
62
63 char *
64 put_sid (PSID sid)
65 {
66 static char s[512];
67 char t[32];
68 DWORD i;
69
70 strcpy (s, "S-1-");
71 sprintf(t, "%u", GetSidIdentifierAuthority (sid)->Value[5]);
72 strcat (s, t);
73 for (i = 0; i < *GetSidSubAuthorityCount (sid); ++i)
74 {
75 sprintf(t, "-%lu", *GetSidSubAuthority (sid, i));
76 strcat (s, t);
77 }
78 return s;
79 }
80
81 void
82 psx_dir (char *in, char *out)
83 {
84 if (isalpha (in[0]) && in[1] == ':')
85 {
86 sprintf (out, "/cygdrive/%c", in[0]);
87 in += 2;
88 out += strlen (out);
89 }
90
91 while (*in)
92 {
93 if (*in == '\\')
94 *out = '/';
95 else
96 *out = *in;
97 in++;
98 out++;
99 }
100
101 *out = '\0';
102 }
103
104 void
105 uni2ansi (LPWSTR wcs, char *mbs, int size)
106 {
107 if (wcs)
108 WideCharToMultiByte (CP_ACP, 0, wcs, -1, mbs, size, NULL, NULL);
109 else
110 *mbs = '\0';
111 }
112
113 void
114 print_win_error(DWORD code)
115 {
116 char buf[4096];
117
118 if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
119 | FORMAT_MESSAGE_IGNORE_INSERTS,
120 NULL,
121 code,
122 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
123 (LPTSTR) buf, sizeof (buf), NULL))
124 fprintf (stderr, "mkpasswd: [%lu] %s", code, buf);
125 else
126 fprintf (stderr, "mkpasswd: error %lu", code);
127 }
128
129 void
130 current_user (int print_sids, int print_cygpath,
131 const char * passed_home_path, int id_offset, const char * disp_username)
132 {
133 char name[UNLEN + 1], *envname, *envdomain;
134 DWORD len;
135 HANDLE ptok;
136 int errpos = 0;
137 struct {
138 PSID psid;
139 int buffer[10];
140 } tu, tg;
141
142
143 if ((!GetUserName (name, (len = sizeof (name), &len)) && (errpos = __LINE__))
144 || !name[0]
145 || !(envname = getenv("USERNAME"))
146 || strcasecmp (envname, name)
147 || (disp_username && strcasecmp(envname, disp_username))
148 || (!GetComputerName (name, (len = sizeof (name), &len))
149 && (errpos = __LINE__))
150 || !(envdomain = getenv("USERDOMAIN"))
151 || !envdomain[0]
152 || !strcasecmp (envdomain, name)
153 || (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &ptok)
154 && (errpos = __LINE__))
155 || (!GetTokenInformation (ptok, TokenUser, &tu, sizeof tu, &len)
156 && (errpos = __LINE__))
157 || (!GetTokenInformation (ptok, TokenPrimaryGroup, &tg, sizeof tg, &len)
158 && (errpos = __LINE__))
159 || (!CloseHandle (ptok) && (errpos = __LINE__)))
160 {
161 if (errpos)
162 {
163 print_win_error (GetLastError ());
164 fprintf(stderr, " on line %d\n", errpos);
165 }
166 return;
167 }
168
169 int uid = *GetSidSubAuthority (tu.psid, *GetSidSubAuthorityCount(tu.psid) - 1);
170 int gid = *GetSidSubAuthority (tg.psid, *GetSidSubAuthorityCount(tg.psid) - 1);
171 char homedir_psx[MAX_PATH] = {0}, homedir_w32[MAX_PATH] = {0};
172
173 char *envhomedrive = getenv ("HOMEDRIVE");
174 char *envhomepath = getenv ("HOMEPATH");
175
176 if (passed_home_path[0] == '\0')
177 {
178 if (envhomepath && envhomepath[0])
179 {
180 if (envhomedrive)
181 strlcpy (homedir_w32, envhomedrive, sizeof (homedir_w32));
182 if (envhomepath[0] != '\\')
183 strlcat (homedir_w32, "\\", sizeof (homedir_w32));
184 strlcat (homedir_w32, envhomepath, sizeof (homedir_w32));
185 if (print_cygpath)
186 cygwin_conv_to_posix_path (homedir_w32, homedir_psx);
187 else
188 psx_dir (homedir_w32, homedir_psx);
189 }
190 else
191 {
192 strlcpy (homedir_psx, "/home/", sizeof (homedir_psx));
193 strlcat (homedir_psx, envname, sizeof (homedir_psx));
194 }
195 }
196 else
197 {
198 strlcpy (homedir_psx, passed_home_path, sizeof (homedir_psx));
199 strlcat (homedir_psx, envname, sizeof (homedir_psx));
200 }
201
202 printf ("%s:unused_by_nt/2000/xp:%d:%d:%s%s%s%s%s%s%s%s:%s:/bin/bash\n",
203 envname,
204 uid + id_offset,
205 gid + id_offset,
206 envname,
207 print_sids ? "," : "",
208 print_sids ? "U-" : "",
209 print_sids ? envdomain : "",
210 print_sids ? "\\" : "",
211 print_sids ? envname : "",
212 print_sids ? "," : "",
213 print_sids ? put_sid (tu.psid) : "",
214 homedir_psx);
215 }
216
217 int
218 enum_users (LPWSTR servername, int print_sids, int print_cygpath,
219 const char * passed_home_path, int id_offset, char *disp_username)
220 {
221 USER_INFO_3 *buffer;
222 DWORD entriesread = 0;
223 DWORD totalentries = 0;
224 DWORD resume_handle = 0;
225 DWORD rc;
226 char ansi_srvname[256];
227 WCHAR uni_name[512];
228
229 if (servername)
230 uni2ansi (servername, ansi_srvname, sizeof (ansi_srvname));
231
232 do
233 {
234 DWORD i;
235
236 if (disp_username != NULL)
237 {
238 MultiByteToWideChar (CP_ACP, 0, disp_username, -1, uni_name, 512 );
239 rc = netusergetinfo(servername, (LPWSTR) & uni_name, 3,
240 (LPBYTE *) &buffer );
241 entriesread=1;
242 }
243 else
244 rc = netuserenum (servername, 3, FILTER_NORMAL_ACCOUNT,
245 (LPBYTE *) & buffer, 1024,
246 &entriesread, &totalentries, &resume_handle);
247 switch (rc)
248 {
249 case ERROR_ACCESS_DENIED:
250 print_win_error(rc);
251 exit (1);
252
253 case ERROR_MORE_DATA:
254 case ERROR_SUCCESS:
255 break;
256
257 default:
258 print_win_error(rc);
259 exit (1);
260 }
261
262 for (i = 0; i < entriesread; i++)
263 {
264 char username[100];
265 char fullname[100];
266 char homedir_psx[MAX_PATH];
267 char homedir_w32[MAX_PATH];
268 char domain_name[100];
269 DWORD domname_len = 100;
270 char psid_buffer[1024];
271 PSID psid = (PSID) psid_buffer;
272 DWORD sid_length = 1024;
273 SID_NAME_USE acc_type;
274
275 int uid = buffer[i].usri3_user_id;
276 int gid = buffer[i].usri3_primary_group_id;
277 uni2ansi (buffer[i].usri3_name, username, sizeof (username));
278 uni2ansi (buffer[i].usri3_full_name, fullname, sizeof (fullname));
279 homedir_w32[0] = homedir_psx[0] = '\0';
280 if (passed_home_path[0] == '\0')
281 {
282 uni2ansi (buffer[i].usri3_home_dir, homedir_w32,
283 sizeof (homedir_w32));
284 if (homedir_w32[0] != '\0')
285 {
286 if (print_cygpath)
287 cygwin_conv_to_posix_path (homedir_w32, homedir_psx);
288 else
289 psx_dir (homedir_w32, homedir_psx);
290 }
291 else
292 {
293 strcpy (homedir_psx, "/home/");
294 strcat (homedir_psx, username);
295 }
296 }
297 else
298 {
299 strcpy (homedir_psx, passed_home_path);
300 strcat (homedir_psx, username);
301 }
302
303 if (print_sids)
304 {
305 if (!LookupAccountName (servername ? ansi_srvname : NULL,
306 username,
307 psid, &sid_length,
308 domain_name, &domname_len,
309 &acc_type))
310 {
311 print_win_error(GetLastError ());
312 continue;
313 }
314 else if (acc_type == SidTypeDomain)
315 {
316 char domname[356];
317
318 strcpy (domname, domain_name);
319 strcat (domname, "\\");
320 strcat (domname, username);
321 sid_length = 1024;
322 domname_len = 100;
323 if (!LookupAccountName (servername ? ansi_srvname : NULL,
324 domname,
325 psid, &sid_length,
326 domain_name, &domname_len,
327 &acc_type))
328 {
329 print_win_error(GetLastError ());
330 continue;
331 }
332 }
333 }
334 printf ("%s:unused_by_nt/2000/xp:%d:%d:%s%s%s%s%s%s%s%s:%s:/bin/bash\n",
335 username,
336 uid + id_offset,
337 gid + id_offset,
338 fullname,
339 print_sids && fullname[0] ? "," : "",
340 print_sids ? "U-" : "",
341 print_sids ? domain_name : "",
342 print_sids && domain_name[0] ? "\\" : "",
343 print_sids ? username : "",
344 print_sids ? "," : "",
345 print_sids ? put_sid (psid) : "",
346 homedir_psx);
347 }
348
349 netapibufferfree (buffer);
350
351 }
352 while (rc == ERROR_MORE_DATA);
353
354 if (servername)
355 netapibufferfree (servername);
356
357 return 0;
358 }
359
360 int
361 enum_local_groups (int print_sids)
362 {
363 LOCALGROUP_INFO_0 *buffer;
364 DWORD entriesread = 0;
365 DWORD totalentries = 0;
366 DWORD resume_handle = 0;
367 DWORD rc ;
368
369 do
370 {
371 DWORD i;
372
373 rc = netlocalgroupenum (NULL, 0, (LPBYTE *) & buffer, 1024,
374 &entriesread, &totalentries, &resume_handle);
375 switch (rc)
376 {
377 case ERROR_ACCESS_DENIED:
378 print_win_error(rc);
379 exit (1);
380
381 case ERROR_MORE_DATA:
382 case ERROR_SUCCESS:
383 break;
384
385 default:
386 print_win_error(rc);
387 exit (1);
388 }
389
390 for (i = 0; i < entriesread; i++)
391 {
392 char localgroup_name[100];
393 char domain_name[100];
394 DWORD domname_len = 100;
395 char psid_buffer[1024];
396 PSID psid = (PSID) psid_buffer;
397 DWORD sid_length = 1024;
398 DWORD gid;
399 SID_NAME_USE acc_type;
400 uni2ansi (buffer[i].lgrpi0_name, localgroup_name, sizeof (localgroup_name));
401
402 if (!LookupAccountName (NULL, localgroup_name, psid,
403 &sid_length, domain_name, &domname_len,
404 &acc_type))
405 {
406 print_win_error(GetLastError ());
407 continue;
408 }
409 else if (acc_type == SidTypeDomain)
410 {
411 char domname[356];
412
413 strcpy (domname, domain_name);
414 strcat (domname, "\\");
415 strcat (domname, localgroup_name);
416 sid_length = 1024;
417 domname_len = 100;
418 if (!LookupAccountName (NULL, domname,
419 psid, &sid_length,
420 domain_name, &domname_len,
421 &acc_type))
422 {
423 print_win_error(GetLastError ());
424 continue;
425 }
426 }
427
428 gid = *GetSidSubAuthority (psid, *GetSidSubAuthorityCount(psid) - 1);
429
430 printf ("%s:*:%ld:%ld:%s%s::\n", localgroup_name, gid, gid,
431 print_sids ? "," : "",
432 print_sids ? put_sid (psid) : "");
433 }
434
435 netapibufferfree (buffer);
436
437 }
438 while (rc == ERROR_MORE_DATA);
439
440 return 0;
441 }
442
443 void
444 print_special (int print_sids,
445 PSID_IDENTIFIER_AUTHORITY auth, BYTE cnt,
446 DWORD sub1, DWORD sub2, DWORD sub3, DWORD sub4,
447 DWORD sub5, DWORD sub6, DWORD sub7, DWORD sub8)
448 {
449 char name[256], dom[256];
450 DWORD len, len2, rid;
451 PSID sid;
452 SID_NAME_USE use;
453
454 if (AllocateAndInitializeSid (auth, cnt, sub1, sub2, sub3, sub4,
455 sub5, sub6, sub7, sub8, &sid))
456 {
457 if (LookupAccountSid (NULL, sid,
458 name, (len = 256, &len),
459 dom, (len2 = 256, &len),
460 &use))
461 {
462 if (sub8)
463 rid = sub8;
464 else if (sub7)
465 rid = sub7;
466 else if (sub6)
467 rid = sub6;
468 else if (sub5)
469 rid = sub5;
470 else if (sub4)
471 rid = sub4;
472 else if (sub3)
473 rid = sub3;
474 else if (sub2)
475 rid = sub2;
476 else
477 rid = sub1;
478 printf ("%s:*:%lu:%lu:%s%s::\n",
479 name, rid, rid == 18 ? 544 : rid, /* SYSTEM hack */
480 print_sids ? "," : "",
481 print_sids ? put_sid (sid) : "");
482 }
483 FreeSid (sid);
484 }
485 }
486
487 int
488 usage (FILE * stream, int isNT)
489 {
490 fprintf (stream, "Usage: mkpasswd [OPTION]... [domain]\n\n"
491 "This program prints a /etc/passwd file to stdout\n\n"
492 "Options:\n");
493 if (isNT)
494 fprintf (stream, " -l,--local print local user accounts\n"
495 " -c,--current print current account, if a domain account\n"
496 " -d,--domain print domain accounts (from current domain\n"
497 " if no domain specified)\n"
498 " -o,--id-offset offset change the default offset (10000) added to uids\n"
499 " in domain accounts.\n"
500 " -g,--local-groups print local group information too\n"
501 " if no domain specified\n"
502 " -m,--no-mount don't use mount points for home dir\n"
503 " -s,--no-sids don't print SIDs in GCOS field\n"
504 " (this affects ntsec)\n");
505 fprintf (stream, " -p,--path-to-home path use specified path instead of user account home dir\n"
506 " -u,--username username only return information for the specified user\n"
507 " -h,--help displays this message\n"
508 " -v,--version version information and exit\n\n");
509 if (isNT)
510 fprintf (stream, "One of `-l', `-d' or `-g' must be given.\n");
511 return 1;
512 }
513
514 struct option longopts[] = {
515 {"local", no_argument, NULL, 'l'},
516 {"current", no_argument, NULL, 'c'},
517 {"domain", no_argument, NULL, 'd'},
518 {"id-offset", required_argument, NULL, 'o'},
519 {"local-groups", no_argument, NULL, 'g'},
520 {"no-mount", no_argument, NULL, 'm'},
521 {"no-sids", no_argument, NULL, 's'},
522 {"path-to-home", required_argument, NULL, 'p'},
523 {"username", required_argument, NULL, 'u'},
524 {"help", no_argument, NULL, 'h'},
525 {"version", no_argument, NULL, 'v'},
526 {0, no_argument, NULL, 0}
527 };
528
529 char opts[] = "lcdo:gsmhp:u:v";
530
531 static void
532 print_version ()
533 {
534 const char *v = strchr (version, ':');
535 int len;
536 if (!v)
537 {
538 v = "?";
539 len = 1;
540 }
541 else
542 {
543 v += 2;
544 len = strchr (v, ' ') - v;
545 }
546 printf ("\
547 mkpasswd (cygwin) %.*s\n\
548 passwd File Generator\n\
549 Copyright 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.\n\
550 Compiled on %s\n\
551 ", len, v, __DATE__);
552 }
553
554 int
555 main (int argc, char **argv)
556 {
557 LPWSTR servername = NULL;
558 DWORD rc = ERROR_SUCCESS;
559 WCHAR domain_name[200];
560 int print_local = 0;
561 int print_current = 0;
562 int print_domain = 0;
563 int print_local_groups = 0;
564 int domain_name_specified = 0;
565 int print_sids = 1;
566 int print_cygpath = 1;
567 int id_offset = 10000;
568 int i;
569 int isNT;
570 char *disp_username = NULL;
571 char name[256], passed_home_path[MAX_PATH];
572 DWORD len;
573
574 isNT = (GetVersion () < 0x80000000);
575 passed_home_path[0] = '\0';
576 if (!isatty (1))
577 setmode (1, O_BINARY);
578
579 if (isNT && argc == 1)
580 return usage (stderr, isNT);
581 else
582 {
583 while ((i = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
584 switch (i)
585 {
586 case 'l':
587 print_local = 1;
588 break;
589 case 'c':
590 print_current = 1;
591 break;
592 case 'd':
593 print_domain = 1;
594 break;
595 case 'o':
596 id_offset = strtol (optarg, NULL, 10);
597 break;
598 case 'g':
599 print_local_groups = 1;
600 break;
601 case 's':
602 print_sids = 0;
603 break;
604 case 'm':
605 print_cygpath = 0;
606 break;
607 case 'p':
608 if (optarg[0] != '/')
609 {
610 fprintf (stderr, "%s: `%s' is not a fully qualified path.\n",
611 argv[0], optarg);
612 return 1;
613 }
614 strcpy (passed_home_path, optarg);
615 if (optarg[strlen (optarg)-1] != '/')
616 strcat (passed_home_path, "/");
617 break;
618 case 'u':
619 disp_username = optarg;
620 break;
621 case 'h':
622 usage (stdout, isNT);
623 return 0;
624 case 'v':
625 print_version ();
626 return 0;
627 default:
628 fprintf (stderr, "Try `%s --help' for more information.\n", argv[0]);
629 return 1;
630 }
631 }
632 if (!isNT)
633 {
634 /* This takes Windows 9x/ME into account. */
635 if (passed_home_path[0] == '\0')
636 strcpy (passed_home_path, "/home/");
637 if (!disp_username)
638 {
639 printf ("admin:use_crypt:%lu:%lu:Administrator:%sadmin:/bin/bash\n",
640 DOMAIN_USER_RID_ADMIN,
641 DOMAIN_ALIAS_RID_ADMINS,
642 passed_home_path);
643 if (GetUserName (name, (len = 256, &len)))
644 disp_username = name;
645 }
646 if (disp_username && disp_username[0])
647 {
648 /* Create a pseudo random uid */
649 unsigned long uid = 0, i;
650 for (i = 0; disp_username[i]; i++)
651 uid += toupper (disp_username[i]) << ((6 * i) % 25);
652 uid = (uid % (65535 - DOMAIN_USER_RID_ADMIN - 1))
653 + DOMAIN_USER_RID_ADMIN + 1;
654
655 printf ("%s:use_crypt:%lu:%lu:%s:%s%s:/bin/bash\n",
656 disp_username,
657 uid,
658 DOMAIN_ALIAS_RID_ADMINS,
659 disp_username,
660 passed_home_path,
661 disp_username);
662 }
663 return 0;
664 }
665 if (!print_local && !print_domain && !print_local_groups)
666 {
667 fprintf (stderr, "%s: Specify one of `-l', `-d' or `-g'\n", argv[0]);
668 return 1;
669 }
670 if (optind < argc)
671 {
672 if (!print_domain)
673 {
674 fprintf (stderr, "%s: A domain name is only accepted "
675 "when `-d' is given.\n", argv[0]);
676 return 1;
677 }
678 mbstowcs (domain_name, argv[optind], (strlen (argv[optind]) + 1));
679 domain_name_specified = 1;
680 }
681 if (!load_netapi ())
682 {
683 print_win_error(GetLastError ());
684 return 1;
685 }
686
687 if (disp_username == NULL)
688 {
689 #if 0
690 /*
691 * Get `Everyone' group
692 */
693 print_special (print_sids, &sid_world_auth, 1, SECURITY_WORLD_RID,
694 0, 0, 0, 0, 0, 0, 0);
695 #endif
696 /*
697 * Get `system' group
698 */
699 print_special (print_sids, &sid_nt_auth, 1, SECURITY_LOCAL_SYSTEM_RID,
700 0, 0, 0, 0, 0, 0, 0);
701 /*
702 * Get `administrators' group
703 */
704 if (!print_local_groups)
705 print_special (print_sids, &sid_nt_auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
706 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0);
707
708 if (print_local_groups)
709 enum_local_groups (print_sids);
710 }
711
712 if (print_domain)
713 {
714 if (domain_name_specified)
715 rc = netgetdcname (NULL, domain_name, (LPBYTE *) & servername);
716
717 else
718 rc = netgetdcname (NULL, NULL, (LPBYTE *) & servername);
719
720 if (rc != ERROR_SUCCESS)
721 {
722 print_win_error(rc);
723 return 1;
724 }
725
726 enum_users (servername, print_sids, print_cygpath, passed_home_path,
727 id_offset, disp_username);
728 }
729
730 if (print_local)
731 enum_users (NULL, print_sids, print_cygpath, passed_home_path, 0,
732 disp_username);
733
734 if (print_current && !print_domain)
735 current_user(print_sids, print_cygpath, passed_home_path,
736 id_offset, disp_username);
737
738 if (servername)
739 netapibufferfree (servername);
740
741 return 0;
742 }
This page took 0.072428 seconds and 6 git commands to generate.