3 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006,
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
12 #define _WIN32_WINNT 0x0600
20 #include <sys/fcntl.h>
21 #include <sys/cygwin.h>
30 #define print_win_error(x) _print_win_error(x, __LINE__)
32 #define MAX_SID_LEN 40
34 static const char version
[] = "$Revision$";
36 extern char *__progname
;
38 SID_IDENTIFIER_AUTHORITY sid_world_auth
= {SECURITY_WORLD_SID_AUTHORITY
};
39 SID_IDENTIFIER_AUTHORITY sid_nt_auth
= {SECURITY_NT_AUTHORITY
};
41 NET_API_STATUS
WINAPI (*dsgetdcname
)(LPWSTR
,LPWSTR
,GUID
*,LPWSTR
,ULONG
,PDOMAIN_CONTROLLER_INFOW
*);
44 #define min(a,b) (((a)<(b))?(a):(b))
54 _print_win_error(DWORD code
, int line
)
58 if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
59 | FORMAT_MESSAGE_IGNORE_INSERTS
,
62 MAKELANGID (LANG_NEUTRAL
, SUBLANG_DEFAULT
),
63 (LPTSTR
) buf
, sizeof (buf
), NULL
))
64 fprintf (stderr
, "mkpasswd (%d): [%lu] %s", line
, code
, buf
);
66 fprintf (stderr
, "mkpasswd (%d): error %lu", line
, code
);
72 HANDLE h
= LoadLibrary ("netapi32.dll");
75 dsgetdcname
= (void *) GetProcAddress (h
, "DsGetDcNameW");
79 get_dcname (char *domain
)
81 static WCHAR server
[INTERNET_MAX_HOST_NAME_LENGTH
+ 1];
84 WCHAR domain_name
[MAX_DOMAIN_NAME_LEN
+ 1];
85 PDOMAIN_CONTROLLER_INFOW pdci
= NULL
;
91 mbstowcs (domain_name
, domain
, strlen (domain
) + 1);
92 rc
= dsgetdcname (NULL
, domain_name
, NULL
, NULL
, 0, &pdci
);
95 rc
= dsgetdcname (NULL
, NULL
, NULL
, NULL
, 0, &pdci
);
96 if (rc
!= ERROR_SUCCESS
)
101 wcscpy (server
, pdci
->DomainControllerName
);
102 NetApiBufferFree (pdci
);
106 rc
= NetGetDCName (NULL
, NULL
, (void *) &servername
);
107 if (rc
== ERROR_SUCCESS
&& domain
)
109 LPWSTR server
= servername
;
110 mbstowcs (domain_name
, domain
, strlen (domain
) + 1);
111 rc
= NetGetDCName (server
, domain_name
, (void *) &servername
);
112 NetApiBufferFree (server
);
114 if (rc
!= ERROR_SUCCESS
)
119 wcscpy (server
, servername
);
120 NetApiBufferFree ((PVOID
) servername
);
133 sprintf(t
, "%u", GetSidIdentifierAuthority (sid
)->Value
[5]);
135 for (i
= 0; i
< *GetSidSubAuthorityCount (sid
); ++i
)
137 sprintf(t
, "-%lu", *GetSidSubAuthority (sid
, i
));
144 psx_dir (char *in
, char *out
)
146 if (isalpha (in
[0]) && in
[1] == ':')
148 sprintf (out
, "/cygdrive/%c", in
[0]);
167 uni2ansi (LPWSTR wcs
, char *mbs
, int size
)
170 wcstombs (mbs
, wcs
, size
);
176 current_user (int print_cygpath
, const char *sep
, const char *passed_home_path
,
177 int id_offset
, const char *disp_username
)
185 char user
[UNLEN
+ 1];
186 char dom
[MAX_DOMAIN_NAME_LEN
+ 1];
187 DWORD ulen
= UNLEN
+ 1;
188 DWORD dlen
= MAX_DOMAIN_NAME_LEN
+ 1;
189 SID_NAME_USE acc_type
;
191 char homedir_psx
[PATH_MAX
] = {0}, homedir_w32
[MAX_PATH
] = {0};
193 if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY
, &ptok
)
194 || !GetTokenInformation (ptok
, TokenUser
, &tu
, sizeof tu
, &len
)
195 || !GetTokenInformation (ptok
, TokenPrimaryGroup
, &tg
, sizeof tg
, &len
)
196 || !CloseHandle (ptok
)
197 || !LookupAccountSidA (NULL
, tu
.psid
, user
, &ulen
, dom
, &dlen
, &acc_type
))
199 print_win_error (GetLastError ());
203 uid
= *GetSidSubAuthority (tu
.psid
, *GetSidSubAuthorityCount(tu
.psid
) - 1);
204 gid
= *GetSidSubAuthority (tg
.psid
, *GetSidSubAuthorityCount(tg
.psid
) - 1);
205 if (passed_home_path
[0] == '\0')
207 char *envhome
= getenv ("HOME");
208 char *envhomedrive
= getenv ("HOMEDRIVE");
209 char *envhomepath
= getenv ("HOMEPATH");
211 if (envhome
&& envhome
[0])
214 cygwin_conv_path (CCP_WIN_A_TO_POSIX
| CCP_ABSOLUTE
, envhome
,
215 homedir_psx
, PATH_MAX
);
217 psx_dir (envhome
, homedir_psx
);
219 else if (envhomepath
&& envhomepath
[0])
222 strlcpy (homedir_w32
, envhomedrive
, sizeof (homedir_w32
));
223 if (envhomepath
[0] != '\\')
224 strlcat (homedir_w32
, "\\", sizeof (homedir_w32
));
225 strlcat (homedir_w32
, envhomepath
, sizeof (homedir_w32
));
227 cygwin_conv_path (CCP_WIN_A_TO_POSIX
| CCP_ABSOLUTE
, homedir_w32
,
228 homedir_psx
, PATH_MAX
);
230 psx_dir (homedir_w32
, homedir_psx
);
234 strlcpy (homedir_psx
, "/home/", sizeof (homedir_psx
));
235 strlcat (homedir_psx
, user
, sizeof (homedir_psx
));
240 strlcpy (homedir_psx
, passed_home_path
, sizeof (homedir_psx
));
241 strlcat (homedir_psx
, user
, sizeof (homedir_psx
));
244 printf ("%s%s%s:unused:%u:%u:U-%s\\%s,%s:%s:/bin/bash\n",
257 enum_users (BOOL domain
, domlist_t
*dom_or_machine
, const char *sep
,
258 int print_cygpath
, const char *passed_home_path
, int id_offset
,
261 WCHAR machine
[INTERNET_MAX_HOST_NAME_LENGTH
+ 1];
262 PWCHAR servername
= NULL
;
263 char *d_or_m
= dom_or_machine
? dom_or_machine
->str
: NULL
;
264 BOOL with_dom
= dom_or_machine
? dom_or_machine
->with_dom
: FALSE
;
266 DWORD entriesread
= 0;
267 DWORD totalentries
= 0;
268 DWORD resume_handle
= 0;
270 WCHAR uni_name
[UNLEN
+ 1];
274 servername
= get_dcname (d_or_m
);
275 if (servername
== (PWCHAR
) -1)
280 int ret
= mbstowcs (machine
, d_or_m
, INTERNET_MAX_HOST_NAME_LENGTH
+ 1);
281 if (ret
< 1 || ret
>= INTERNET_MAX_HOST_NAME_LENGTH
+ 1)
283 fprintf (stderr
, "%s: Invalid machine name '%s'. Skipping...\n",
287 servername
= machine
;
294 if (disp_username
!= NULL
)
296 mbstowcs (uni_name
, disp_username
, UNLEN
+ 1);
297 rc
= NetUserGetInfo (servername
, (LPWSTR
) &uni_name
, 3,
302 rc
= NetUserEnum (servername
, 3, FILTER_NORMAL_ACCOUNT
,
303 (void *) &buffer
, MAX_PREFERRED_LENGTH
,
304 &entriesread
, &totalentries
, &resume_handle
);
307 case ERROR_ACCESS_DENIED
:
311 case ERROR_MORE_DATA
:
320 for (i
= 0; i
< entriesread
; i
++)
322 char homedir_psx
[PATH_MAX
];
323 char homedir_w32
[MAX_PATH
];
324 WCHAR domain_name
[MAX_DOMAIN_NAME_LEN
+ 1];
325 DWORD domname_len
= MAX_DOMAIN_NAME_LEN
+ 1;
326 char psid_buffer
[MAX_SID_LEN
];
327 PSID psid
= (PSID
) psid_buffer
;
328 DWORD sid_length
= MAX_SID_LEN
;
329 SID_NAME_USE acc_type
;
331 int uid
= buffer
[i
].usri3_user_id
;
332 int gid
= buffer
[i
].usri3_primary_group_id
;
333 homedir_w32
[0] = homedir_psx
[0] = '\0';
334 if (passed_home_path
[0] == '\0')
336 uni2ansi (buffer
[i
].usri3_home_dir
, homedir_w32
,
337 sizeof (homedir_w32
));
338 if (homedir_w32
[0] != '\0')
341 cygwin_conv_path (CCP_WIN_A_TO_POSIX
| CCP_ABSOLUTE
,
342 homedir_w32
, homedir_psx
, PATH_MAX
);
344 psx_dir (homedir_w32
, homedir_psx
);
347 uni2ansi (buffer
[i
].usri3_name
,
348 stpcpy (homedir_psx
, "/home/"), PATH_MAX
- 6);
351 uni2ansi (buffer
[i
].usri3_name
,
352 stpcpy (homedir_psx
, passed_home_path
),
353 PATH_MAX
- strlen (passed_home_path
));
355 if (!LookupAccountNameW (servername
, buffer
[i
].usri3_name
,
356 psid
, &sid_length
, domain_name
,
357 &domname_len
, &acc_type
))
359 print_win_error(GetLastError ());
360 fprintf(stderr
, " (%ls)\n", buffer
[i
].usri3_name
);
363 else if (acc_type
== SidTypeDomain
)
365 WCHAR domname
[MAX_DOMAIN_NAME_LEN
+ UNLEN
+ 2];
367 wcscpy (domname
, domain_name
);
368 wcscat (domname
, L
"\\");
369 wcscat (domname
, buffer
[i
].usri3_name
);
370 sid_length
= MAX_SID_LEN
;
371 domname_len
= sizeof (domname
);
372 if (!LookupAccountNameW (servername
, domname
, psid
,
373 &sid_length
, domain_name
,
374 &domname_len
, &acc_type
))
376 print_win_error(GetLastError ());
377 fprintf(stderr
, " (%ls)\n", domname
);
382 printf ("%ls%s%ls:unused:%u:%u:%ls%sU-%ls\\%ls,%s:%s:/bin/bash\n",
383 with_dom
? domain_name
: L
"",
385 buffer
[i
].usri3_name
,
388 buffer
[i
].usri3_full_name
?: L
"",
389 buffer
[i
].usri3_full_name
390 && buffer
[i
].usri3_full_name
[0] ? "," : "",
392 buffer
[i
].usri3_name
,
397 NetApiBufferFree (buffer
);
400 while (rc
== ERROR_MORE_DATA
);
406 print_special (PSID_IDENTIFIER_AUTHORITY auth
, BYTE cnt
,
407 DWORD sub1
, DWORD sub2
, DWORD sub3
, DWORD sub4
,
408 DWORD sub5
, DWORD sub6
, DWORD sub7
, DWORD sub8
)
410 char name
[UNLEN
+ 1], dom
[MAX_DOMAIN_NAME_LEN
+ 1];
411 DWORD len
, len2
, rid
;
415 if (AllocateAndInitializeSid (auth
, cnt
, sub1
, sub2
, sub3
, sub4
,
416 sub5
, sub6
, sub7
, sub8
, &sid
))
418 if (LookupAccountSid (NULL
, sid
,
419 name
, (len
= UNLEN
+ 1, &len
),
420 dom
, (len2
= MAX_DOMAIN_NAME_LEN
+ 1, &len
),
439 printf ("%s:*:%lu:%lu:,%s::\n",
440 name
, rid
, rid
== 18 ? 544 : rid
, /* SYSTEM hack */
448 usage (FILE * stream
)
451 "Usage: mkpasswd [OPTIONS]...\n"
452 "Print /etc/passwd file to stdout\n"
455 " -l,--local [machine] print local user accounts (from local machine\n"
456 " if no machine specified)\n"
457 " -L,--Local [machine] ditto, but generate username with machine prefix\n"
458 " -d,--domain [domain] print domain accounts (from current domain\n"
459 " if no domain specified)\n"
460 " -D,--Domain [domain] ditto, but generate username with domain prefix\n"
461 " -c,--current print current user\n"
462 " -C,--Current ditto, but generate username with machine or\n"
464 " -S,--separator char for -L, -D, -C use character char as domain\\user\n"
465 " separator in username instead of the default '\\'\n"
466 " -o,--id-offset offset change the default offset (10000) added to uids\n"
467 " in domain or foreign server accounts.\n"
468 " -u,--username username only return information for the specified user\n"
469 " one of -l, -L, -d, -D must be specified, too\n"
470 " -p,--path-to-home path use specified path instead of user account home dir\n"
472 " -m,--no-mount don't use mount points for home dir\n"
473 " -s,--no-sids (ignored)\n"
474 " -g,--local-groups (ignored)\n"
475 " -h,--help displays this message\n"
476 " -v,--version version information and exit\n"
478 "Default is to print local accounts on stand-alone machines, domain accounts\n"
479 "on domain controllers and domain member machines.\n");
483 struct option longopts
[] = {
484 {"current", no_argument
, NULL
, 'c'},
485 {"Current", no_argument
, NULL
, 'C'},
486 {"domain", optional_argument
, NULL
, 'd'},
487 {"Domain", optional_argument
, NULL
, 'D'},
488 {"local-groups", no_argument
, NULL
, 'g'},
489 {"help", no_argument
, NULL
, 'h'},
490 {"local", optional_argument
, NULL
, 'l'},
491 {"Local", optional_argument
, NULL
, 'L'},
492 {"no-mount", no_argument
, NULL
, 'm'},
493 {"id-offset", required_argument
, NULL
, 'o'},
494 {"path-to-home", required_argument
, NULL
, 'p'},
495 {"no-sids", no_argument
, NULL
, 's'},
496 {"separator", required_argument
, NULL
, 'S'},
497 {"username", required_argument
, NULL
, 'u'},
498 {"version", no_argument
, NULL
, 'v'},
499 {0, no_argument
, NULL
, 0}
502 char opts
[] = "cCd::D::ghl::L::mo:sS:p:u:v";
507 const char *v
= strchr (version
, ':');
517 len
= strchr (v
, ' ') - v
;
520 mkpasswd (cygwin) %.*s\n\
521 passwd File Generator\n\
522 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2008 Red Hat, Inc.\n\
524 ", len
, v
, __DATE__
);
530 /* Generate service starter account entries. */
531 printf ("SYSTEM:*:18:544:,S-1-5-18::\n");
532 printf ("LocalService:*:19:544:U-NT AUTHORITY\\LocalService,S-1-5-19::\n");
533 printf ("NetworkService:*:20:544:U-NT AUTHORITY\\NetworkService,S-1-5-20::\n");
534 /* Get 'administrators' group (has localized name). */
535 print_special (&sid_nt_auth
, 2, SECURITY_BUILTIN_DOMAIN_RID
,
536 DOMAIN_ALIAS_RID_ADMINS
, 0, 0, 0, 0, 0, 0);
539 static PPOLICY_PRIMARY_DOMAIN_INFO p_dom
;
542 fetch_primary_domain ()
545 LSA_OBJECT_ATTRIBUTES oa
= { 0, 0, 0, 0, 0, 0 };
550 status
= LsaOpenPolicy (NULL
, &oa
, POLICY_VIEW_LOCAL_INFORMATION
, &lsa
);
551 if (!NT_SUCCESS (status
))
553 status
= LsaQueryInformationPolicy (lsa
, PolicyPrimaryDomainInformation
,
556 if (!NT_SUCCESS (status
))
563 main (int argc
, char **argv
)
566 domlist_t locals
[16];
567 int print_domain
= 0;
568 domlist_t domains
[16];
570 int print_cygpath
= 1;
571 int print_current
= 0;
572 const char *sep_char
= "\\";
573 int id_offset
= 10000;
575 char *disp_username
= NULL
;
576 char passed_home_path
[PATH_MAX
];
579 passed_home_path
[0] = '\0';
581 setmode (1, O_BINARY
);
584 in_domain
= fetch_primary_domain ();
587 enum_std_accounts ();
589 enum_users (TRUE
, NULL
, sep_char
, print_cygpath
, passed_home_path
,
590 10000, disp_username
);
592 enum_users (FALSE
, NULL
, sep_char
, print_cygpath
, passed_home_path
, 0,
597 while ((c
= getopt_long (argc
, argv
, opts
, longopts
, NULL
)) != EOF
)
602 if (print_local
>= 16)
604 fprintf (stderr
, "%s: Can not enumerate from more than 16 "
605 "servers.\n", __progname
);
609 argv
[optind
] && argv
[optind
][0] != '-' ? argv
[optind
] : NULL
;
610 for (i
= 0; i
< print_local
; ++i
)
611 if ((!locals
[i
].str
&& !opt
)
612 || (locals
[i
].str
&& opt
&& !strcmp (locals
[i
].str
, opt
)))
614 locals
[print_local
].str
= opt
;
615 locals
[print_local
++].with_dom
= c
== 'L';
620 if (print_domain
>= 16)
622 fprintf (stderr
, "%s: Can not enumerate from more than 16 "
623 "domains.\n", __progname
);
627 argv
[optind
] && argv
[optind
][0] != '-' ? argv
[optind
] : NULL
;
628 for (i
= 0; i
< print_domain
; ++i
)
629 if ((!domains
[i
].str
&& !opt
)
630 || (domains
[i
].str
&& opt
&& !strcmp (domains
[i
].str
, opt
)))
632 domains
[print_domain
].str
= opt
;
633 domains
[print_domain
++].with_dom
= c
== 'D';
638 if (strlen (sep_char
) > 1)
640 fprintf (stderr
, "%s: Only one character allowed as domain\\user "
641 "separator character.\n", __progname
);
644 if (*sep_char
== ':')
646 fprintf (stderr
, "%s: Colon not allowed as domain\\user separator "
647 "character.\n", __progname
);
658 id_offset
= strtol (optarg
, NULL
, 10);
668 if (optarg
[0] != '/')
670 fprintf (stderr
, "%s: '%s' is not a fully qualified path.\n",
674 strcpy (passed_home_path
, optarg
);
675 if (optarg
[strlen (optarg
)-1] != '/')
676 strcat (passed_home_path
, "/");
679 disp_username
= optarg
;
688 fprintf (stderr
, "Try '%s --help' for more information.\n", __progname
);
692 if (optind
< argc
- 1)
696 for (i
= 0; i
< print_local
; ++i
)
699 enum_users (FALSE
, locals
+ i
, sep_char
, print_cygpath
,
700 passed_home_path
, id_offset
* off
++, disp_username
);
703 enum_std_accounts ();
704 enum_users (FALSE
, locals
+ i
, sep_char
, print_cygpath
,
705 passed_home_path
, 0, disp_username
);
709 for (i
= 0; i
< print_domain
; ++i
)
710 enum_users (TRUE
, domains
+ i
, sep_char
, print_cygpath
, passed_home_path
,
711 id_offset
* off
++, disp_username
);
714 current_user (print_cygpath
, sep_char
, passed_home_path
, id_offset
, disp_username
);