]> sourceware.org Git - newlib-cygwin.git/blame - winsup/utils/mkpasswd.c
* Merge in cygwin-64bit-branch.
[newlib-cygwin.git] / winsup / utils / mkpasswd.c
CommitLineData
1fd5e000
CF
1/* mkpasswd.c:
2
df0f949c 3 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2008, 2009,
61522196 4 2010, 2011, 2012, 2013 Red Hat, Inc.
1fd5e000
CF
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
a1e19903 12#define _WIN32_WINNT 0x0600
92b499ac 13#include <errno.h>
1fd5e000
CF
14#include <ctype.h>
15#include <stdlib.h>
16#include <wchar.h>
0bdab5c8 17#include <wctype.h>
73535010 18#include <locale.h>
1fd5e000 19#include <stdio.h>
0fa64fa3 20#include <unistd.h>
61522196 21#include <inttypes.h>
315f8fd3 22#include <getopt.h>
a1e19903 23#include <io.h>
12a9c874 24#include <sys/fcntl.h>
a1e19903 25#include <sys/cygwin.h>
92b499ac 26#include <cygwin/version.h>
a1e19903
CV
27#include <windows.h>
28#include <lm.h>
375a780e 29#include <iptypes.h>
a1e19903
CV
30#include <wininet.h>
31#include <ntsecapi.h>
32#include <dsgetdc.h>
33#include <ntdef.h>
71d8f118 34#include "loadlib.h"
1fd5e000 35
114b7248
PH
36#define print_win_error(x) _print_win_error(x, __LINE__)
37
375a780e
CV
38#define MAX_SID_LEN 40
39
1fd5e000
CF
40SID_IDENTIFIER_AUTHORITY sid_world_auth = {SECURITY_WORLD_SID_AUTHORITY};
41SID_IDENTIFIER_AUTHORITY sid_nt_auth = {SECURITY_NT_AUTHORITY};
42
43#ifndef min
44#define min(a,b) (((a)<(b))?(a):(b))
45#endif
46
6510edf4 47typedef struct
a1e19903
CV
48{
49 char *str;
f9519bcd
CV
50 DWORD id_offset;
51 BOOL domain;
a1e19903
CV
52 BOOL with_dom;
53} domlist_t;
54
6510edf4 55static void
a1e19903
CV
56_print_win_error(DWORD code, int line)
57{
58 char buf[4096];
59
60 if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
61 | FORMAT_MESSAGE_IGNORE_INSERTS,
62 NULL,
63 code,
64 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
65 (LPTSTR) buf, sizeof (buf), NULL))
61522196
CV
66 fprintf (stderr, "mkpasswd (%d): [%" PRIu32 "] %s",
67 line, (unsigned int) code, buf);
a1e19903 68 else
61522196
CV
69 fprintf (stderr, "mkpasswd (%d): error %" PRIu32,
70 line, (unsigned int) code);
a1e19903
CV
71}
72
a1e19903
CV
73static PWCHAR
74get_dcname (char *domain)
75{
76 static WCHAR server[INTERNET_MAX_HOST_NAME_LENGTH + 1];
77 DWORD rc;
a1e19903
CV
78 WCHAR domain_name[MAX_DOMAIN_NAME_LEN + 1];
79 PDOMAIN_CONTROLLER_INFOW pdci = NULL;
80
13a20f95 81 if (domain)
a1e19903 82 {
13a20f95
CV
83 mbstowcs (domain_name, domain, strlen (domain) + 1);
84 rc = DsGetDcNameW (NULL, domain_name, NULL, NULL, 0, &pdci);
a1e19903
CV
85 }
86 else
13a20f95
CV
87 rc = DsGetDcNameW (NULL, NULL, NULL, NULL, 0, &pdci);
88 if (rc != ERROR_SUCCESS)
a1e19903 89 {
13a20f95
CV
90 print_win_error (rc);
91 return (PWCHAR) -1;
a1e19903 92 }
13a20f95
CV
93 wcscpy (server, pdci->DomainControllerName);
94 NetApiBufferFree (pdci);
a1e19903
CV
95 return server;
96}
97
6510edf4 98static char *
1fd5e000
CF
99put_sid (PSID sid)
100{
101 static char s[512];
102 char t[32];
103 DWORD i;
104
105 strcpy (s, "S-1-");
106 sprintf(t, "%u", GetSidIdentifierAuthority (sid)->Value[5]);
107 strcat (s, t);
108 for (i = 0; i < *GetSidSubAuthorityCount (sid); ++i)
109 {
61522196 110 sprintf(t, "-%" PRIu32, (unsigned int) *GetSidSubAuthority (sid, i));
1fd5e000
CF
111 strcat (s, t);
112 }
113 return s;
114}
115
6510edf4 116static void
dd9752e8 117uni2ansi (LPWSTR wcs, char *mbs, int size)
1fd5e000
CF
118{
119 if (wcs)
375a780e 120 wcstombs (mbs, wcs, size);
1fd5e000
CF
121 else
122 *mbs = '\0';
123}
124
9258eca9
CV
125typedef struct {
126 PSID psid;
127 int buffer[10];
128} sidbuf;
129
6510edf4
CF
130static sidbuf curr_user;
131static sidbuf curr_pgrp;
132static BOOL got_curr_user = FALSE;
9258eca9 133
6510edf4 134static void
9258eca9 135fetch_current_user_sid ()
7041c7ab 136{
f1c9046a
CV
137 DWORD len;
138 HANDLE ptok;
9258eca9
CV
139
140 if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &ptok)
141 || !GetTokenInformation (ptok, TokenUser, &curr_user, sizeof curr_user,
142 &len)
143 || !GetTokenInformation (ptok, TokenPrimaryGroup, &curr_pgrp,
144 sizeof curr_pgrp, &len)
145 || !CloseHandle (ptok))
146 {
147 print_win_error (GetLastError ());
148 return;
149 }
150}
151
6510edf4 152static void
13a20f95
CV
153current_user (const char *sep, const char *passed_home_path, DWORD id_offset,
154 const char *disp_username)
9258eca9 155{
0bdab5c8
CV
156 WCHAR user[UNLEN + 1];
157 WCHAR dom[MAX_DOMAIN_NAME_LEN + 1];
a1e19903
CV
158 DWORD ulen = UNLEN + 1;
159 DWORD dlen = MAX_DOMAIN_NAME_LEN + 1;
160 SID_NAME_USE acc_type;
161 int uid, gid;
05e6f7b2 162 char homedir_psx[PATH_MAX] = {0};
a1e19903 163
9258eca9
CV
164 if (!curr_user.psid || !curr_pgrp.psid
165 || !LookupAccountSidW (NULL, curr_user.psid, user, &ulen, dom, &dlen,
166 &acc_type))
f1c9046a 167 {
a1e19903 168 print_win_error (GetLastError ());
f1c9046a
CV
169 return;
170 }
171
9258eca9
CV
172 uid = *GetSidSubAuthority (curr_user.psid,
173 *GetSidSubAuthorityCount(curr_user.psid) - 1);
174 gid = *GetSidSubAuthority (curr_pgrp.psid,
175 *GetSidSubAuthorityCount(curr_pgrp.psid) - 1);
f1c9046a
CV
176 if (passed_home_path[0] == '\0')
177 {
6428476b 178 char *envhome = getenv ("HOME");
a1e19903 179
6428476b
CV
180 /* If $HOME exists and is non-empty, just copy it over to homedir_psx.
181 Otherwise, generate a new path of the form "/home/$USER". */
182 if (envhome && envhome[0] != '\0')
183 strncat (homedir_psx, envhome, sizeof (homedir_psx) - 1);
184 else
6510edf4 185 {
0bdab5c8
CV
186 wcstombs (stpncpy (homedir_psx, "/home/", sizeof (homedir_psx)),
187 user, sizeof (homedir_psx) - 6);
188 homedir_psx[PATH_MAX - 1] = '\0';
f1c9046a
CV
189 }
190 }
191 else
192 {
0bdab5c8
CV
193 char *p = stpncpy (homedir_psx, passed_home_path, sizeof (homedir_psx));
194 wcstombs (p, user, sizeof (homedir_psx) - (p - homedir_psx));
195 homedir_psx[PATH_MAX - 1] = '\0';
f1c9046a
CV
196 }
197
61522196
CV
198 printf ("%ls%s%ls:unused:%" PRIu32 ":%" PRIu32
199 ":U-%ls\\%ls,%s:%s:/bin/bash\n",
0bdab5c8 200 sep ? dom : L"",
a1e19903
CV
201 sep ?: "",
202 user,
61522196
CV
203 (unsigned int) (id_offset + uid),
204 (unsigned int) (id_offset + gid),
a1e19903
CV
205 dom,
206 user,
9258eca9 207 put_sid (curr_user.psid),
f1c9046a
CV
208 homedir_psx);
209}
210
6510edf4 211static void
f9519bcd 212enum_unix_users (domlist_t *dom_or_machine, const char *sep, DWORD id_offset,
0bdab5c8
CV
213 char *unix_user_list)
214{
215 WCHAR machine[INTERNET_MAX_HOST_NAME_LENGTH + 1];
216 PWCHAR servername = NULL;
217 char *d_or_m = dom_or_machine ? dom_or_machine->str : NULL;
218 BOOL with_dom = dom_or_machine ? dom_or_machine->with_dom : FALSE;
219 SID_IDENTIFIER_AUTHORITY auth = { { 0, 0, 0, 0, 0, 22 } };
220 char *ustr, *user_list;
221 WCHAR user[UNLEN + sizeof ("Unix User\\") + 1];
222 WCHAR dom[MAX_DOMAIN_NAME_LEN + 1];
223 DWORD ulen, dlen, sidlen;
224 PSID psid;
225 char psid_buffer[MAX_SID_LEN];
226 SID_NAME_USE acc_type;
227
228 if (!d_or_m)
229 return;
230
231 int ret = mbstowcs (machine, d_or_m, INTERNET_MAX_HOST_NAME_LENGTH + 1);
232 if (ret < 1 || ret >= INTERNET_MAX_HOST_NAME_LENGTH + 1)
233 {
234 fprintf (stderr, "%s: Invalid machine name '%s'. Skipping...\n",
92b499ac 235 program_invocation_short_name, d_or_m);
0bdab5c8
CV
236 return;
237 }
238 servername = machine;
239
240 if (!AllocateAndInitializeSid (&auth, 2, 1, 0, 0, 0, 0, 0, 0, 0, &psid))
241 return;
242
243 if (!(user_list = strdup (unix_user_list)))
244 {
245 FreeSid (psid);
246 return;
247 }
248
249 for (ustr = strtok (user_list, ","); ustr; ustr = strtok (NULL, ","))
250 {
05e6f7b2 251 if (!isdigit ((unsigned char) ustr[0]) && ustr[0] != '-')
6510edf4 252 {
0bdab5c8
CV
253 PWCHAR p = wcpcpy (user, L"Unix User\\");
254 ret = mbstowcs (p, ustr, UNLEN + 1);
255 if (ret < 1 || ret >= UNLEN + 1)
256 fprintf (stderr, "%s: Invalid user name '%s'. Skipping...\n",
92b499ac 257 program_invocation_short_name, ustr);
0bdab5c8
CV
258 else if (LookupAccountNameW (servername, user,
259 psid = (PSID) psid_buffer,
260 (sidlen = MAX_SID_LEN, &sidlen),
261 dom,
262 (dlen = MAX_DOMAIN_NAME_LEN + 1, &dlen),
263 &acc_type))
61522196 264 printf ("%s%s%ls:unused:%" PRIu32 ":99999:,%s::\n",
6510edf4
CF
265 with_dom ? "Unix User" : "",
266 with_dom ? sep : "",
267 user + 10,
61522196 268 (unsigned int) (id_offset +
0bdab5c8 269 *GetSidSubAuthority (psid,
61522196 270 *GetSidSubAuthorityCount(psid) - 1)),
6510edf4 271 put_sid (psid));
0bdab5c8
CV
272 }
273 else
274 {
275 DWORD start, stop;
276 char *p = ustr;
277 if (*p == '-')
278 start = 0;
279 else
280 start = strtol (p, &p, 10);
281 if (!*p)
282 stop = start;
05e6f7b2 283 else if (*p++ != '-' || !isdigit ((unsigned char) *p)
0bdab5c8
CV
284 || (stop = strtol (p, &p, 10)) < start || *p)
285 {
286 fprintf (stderr, "%s: Malformed unix user list entry '%s'. "
92b499ac
CV
287 "Skipping...\n",
288 program_invocation_short_name, ustr);
0bdab5c8
CV
289 continue;
290 }
291 for (; start <= stop; ++ start)
292 {
293 *GetSidSubAuthority (psid, *GetSidSubAuthorityCount(psid) - 1)
294 = start;
295 if (LookupAccountSidW (servername, psid,
296 user, (ulen = GNLEN + 1, &ulen),
297 dom,
298 (dlen = MAX_DOMAIN_NAME_LEN + 1, &dlen),
299 &acc_type)
300 && !iswdigit (user[0]))
61522196 301 printf ("%s%s%ls:unused:%" PRIu32 ":99999:,%s::\n",
0bdab5c8
CV
302 with_dom ? "Unix User" : "",
303 with_dom ? sep : "",
304 user,
61522196 305 (unsigned int) (id_offset + start),
0bdab5c8
CV
306 put_sid (psid));
307 }
308 }
309 }
310
311 free (user_list);
312 FreeSid (psid);
313}
314
6510edf4 315static int
a1e19903 316enum_users (BOOL domain, domlist_t *dom_or_machine, const char *sep,
13a20f95
CV
317 const char *passed_home_path, DWORD id_offset, char *disp_username,
318 int print_current)
1fd5e000 319{
a1e19903
CV
320 WCHAR machine[INTERNET_MAX_HOST_NAME_LENGTH + 1];
321 PWCHAR servername = NULL;
322 char *d_or_m = dom_or_machine ? dom_or_machine->str : NULL;
323 BOOL with_dom = dom_or_machine ? dom_or_machine->with_dom : FALSE;
1fd5e000
CF
324 USER_INFO_3 *buffer;
325 DWORD entriesread = 0;
326 DWORD totalentries = 0;
327 DWORD resume_handle = 0;
0ac91154 328 DWORD rc;
375a780e 329 WCHAR uni_name[UNLEN + 1];
a1e19903
CV
330 if (domain)
331 {
332 servername = get_dcname (d_or_m);
333 if (servername == (PWCHAR) -1)
6510edf4 334 return 1;
a1e19903
CV
335 }
336 else if (d_or_m)
337 {
338 int ret = mbstowcs (machine, d_or_m, INTERNET_MAX_HOST_NAME_LENGTH + 1);
339 if (ret < 1 || ret >= INTERNET_MAX_HOST_NAME_LENGTH + 1)
340 {
341 fprintf (stderr, "%s: Invalid machine name '%s'. Skipping...\n",
92b499ac 342 program_invocation_short_name, d_or_m);
a1e19903
CV
343 return 1;
344 }
345 servername = machine;
346 }
1fd5e000
CF
347
348 do
349 {
350 DWORD i;
1fd5e000 351
375a780e
CV
352 if (disp_username != NULL)
353 {
354 mbstowcs (uni_name, disp_username, UNLEN + 1);
355 rc = NetUserGetInfo (servername, (LPWSTR) &uni_name, 3,
356 (void *) &buffer);
357 entriesread = 1;
91dd009e
CV
358 /* Avoid annoying error messages just because the user hasn't been
359 found. */
360 if (rc == NERR_UserNotFound)
361 return 0;
375a780e 362 }
6510edf4 363 else
375a780e
CV
364 rc = NetUserEnum (servername, 3, FILTER_NORMAL_ACCOUNT,
365 (void *) &buffer, MAX_PREFERRED_LENGTH,
366 &entriesread, &totalentries, &resume_handle);
1fd5e000
CF
367 switch (rc)
368 {
369 case ERROR_ACCESS_DENIED:
7041c7ab 370 print_win_error(rc);
a1e19903 371 return 1;
1fd5e000
CF
372
373 case ERROR_MORE_DATA:
374 case ERROR_SUCCESS:
375 break;
376
377 default:
7041c7ab 378 print_win_error(rc);
a1e19903 379 return 1;
1fd5e000
CF
380 }
381
382 for (i = 0; i < entriesread; i++)
383 {
375a780e 384 char homedir_psx[PATH_MAX];
375a780e
CV
385 WCHAR domain_name[MAX_DOMAIN_NAME_LEN + 1];
386 DWORD domname_len = MAX_DOMAIN_NAME_LEN + 1;
387 char psid_buffer[MAX_SID_LEN];
1fd5e000 388 PSID psid = (PSID) psid_buffer;
375a780e 389 DWORD sid_length = MAX_SID_LEN;
1fd5e000
CF
390 SID_NAME_USE acc_type;
391
392 int uid = buffer[i].usri3_user_id;
393 int gid = buffer[i].usri3_primary_group_id;
13a20f95 394 homedir_psx[0] = '\0';
8606f005
CV
395 if (passed_home_path[0] == '\0')
396 {
13a20f95
CV
397 if (buffer[i].usri3_home_dir[0] != L'\0')
398 cygwin_conv_path (CCP_WIN_W_TO_POSIX | CCP_ABSOLUTE,
399 buffer[i].usri3_home_dir, homedir_psx,
400 PATH_MAX);
8606f005 401 else
375a780e
CV
402 uni2ansi (buffer[i].usri3_name,
403 stpcpy (homedir_psx, "/home/"), PATH_MAX - 6);
8606f005 404 }
37c49e19 405 else
375a780e
CV
406 uni2ansi (buffer[i].usri3_name,
407 stpcpy (homedir_psx, passed_home_path),
408 PATH_MAX - strlen (passed_home_path));
9ae2974f 409
a1e19903
CV
410 if (!LookupAccountNameW (servername, buffer[i].usri3_name,
411 psid, &sid_length, domain_name,
412 &domname_len, &acc_type))
1fd5e000 413 {
7041c7ab 414 print_win_error(GetLastError ());
a1e19903 415 fprintf(stderr, " (%ls)\n", buffer[i].usri3_name);
1fd5e000
CF
416 continue;
417 }
37c49e19
CF
418 else if (acc_type == SidTypeDomain)
419 {
a1e19903 420 WCHAR domname[MAX_DOMAIN_NAME_LEN + UNLEN + 2];
375a780e 421
7e1fdc9e
CV
422 wcscpy (domname, domain || !servername
423 ? domain_name : servername);
375a780e 424 wcscat (domname, L"\\");
a1e19903 425 wcscat (domname, buffer[i].usri3_name);
375a780e 426 sid_length = MAX_SID_LEN;
a1e19903
CV
427 domname_len = sizeof (domname);
428 if (!LookupAccountNameW (servername, domname, psid,
429 &sid_length, domain_name,
430 &domname_len, &acc_type))
37c49e19 431 {
7041c7ab 432 print_win_error(GetLastError ());
375a780e 433 fprintf(stderr, " (%ls)\n", domname);
37c49e19
CF
434 continue;
435 }
436 }
6510edf4
CF
437 if (!print_current)
438 /* fall through */;
439 else if (EqualSid (curr_user.psid, psid))
9258eca9 440 got_curr_user = TRUE;
6510edf4 441
61522196
CV
442 printf ("%ls%s%ls:unused:%" PRIu32 ":%" PRIu32
443 ":%ls%sU-%ls\\%ls,%s:%s:/bin/bash\n",
a1e19903
CV
444 with_dom ? domain_name : L"",
445 with_dom ? sep : "",
6510edf4 446 buffer[i].usri3_name,
61522196
CV
447 (unsigned int) (id_offset + uid),
448 (unsigned int) (id_offset + gid),
a1e19903 449 buffer[i].usri3_full_name ?: L"",
6510edf4 450 buffer[i].usri3_full_name
a1e19903
CV
451 && buffer[i].usri3_full_name[0] ? "," : "",
452 domain_name,
453 buffer[i].usri3_name,
454 put_sid (psid),
455 homedir_psx);
1fd5e000
CF
456 }
457
375a780e 458 NetApiBufferFree (buffer);
1fd5e000
CF
459
460 }
0ac91154 461 while (rc == ERROR_MORE_DATA);
1fd5e000
CF
462
463 return 0;
464}
465
6510edf4 466static void
036fb477
CV
467print_special_by_sid (PSID_IDENTIFIER_AUTHORITY auth, BYTE cnt,
468 DWORD sub1, DWORD sub2, DWORD sub3, DWORD sub4,
469 DWORD sub5, DWORD sub6, DWORD sub7, DWORD sub8)
011ec894 470{
0bdab5c8 471 WCHAR user[UNLEN + 1], dom[MAX_DOMAIN_NAME_LEN + 1];
011ec894
CV
472 DWORD len, len2, rid;
473 PSID sid;
0bdab5c8 474 SID_NAME_USE acc_type;
011ec894
CV
475
476 if (AllocateAndInitializeSid (auth, cnt, sub1, sub2, sub3, sub4,
6510edf4 477 sub5, sub6, sub7, sub8, &sid))
011ec894 478 {
0bdab5c8
CV
479 if (LookupAccountSidW (NULL, sid,
480 user, (len = UNLEN + 1, &len),
61522196 481 dom, (len2 = MAX_DOMAIN_NAME_LEN + 1, &len2),
0bdab5c8 482 &acc_type))
011ec894
CV
483 {
484 if (sub8)
485 rid = sub8;
486 else if (sub7)
487 rid = sub7;
488 else if (sub6)
489 rid = sub6;
490 else if (sub5)
491 rid = sub5;
492 else if (sub4)
493 rid = sub4;
494 else if (sub3)
495 rid = sub3;
496 else if (sub2)
497 rid = sub2;
498 else
499 rid = sub1;
61522196
CV
500 printf ("%ls:*:%" PRIu32 ":%" PRIu32 ":,%s::\n",
501 user, (unsigned int) rid,
502 (unsigned int) (rid == 18 ? 544 : rid), /* SYSTEM hack */
a1e19903 503 put_sid (sid));
6510edf4 504 }
011ec894
CV
505 FreeSid (sid);
506 }
507}
508
6510edf4 509static int
a1e19903 510usage (FILE * stream)
1fd5e000 511{
a1e19903 512 fprintf (stream,
92b499ac
CV
513"Usage: %s [OPTIONS]...\n"
514"\n"
a1e19903
CV
515"Print /etc/passwd file to stdout\n"
516"\n"
517"Options:\n"
92b499ac 518"\n"
f9519bcd
CV
519" -l,--local [machine[,offset]]\n"
520" print local user accounts with uid offset offset\n"
521" (from local machine if no machine specified)\n"
522" -L,--Local [machine[,offset]]\n"
523" ditto, but generate username with machine prefix\n"
524" -d,--domain [domain[,offset]]\n"
525" print domain accounts with uid offset offset\n"
526" (from current domain if no domain specified)\n"
527" -D,--Domain [domain[,offset]]\n"
528" ditto, but generate username with domain prefix\n"
a1e19903
CV
529" -c,--current print current user\n"
530" -C,--Current ditto, but generate username with machine or\n"
531" domain prefix\n"
532" -S,--separator char for -L, -D, -C use character char as domain\\user\n"
533" separator in username instead of the default '\\'\n"
534" -o,--id-offset offset change the default offset (10000) added to uids\n"
535" in domain or foreign server accounts.\n"
536" -u,--username username only return information for the specified user\n"
537" one of -l, -L, -d, -D must be specified, too\n"
538" -p,--path-to-home path use specified path instead of user account home dir\n"
539" or /home prefix\n"
6510edf4 540" -U,--unix userlist additionally print UNIX users when using -l or -L\n"
0bdab5c8
CV
541" on a UNIX Samba server\n"
542" userlist is a comma-separated list of usernames\n"
543" or uid ranges (root,-25,50-100).\n"
544" (enumerating large ranges can take a long time!)\n"
a1e19903 545" -s,--no-sids (ignored)\n"
13a20f95 546" -m,--no-mount (ignored)\n"
a1e19903
CV
547" -g,--local-groups (ignored)\n"
548" -h,--help displays this message\n"
92b499ac 549" -V,--version version information and exit\n"
a1e19903
CV
550"\n"
551"Default is to print local accounts on stand-alone machines, domain accounts\n"
92b499ac
CV
552"on domain controllers and domain member machines.\n"
553"\n", program_invocation_short_name);
f1c9046a 554 return 1;
1fd5e000
CF
555}
556
6510edf4 557static struct option longopts[] = {
f1c9046a 558 {"current", no_argument, NULL, 'c'},
a1e19903
CV
559 {"Current", no_argument, NULL, 'C'},
560 {"domain", optional_argument, NULL, 'd'},
561 {"Domain", optional_argument, NULL, 'D'},
9ae2974f 562 {"local-groups", no_argument, NULL, 'g'},
a1e19903
CV
563 {"help", no_argument, NULL, 'h'},
564 {"local", optional_argument, NULL, 'l'},
565 {"Local", optional_argument, NULL, 'L'},
315f8fd3 566 {"no-mount", no_argument, NULL, 'm'},
a1e19903 567 {"id-offset", required_argument, NULL, 'o'},
1d3dc113 568 {"path-to-home", required_argument, NULL, 'p'},
a1e19903
CV
569 {"no-sids", no_argument, NULL, 's'},
570 {"separator", required_argument, NULL, 'S'},
1d3dc113 571 {"username", required_argument, NULL, 'u'},
0bdab5c8 572 {"unix", required_argument, NULL, 'U'},
92b499ac 573 {"version", no_argument, NULL, 'V'},
315f8fd3
CV
574 {0, no_argument, NULL, 0}
575};
576
92b499ac 577static char opts[] = "cCd::D::ghl::L::mo:sS:p:u:U:V";
eccebec0
CV
578
579static void
580print_version ()
581{
92b499ac 582 printf ("mkpasswd (cygwin) %d.%d.%d\n"
1b23b30b
CF
583 "Passwd File Generator\n"
584 "Copyright (C) 1997 - %s Red Hat, Inc.\n"
585 "This is free software; see the source for copying conditions. There is NO\n"
92b499ac 586 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
1b23b30b
CF
587 CYGWIN_VERSION_DLL_MAJOR / 1000,
588 CYGWIN_VERSION_DLL_MAJOR % 1000,
589 CYGWIN_VERSION_DLL_MINOR,
590 strrchr (__DATE__, ' ') + 1);
eccebec0 591}
315f8fd3 592
036fb477
CV
593static void
594print_special_by_name (PCWSTR name, uid_t uid, gid_t gid)
595{
596 DWORD size = 256, dom_size = 256;
597 PSID sid = (PSID) alloca (size);
598 WCHAR dom[dom_size];
599 SID_NAME_USE use;
600
601 PWCHAR name_only = wcschr (name, L'\\');
602 if (name_only)
603 ++name_only;
604
605 if (LookupAccountNameW (NULL, name, sid, &size, dom, &dom_size, &use))
606 printf ("%ls:*:%lu:%lu:U-%ls%s%ls,%s::\n",
607 name_only ?: name,
608 (unsigned long) uid,
609 (unsigned long) gid,
610 name_only ? dom : L"",
611 name_only ? "\\" : "",
612 name_only ?: name,
613 put_sid (sid));
614}
615
a1e19903
CV
616static void
617enum_std_accounts ()
618{
619 /* Generate service starter account entries. */
620 printf ("SYSTEM:*:18:544:,S-1-5-18::\n");
621 printf ("LocalService:*:19:544:U-NT AUTHORITY\\LocalService,S-1-5-19::\n");
622 printf ("NetworkService:*:20:544:U-NT AUTHORITY\\NetworkService,S-1-5-20::\n");
623 /* Get 'administrators' group (has localized name). */
036fb477
CV
624 print_special_by_sid (&sid_nt_auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
625 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0);
626 /* Fetch "TrustedInstaller" account starting with Vista. */
627 print_special_by_name (L"NT SERVICE\\TrustedInstaller", -2, -2);
a1e19903
CV
628}
629
630static PPOLICY_PRIMARY_DOMAIN_INFO p_dom;
631
632static BOOL
633fetch_primary_domain ()
634{
635 NTSTATUS status;
636 LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 };
637 LSA_HANDLE lsa;
638
639 if (!p_dom)
640 {
641 status = LsaOpenPolicy (NULL, &oa, POLICY_VIEW_LOCAL_INFORMATION, &lsa);
642 if (!NT_SUCCESS (status))
643 return FALSE;
644 status = LsaQueryInformationPolicy (lsa, PolicyPrimaryDomainInformation,
6510edf4 645 (PVOID *) ((void *) &p_dom));
a1e19903
CV
646 LsaClose (lsa);
647 if (!NT_SUCCESS (status))
648 return FALSE;
649 }
650 return !!p_dom->Sid;
651}
652
eedc36cb 653int
1fd5e000
CF
654main (int argc, char **argv)
655{
f9519bcd
CV
656 int print_domlist = 0;
657 domlist_t domlist[32];
658 char *opt, *p, *ep;
a1e19903 659 int print_current = 0;
0bdab5c8 660 char *print_unix = NULL;
a1e19903 661 const char *sep_char = "\\";
f9519bcd
CV
662 DWORD id_offset = 10000, off;
663 int c, i;
1d3dc113 664 char *disp_username = NULL;
a1e19903
CV
665 char passed_home_path[PATH_MAX];
666 BOOL in_domain;
01dd3162 667 int optional_args = 0;
1fd5e000 668
9ae2974f 669 passed_home_path[0] = '\0';
dfe56933
CF
670 if (!isatty (1))
671 setmode (1, O_BINARY);
9ae2974f 672
73535010
CV
673 /* Use locale from environment. If not set or set to "C", use UTF-8. */
674 setlocale (LC_CTYPE, "");
675 if (!strcmp (setlocale (LC_CTYPE, NULL), "C"))
676 setlocale (LC_CTYPE, "en_US.UTF-8");
a1e19903 677 in_domain = fetch_primary_domain ();
6510edf4
CF
678 fetch_current_user_sid ();
679
a1e19903 680 if (argc == 1)
011ec894 681 {
a1e19903
CV
682 enum_std_accounts ();
683 if (in_domain)
13a20f95
CV
684 enum_users (TRUE, NULL, sep_char, passed_home_path, 10000,
685 disp_username, 0);
a1e19903 686 else
13a20f95 687 enum_users (FALSE, NULL, sep_char, passed_home_path, 0,
6510edf4 688 disp_username, 0);
a1e19903
CV
689 return 0;
690 }
691
01dd3162 692 unsetenv ("POSIXLY_CORRECT"); /* To get optional arg processing right. */
a1e19903
CV
693 while ((c = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
694 switch (c)
695 {
f9519bcd
CV
696 case 'd':
697 case 'D':
a1e19903
CV
698 case 'l':
699 case 'L':
f9519bcd 700 if (print_domlist >= 32)
f1c9046a 701 {
f9519bcd 702 fprintf (stderr, "%s: Can not enumerate from more than 32 "
92b499ac
CV
703 "domains and machines.\n",
704 program_invocation_short_name);
f1c9046a
CV
705 return 1;
706 }
f36c78a4 707 domlist[print_domlist].domain = (c == 'd' || c == 'D');
a1e19903
CV
708 opt = optarg ?:
709 argv[optind] && argv[optind][0] != '-' ? argv[optind] : NULL;
096df177 710 if (argv[optind] && opt == argv[optind])
01dd3162 711 ++optional_args;
f9519bcd 712 for (i = 0; i < print_domlist; ++i)
f36c78a4
CV
713 if (domlist[i].domain == domlist[print_domlist].domain
714 && ((!domlist[i].str && !opt)
715 || (domlist[i].str && opt
716 && (off = strlen (domlist[i].str))
717 && !strncmp (domlist[i].str, opt, off)
718 && (!opt[off] || opt[off] == ','))))
719 {
720 fprintf (stderr, "%s: Duplicate %s '%s'. Skipping...\n",
92b499ac
CV
721 program_invocation_short_name,
722 domlist[i].domain ? "domain" : "machine",
f36c78a4
CV
723 domlist[i].str);
724 goto skip;
725 }
f9519bcd 726 domlist[print_domlist].str = opt;
61522196 727 domlist[print_domlist].id_offset = UINT32_MAX;
f9519bcd 728 if (opt && (p = strchr (opt, ',')))
a1e19903 729 {
f9519bcd 730 if (p == opt
05e6f7b2 731 || !isdigit ((unsigned char) p[1])
6510edf4 732 || (domlist[print_domlist].id_offset = strtol (p + 1, &ep, 10)
f9519bcd
CV
733 , *ep))
734 {
735 fprintf (stderr, "%s: Malformed domain,offset string '%s'. "
92b499ac 736 "Skipping...\n", program_invocation_short_name, opt);
6510edf4 737 break;
f9519bcd
CV
738 }
739 *p = '\0';
a1e19903 740 }
f9519bcd
CV
741 domlist[print_domlist++].with_dom = (c == 'D' || c == 'L');
742skip:
a1e19903
CV
743 break;
744 case 'S':
745 sep_char = optarg;
746 if (strlen (sep_char) > 1)
747 {
748 fprintf (stderr, "%s: Only one character allowed as domain\\user "
92b499ac
CV
749 "separator character.\n",
750 program_invocation_short_name);
a1e19903
CV
751 return 1;
752 }
753 if (*sep_char == ':')
754 {
755 fprintf (stderr, "%s: Colon not allowed as domain\\user separator "
92b499ac 756 "character.\n", program_invocation_short_name);
a1e19903
CV
757 return 1;
758 }
6510edf4 759 break;
0bdab5c8 760 case 'U':
6510edf4 761 print_unix = optarg;
0bdab5c8 762 break;
a1e19903
CV
763 case 'c':
764 sep_char = NULL;
765 /*FALLTHRU*/
766 case 'C':
767 print_current = 1;
768 break;
769 case 'o':
f9519bcd
CV
770 id_offset = strtoul (optarg, &ep, 10);
771 if (*ep)
772 {
773 fprintf (stderr, "%s: Malformed offset '%s'. "
92b499ac 774 "Skipping...\n", program_invocation_short_name, optarg);
f9519bcd
CV
775 return 1;
776 }
a1e19903 777 break;
a1e19903
CV
778 case 'p':
779 if (optarg[0] != '/')
780 {
781 fprintf (stderr, "%s: '%s' is not a fully qualified path.\n",
92b499ac 782 program_invocation_short_name, optarg);
f1c9046a
CV
783 return 1;
784 }
a1e19903
CV
785 strcpy (passed_home_path, optarg);
786 if (optarg[strlen (optarg)-1] != '/')
787 strcat (passed_home_path, "/");
788 break;
789 case 'u':
790 disp_username = optarg;
791 break;
792 case 'h':
793 usage (stdout);
794 return 0;
92b499ac 795 case 'V':
a1e19903
CV
796 print_version ();
797 return 0;
13a20f95
CV
798 case 'g': /* deprecated */
799 case 's': /* deprecated */
800 case 'm': /* deprecated */
801 break;
a1e19903 802 default:
92b499ac
CV
803 fprintf (stderr, "Try `%s --help' for more information.\n",
804 program_invocation_short_name);
a1e19903
CV
805 return 1;
806 }
1fd5e000 807
01dd3162 808 optind += optional_args;
6510edf4
CF
809 if (argv[optind])
810 {
811 fprintf (stderr,
812 "mkpasswd: non-option command line argument `%s' is not allowed.\n"
813 "Try `mkpasswd --help' for more information.\n", argv[optind]);
814 exit (1);
815 }
9258eca9 816
f9519bcd
CV
817 off = id_offset;
818 for (i = 0; i < print_domlist; ++i)
1d3dc113 819 {
f9519bcd 820 DWORD my_off = (domlist[i].domain || domlist[i].str)
61522196 821 ? domlist[i].id_offset != UINT_MAX
f9519bcd
CV
822 ? domlist[i].id_offset : off : 0;
823 if (!domlist[i].domain && domlist[i].str && print_unix)
824 enum_unix_users (domlist + i, sep_char, my_off, print_unix);
328b090f 825 if (!my_off && !disp_username)
6510edf4 826 enum_std_accounts ();
13a20f95
CV
827 enum_users (domlist[i].domain, domlist + i, sep_char, passed_home_path,
828 my_off, disp_username, print_current);
f9519bcd 829 if (my_off)
6510edf4 830 off += id_offset;
1d3dc113 831 }
1fd5e000 832
9258eca9 833 if (print_current && !got_curr_user)
13a20f95 834 current_user (sep_char, passed_home_path, off, disp_username);
f1c9046a 835
1fd5e000
CF
836 return 0;
837}
This page took 0.363297 seconds and 5 git commands to generate.