]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* passwd.c: Changing passwords and managing account information |
2 | ||
61522196 CV |
3 | Copyright 1999, 2000, 2001, 2002, 2003, 2005, 2008, 2009, 2011, 2012, |
4 | 2013 Red Hat, Inc. | |
1fd5e000 CF |
5 | |
6 | Written by Corinna Vinschen <corinna.vinschen@cityweb.de> | |
7 | ||
8 | This file is part of Cygwin. | |
9 | ||
10 | This software is a copyrighted work licensed under the terms of the | |
11 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
12 | details. */ | |
13 | ||
94a23f48 CV |
14 | #include <windows.h> |
15 | #include <wininet.h> | |
16 | #include <lmaccess.h> | |
17 | #include <lmerr.h> | |
18 | #include <lmcons.h> | |
19 | #include <lmapibuf.h> | |
20 | ||
1fd5e000 CF |
21 | #include <stdio.h> |
22 | #include <stdlib.h> | |
23 | #include <string.h> | |
24 | #include <unistd.h> | |
61522196 | 25 | #include <inttypes.h> |
1fd5e000 CF |
26 | #include <getopt.h> |
27 | #include <pwd.h> | |
94a23f48 | 28 | #include <sys/cygwin.h> |
92b499ac | 29 | #include <cygwin/version.h> |
1fd5e000 CF |
30 | #include <sys/types.h> |
31 | #include <time.h> | |
d8655020 | 32 | #include <errno.h> |
35aeac58 CV |
33 | #include <locale.h> |
34 | #include <wchar.h> | |
1fd5e000 | 35 | |
1fd5e000 CF |
36 | #define USER_PRIV_ADMIN 2 |
37 | ||
f59faec4 CV |
38 | static char *prog_name; |
39 | ||
40 | static struct option longopts[] = | |
41 | { | |
1f4e5e15 CV |
42 | {"cannot-change", no_argument, NULL, 'c'}, |
43 | {"can-change", no_argument, NULL, 'C'}, | |
4fa0a398 | 44 | {"logonserver", required_argument, NULL, 'd'}, |
1f4e5e15 CV |
45 | {"never-expires", no_argument, NULL, 'e'}, |
46 | {"expires", no_argument, NULL, 'E'}, | |
f59faec4 CV |
47 | {"help", no_argument, NULL, 'h' }, |
48 | {"inactive", required_argument, NULL, 'i'}, | |
49 | {"lock", no_argument, NULL, 'l'}, | |
50 | {"minage", required_argument, NULL, 'n'}, | |
1f4e5e15 CV |
51 | {"pwd-not-required", no_argument, NULL, 'p'}, |
52 | {"pwd-required", no_argument, NULL, 'P'}, | |
f59faec4 | 53 | {"unlock", no_argument, NULL, 'u'}, |
92b499ac | 54 | {"version", no_argument, NULL, 'V'}, |
f59faec4 CV |
55 | {"maxage", required_argument, NULL, 'x'}, |
56 | {"length", required_argument, NULL, 'L'}, | |
57 | {"status", no_argument, NULL, 'S'}, | |
d8655020 | 58 | { "reg-store-pwd", no_argument, NULL, 'R'}, |
f59faec4 CV |
59 | {NULL, 0, NULL, 0} |
60 | }; | |
61 | ||
a442c9cd | 62 | static char opts[] = "cCd:eEhi:ln:pPuvVx:L:SR"; |
1fd5e000 CF |
63 | |
64 | int | |
65 | eprint (int with_name, const char *fmt, ...) | |
66 | { | |
67 | va_list ap; | |
68 | ||
69 | if (with_name) | |
f59faec4 | 70 | fprintf(stderr, "%s: ", prog_name); |
1fd5e000 CF |
71 | va_start (ap, fmt); |
72 | vfprintf (stderr, fmt, ap); | |
73 | va_end (ap); | |
74 | fprintf(stderr, "\n"); | |
75 | return 1; | |
76 | } | |
77 | ||
78 | int | |
79 | EvalRet (int ret, const char *user) | |
80 | { | |
81 | switch (ret) | |
82 | { | |
83 | case NERR_Success: | |
84 | return 0; | |
85 | ||
86 | case ERROR_ACCESS_DENIED: | |
87 | if (! user) | |
1b23b30b | 88 | eprint (0, "You may not change password expiry information."); |
1fd5e000 | 89 | else |
1b23b30b | 90 | eprint (0, "You may not change the password for %s.", user); |
1fd5e000 CF |
91 | break; |
92 | ||
93 | eprint (0, "Bad password: Invalid."); | |
94 | break; | |
95 | ||
96 | case NERR_PasswordTooShort: | |
97 | eprint (0, "Bad password: Too short."); | |
98 | break; | |
99 | ||
100 | case NERR_UserNotFound: | |
101 | eprint (1, "unknown user %s", user); | |
102 | break; | |
103 | ||
104 | case ERROR_INVALID_PASSWORD: | |
105 | case NERR_BadPassword: | |
106 | eprint (0, "Incorrect password for %s.", user); | |
107 | eprint (0, "The password for %s is unchanged.", user); | |
108 | break; | |
109 | ||
110 | default: | |
111 | eprint (1, "unrecoverable error %d", ret); | |
112 | break; | |
113 | } | |
114 | return 1; | |
115 | } | |
116 | ||
117 | PUSER_INFO_3 | |
4fa0a398 | 118 | GetPW (char *user, int print_win_name, LPCWSTR server) |
1fd5e000 | 119 | { |
94a23f48 | 120 | char usr_buf[UNLEN + 1]; |
35aeac58 | 121 | WCHAR name[UNLEN + 1]; |
1fd5e000 CF |
122 | DWORD ret; |
123 | PUSER_INFO_3 ui; | |
94a23f48 CV |
124 | struct passwd *pw; |
125 | char *domain = (char *) alloca (INTERNET_MAX_HOST_NAME_LENGTH + 1); | |
1b23b30b | 126 | |
94a23f48 CV |
127 | /* Try getting a Win32 username in case the user edited /etc/passwd */ |
128 | if ((pw = getpwnam (user))) | |
129 | { | |
130 | cygwin_internal (CW_EXTRACT_DOMAIN_AND_USER, pw, domain, usr_buf); | |
131 | if (strcasecmp (pw->pw_name, usr_buf)) | |
132 | { | |
133 | /* Hack to avoid problem with LookupAccountSid after impersonation */ | |
134 | if (strcasecmp (usr_buf, "SYSTEM")) | |
135 | { | |
136 | user = usr_buf; | |
137 | if (print_win_name) | |
138 | printf ("Windows username : %s\n", user); | |
139 | } | |
140 | } | |
141 | } | |
35aeac58 | 142 | mbstowcs (name, user, UNLEN + 1); |
4fa0a398 | 143 | ret = NetUserGetInfo (server, name, 3, (void *) &ui); |
1fd5e000 CF |
144 | return EvalRet (ret, user) ? NULL : ui; |
145 | } | |
146 | ||
147 | int | |
4fa0a398 CV |
148 | ChangePW (const char *user, const char *oldpwd, const char *pwd, int justcheck, |
149 | LPCWSTR server) | |
1fd5e000 | 150 | { |
35aeac58 | 151 | WCHAR name[UNLEN + 1], oldpass[512], pass[512]; |
1fd5e000 CF |
152 | DWORD ret; |
153 | ||
35aeac58 CV |
154 | mbstowcs (name, user, UNLEN + 1); |
155 | mbstowcs (pass, pwd, 512); | |
1fd5e000 CF |
156 | if (! oldpwd) |
157 | { | |
158 | USER_INFO_1003 ui; | |
159 | ||
160 | ui.usri1003_password = pass; | |
4fa0a398 | 161 | ret = NetUserSetInfo (server, name, 1003, (LPBYTE) &ui, NULL); |
1fd5e000 CF |
162 | } |
163 | else | |
164 | { | |
35aeac58 | 165 | mbstowcs (oldpass, oldpwd, 512); |
4fa0a398 | 166 | ret = NetUserChangePassword (server, name, oldpass, pass); |
1fd5e000 | 167 | } |
97832962 CV |
168 | if (justcheck && ret != ERROR_INVALID_PASSWORD) |
169 | return 0; | |
170 | if (! EvalRet (ret, user) && ! justcheck) | |
1fd5e000 CF |
171 | { |
172 | eprint (0, "Password changed."); | |
173 | } | |
174 | return ret; | |
175 | } | |
176 | ||
177 | void | |
4fa0a398 | 178 | PrintPW (PUSER_INFO_3 ui, LPCWSTR server) |
1fd5e000 CF |
179 | { |
180 | time_t t = time (NULL) - ui->usri3_password_age; | |
181 | int ret; | |
182 | PUSER_MODALS_INFO_0 mi; | |
183 | ||
1f4e5e15 | 184 | printf ("Account disabled : %s", |
1b23b30b | 185 | (ui->usri3_flags & UF_ACCOUNTDISABLE) ? "yes\n" : "no\n"); |
02bd05e3 | 186 | printf ("Password not required : %s", |
1b23b30b | 187 | (ui->usri3_flags & UF_PASSWD_NOTREQD) ? "yes\n" : "no\n"); |
1f4e5e15 | 188 | printf ("User can't change password : %s", |
1b23b30b | 189 | (ui->usri3_flags & UF_PASSWD_CANT_CHANGE) ? "yes\n" : "no\n"); |
1f4e5e15 | 190 | printf ("Password never expires : %s", |
1b23b30b | 191 | (ui->usri3_flags & UF_DONT_EXPIRE_PASSWD) ? "yes\n" : "no\n"); |
1f4e5e15 CV |
192 | printf ("Password expired : %s", |
193 | (ui->usri3_password_expired) ? "yes\n" : "no\n"); | |
194 | printf ("Latest password change : %s", ctime(&t)); | |
4fa0a398 | 195 | ret = NetUserModalsGet (server, 0, (void *) &mi); |
1fd5e000 CF |
196 | if (! ret) |
197 | { | |
1f4e5e15 | 198 | if (mi->usrmod0_max_passwd_age == TIMEQ_FOREVER) |
1b23b30b | 199 | mi->usrmod0_max_passwd_age = 0; |
1f4e5e15 | 200 | if (mi->usrmod0_min_passwd_age == TIMEQ_FOREVER) |
1b23b30b | 201 | mi->usrmod0_min_passwd_age = 0; |
1f4e5e15 | 202 | if (mi->usrmod0_force_logoff == TIMEQ_FOREVER) |
1b23b30b | 203 | mi->usrmod0_force_logoff = 0; |
1fd5e000 | 204 | if (ui->usri3_priv == USER_PRIV_ADMIN) |
1b23b30b | 205 | mi->usrmod0_min_passwd_len = 0; |
1f4e5e15 | 206 | printf ("\nSystem password settings:\n"); |
61522196 CV |
207 | printf ("Max. password age %" PRIu32 " days\n", |
208 | (unsigned int) (mi->usrmod0_max_passwd_age / ONE_DAY)); | |
209 | printf ("Min. password age %" PRIu32 " days\n", | |
210 | (unsigned int) (mi->usrmod0_min_passwd_age / ONE_DAY)); | |
211 | printf ("Force logout after %" PRIu32 " days\n", | |
212 | (unsigned int) (mi->usrmod0_force_logoff / ONE_DAY)); | |
213 | printf ("Min. password length: %" PRIu32 "\n", | |
214 | (unsigned int) mi->usrmod0_min_passwd_len); | |
1fd5e000 CF |
215 | } |
216 | } | |
217 | ||
218 | int | |
4fa0a398 | 219 | SetModals (int xarg, int narg, int iarg, int Larg, LPCWSTR server) |
1fd5e000 CF |
220 | { |
221 | int ret; | |
222 | PUSER_MODALS_INFO_0 mi; | |
223 | ||
4fa0a398 | 224 | ret = NetUserModalsGet (server, 0, (void *) &mi); |
1fd5e000 CF |
225 | if (! ret) |
226 | { | |
227 | if (xarg == 0) | |
228 | mi->usrmod0_max_passwd_age = TIMEQ_FOREVER; | |
229 | else if (xarg > 0) | |
230 | mi->usrmod0_max_passwd_age = xarg * ONE_DAY; | |
231 | ||
232 | if (narg == 0) | |
233 | { | |
234 | mi->usrmod0_min_passwd_age = TIMEQ_FOREVER; | |
235 | mi->usrmod0_password_hist_len = 0; | |
236 | } | |
237 | else if (narg > 0) | |
238 | mi->usrmod0_min_passwd_age = narg * ONE_DAY; | |
239 | ||
240 | if (iarg == 0) | |
241 | mi->usrmod0_force_logoff = TIMEQ_FOREVER; | |
242 | else if (iarg > 0) | |
243 | mi->usrmod0_force_logoff = iarg * ONE_DAY; | |
244 | ||
245 | if (Larg >= 0) | |
246 | mi->usrmod0_min_passwd_len = Larg; | |
247 | ||
4fa0a398 | 248 | ret = NetUserModalsSet (server, 0, (LPBYTE) mi, NULL); |
1fd5e000 CF |
249 | NetApiBufferFree (mi); |
250 | } | |
251 | return EvalRet (ret, NULL); | |
252 | } | |
253 | ||
1f4e5e15 | 254 | static void usage (FILE * stream, int status) __attribute__ ((noreturn)); |
f59faec4 CV |
255 | static void |
256 | usage (FILE * stream, int status) | |
1fd5e000 | 257 | { |
f59faec4 | 258 | fprintf (stream, "" |
1f4e5e15 | 259 | "Usage: %s [OPTION] [USER]\n" |
92b499ac | 260 | "\n" |
1f4e5e15 | 261 | "Change USER's password or password attributes.\n" |
f59faec4 CV |
262 | "\n" |
263 | "User operations:\n" | |
1f4e5e15 CV |
264 | " -l, --lock lock USER's account.\n" |
265 | " -u, --unlock unlock USER's account.\n" | |
266 | " -c, --cannot-change USER can't change password.\n" | |
267 | " -C, --can-change USER can change password.\n" | |
268 | " -e, --never-expires USER's password never expires.\n" | |
269 | " -E, --expires USER's password expires according to system's\n" | |
270 | " password aging rule.\n" | |
271 | " -p, --pwd-not-required no password required for USER.\n" | |
272 | " -P, --pwd-required password is required for USER.\n" | |
d8655020 CV |
273 | " -R, --reg-store-pwd enter password to store it in the registry for\n" |
274 | " later usage by services to be able to switch\n" | |
275 | " to this user context with network credentials.\n" | |
f59faec4 CV |
276 | "\n" |
277 | "System operations:\n" | |
1f4e5e15 CV |
278 | " -i, --inactive NUM set NUM of days before inactive accounts are disabled\n" |
279 | " (inactive accounts are those with expired passwords).\n" | |
280 | " -n, --minage DAYS set system minimum password age to DAYS days.\n" | |
281 | " -x, --maxage DAYS set system maximum password age to DAYS days.\n" | |
282 | " -L, --length LEN set system minimum password length to LEN.\n" | |
f59faec4 CV |
283 | "\n" |
284 | "Other options:\n" | |
4fa0a398 | 285 | " -d, --logonserver SERVER connect to SERVER (e.g. domain controller).\n" |
6199f417 CV |
286 | " Default server is the local system, unless\n" |
287 | " changing the current user, in which case the\n" | |
288 | " default is the content of $LOGONSERVER.\n" | |
1f4e5e15 CV |
289 | " -S, --status display password status for USER (locked, expired,\n" |
290 | " etc.) plus global system password settings.\n" | |
291 | " -h, --help output usage information and exit.\n" | |
92b499ac | 292 | " -V, --version output version information and exit.\n" |
1f4e5e15 CV |
293 | "\n" |
294 | "If no option is given, change USER's password. If no user name is given,\n" | |
295 | "operate on current user. System operations must not be mixed with user\n" | |
d8655020 CV |
296 | "operations. Don't specify a USER when triggering a system operation.\n" |
297 | "\n" | |
298 | "Don't specify a user or any other option together with the -R option.\n" | |
7ffaa17c CV |
299 | "Non-Admin users can only store their password if cygserver is running\n" |
300 | "as service under the SYSTEM account.\n" | |
d8655020 CV |
301 | "Note that storing even obfuscated passwords in the registry is not overly\n" |
302 | "secure. Use this feature only if the machine is adequately locked down.\n" | |
303 | "Don't use this feature if you don't need network access within a remote\n" | |
304 | "session. You can delete your stored password by using `passwd -R' and\n" | |
92b499ac | 305 | "specifying an empty password.\n\n", prog_name); |
f59faec4 CV |
306 | exit (status); |
307 | } | |
308 | ||
0e0f5748 CV |
309 | static int |
310 | caller_is_admin () | |
311 | { | |
312 | static int is_admin = -1; | |
313 | HANDLE token; | |
314 | DWORD size; | |
315 | PTOKEN_GROUPS grps; | |
316 | SID_IDENTIFIER_AUTHORITY nt_auth = {SECURITY_NT_AUTHORITY}; | |
1b23b30b | 317 | PSID admin_grp; |
0e0f5748 CV |
318 | DWORD i; |
319 | ||
320 | if (is_admin == -1) | |
321 | { | |
322 | is_admin = 0; | |
323 | if (OpenProcessToken (GetCurrentProcess (), TOKEN_READ, &token)) | |
324 | { | |
325 | GetTokenInformation (token, TokenGroups, NULL, 0, &size); | |
326 | grps = (PTOKEN_GROUPS) alloca (size); | |
327 | if (!GetTokenInformation(token, TokenGroups, grps, size, &size) | |
328 | || !AllocateAndInitializeSid (&nt_auth, 2, | |
329 | SECURITY_BUILTIN_DOMAIN_RID, | |
330 | DOMAIN_ALIAS_RID_ADMINS, | |
331 | 0, 0, 0, 0, 0, 0, &admin_grp)) | |
332 | is_admin = 0; | |
333 | else | |
334 | { | |
335 | for (i = 0; i < grps->GroupCount; ++i) | |
336 | if (EqualSid (admin_grp, grps->Groups[i].Sid) | |
337 | && (grps->Groups[i].Attributes | |
338 | & (SE_GROUP_ENABLED | SE_GROUP_USE_FOR_DENY_ONLY)) | |
339 | == SE_GROUP_ENABLED) | |
340 | { | |
341 | is_admin = 1; | |
342 | break; | |
343 | } | |
344 | FreeSid (admin_grp); | |
345 | } | |
346 | CloseHandle (token); | |
347 | } | |
348 | } | |
349 | return is_admin; | |
350 | } | |
351 | ||
f59faec4 CV |
352 | static void |
353 | print_version () | |
354 | { | |
92b499ac | 355 | printf ("passwd (cygwin) %d.%d.%d\n" |
1b23b30b CF |
356 | "Password Utility\n" |
357 | "Copyright (C) 1999 - %s Red Hat, Inc.\n" | |
358 | "This is free software; see the source for copying conditions. There is NO\n" | |
92b499ac | 359 | "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", |
1b23b30b CF |
360 | CYGWIN_VERSION_DLL_MAJOR / 1000, |
361 | CYGWIN_VERSION_DLL_MAJOR % 1000, | |
362 | CYGWIN_VERSION_DLL_MINOR, | |
363 | strrchr (__DATE__, ' ') + 1); | |
1fd5e000 CF |
364 | } |
365 | ||
366 | int | |
367 | main (int argc, char **argv) | |
368 | { | |
92b499ac | 369 | char *logonserver; |
d8655020 | 370 | char user[UNLEN + 1], oldpwd[_PASSWORD_LEN + 1], newpwd[_PASSWORD_LEN + 1]; |
1fd5e000 CF |
371 | int ret = 0; |
372 | int cnt = 0; | |
35aeac58 | 373 | int opt; |
1fd5e000 CF |
374 | int Larg = -1; |
375 | int xarg = -1; | |
376 | int narg = -1; | |
377 | int iarg = -1; | |
378 | int lopt = 0; | |
379 | int uopt = 0; | |
1f4e5e15 CV |
380 | int copt = 0; |
381 | int Copt = 0; | |
382 | int eopt = 0; | |
383 | int Eopt = 0; | |
384 | int popt = 0; | |
385 | int Popt = 0; | |
1fd5e000 | 386 | int Sopt = 0; |
d8655020 | 387 | int Ropt = 0; |
0e0f5748 CV |
388 | PUSER_INFO_3 ui; |
389 | int myself = 0; | |
4fa0a398 | 390 | LPWSTR server = NULL; |
1fd5e000 | 391 | |
92b499ac | 392 | prog_name = program_invocation_short_name; |
1fd5e000 | 393 | |
73535010 CV |
394 | /* Use locale from environment. If not set or set to "C", use UTF-8. */ |
395 | setlocale (LC_CTYPE, ""); | |
396 | if (!strcmp (setlocale (LC_CTYPE, NULL), "C")) | |
397 | setlocale (LC_CTYPE, "en_US.UTF-8"); | |
f59faec4 | 398 | while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF) |
1fd5e000 CF |
399 | switch (opt) |
400 | { | |
f59faec4 CV |
401 | case 'h': |
402 | usage (stdout, 0); | |
1b23b30b | 403 | break; |
f59faec4 CV |
404 | |
405 | case 'i': | |
d8655020 | 406 | if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt || Ropt) |
1f4e5e15 | 407 | usage (stderr, 1); |
f59faec4 CV |
408 | if ((iarg = atoi (optarg)) < 0 || iarg > 999) |
409 | return eprint (1, "Force logout time must be between 0 and 999."); | |
1b23b30b | 410 | break; |
f59faec4 CV |
411 | |
412 | case 'l': | |
d8655020 | 413 | if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || uopt || Sopt || Ropt) |
f59faec4 CV |
414 | usage (stderr, 1); |
415 | lopt = 1; | |
1b23b30b | 416 | break; |
1fd5e000 CF |
417 | |
418 | case 'n': | |
d8655020 | 419 | if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt || Ropt) |
1f4e5e15 | 420 | usage (stderr, 1); |
1fd5e000 CF |
421 | if ((narg = atoi (optarg)) < 0 || narg > 999) |
422 | return eprint (1, "Minimum password age must be between 0 and 999."); | |
423 | if (xarg >= 0 && narg > xarg) | |
424 | return eprint (1, "Minimum password age must be less than " | |
1b23b30b CF |
425 | "maximum password age."); |
426 | break; | |
1fd5e000 | 427 | |
f59faec4 | 428 | case 'u': |
d8655020 | 429 | if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || lopt || Sopt || Ropt) |
f59faec4 CV |
430 | usage (stderr, 1); |
431 | uopt = 1; | |
1b23b30b | 432 | break; |
1fd5e000 | 433 | |
1f4e5e15 | 434 | case 'c': |
d8655020 | 435 | if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt) |
1f4e5e15 CV |
436 | usage (stderr, 1); |
437 | copt = 1; | |
1b23b30b | 438 | break; |
1f4e5e15 CV |
439 | |
440 | case 'C': | |
d8655020 | 441 | if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt) |
1f4e5e15 CV |
442 | usage (stderr, 1); |
443 | Copt = 1; | |
1b23b30b | 444 | break; |
1f4e5e15 | 445 | |
4fa0a398 | 446 | case 'd': |
1b23b30b | 447 | { |
d8655020 CV |
448 | if (Ropt) |
449 | usage (stderr, 1); | |
4fa0a398 CV |
450 | char *tmpbuf = alloca (strlen (optarg) + 3); |
451 | tmpbuf[0] = '\0'; | |
452 | if (*optarg != '\\') | |
453 | strcpy (tmpbuf, "\\\\"); | |
454 | strcat (tmpbuf, optarg); | |
35aeac58 CV |
455 | size_t len = mbstowcs (NULL, tmpbuf, 0); |
456 | if (len > 0 && len != (size_t) -1) | |
457 | mbstowcs (server = alloca ((len + 1) * sizeof (wchar_t)), | |
458 | tmpbuf, len + 1); | |
4fa0a398 CV |
459 | } |
460 | break; | |
461 | ||
1f4e5e15 | 462 | case 'e': |
d8655020 | 463 | if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt) |
1f4e5e15 CV |
464 | usage (stderr, 1); |
465 | eopt = 1; | |
1b23b30b | 466 | break; |
1f4e5e15 CV |
467 | |
468 | case 'E': | |
d8655020 | 469 | if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt) |
1f4e5e15 CV |
470 | usage (stderr, 1); |
471 | Eopt = 1; | |
1b23b30b | 472 | break; |
1f4e5e15 CV |
473 | |
474 | case 'p': | |
d8655020 | 475 | if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt) |
1f4e5e15 CV |
476 | usage (stderr, 1); |
477 | popt = 1; | |
1b23b30b | 478 | break; |
1f4e5e15 CV |
479 | |
480 | case 'P': | |
d8655020 | 481 | if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt) |
1f4e5e15 CV |
482 | usage (stderr, 1); |
483 | Popt = 1; | |
1b23b30b | 484 | break; |
1f4e5e15 | 485 | |
92b499ac | 486 | case 'V': |
a442c9cd CV |
487 | case 'v': /* Keep this option for historrical reasons, |
488 | but don't advertize it. */ | |
f59faec4 | 489 | print_version (); |
1b23b30b CF |
490 | exit (0); |
491 | break; | |
1fd5e000 | 492 | |
f59faec4 | 493 | case 'x': |
d8655020 | 494 | if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt || Ropt) |
1f4e5e15 | 495 | usage (stderr, 1); |
f59faec4 CV |
496 | if ((xarg = atoi (optarg)) < 0 || xarg > 999) |
497 | return eprint (1, "Maximum password age must be between 0 and 999."); | |
498 | if (narg >= 0 && xarg < narg) | |
499 | return eprint (1, "Maximum password age must be greater than " | |
1b23b30b CF |
500 | "minimum password age."); |
501 | break; | |
1fd5e000 | 502 | |
f59faec4 | 503 | case 'L': |
d8655020 | 504 | if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt || Ropt) |
1f4e5e15 | 505 | usage (stderr, 1); |
f59faec4 CV |
506 | if ((Larg = atoi (optarg)) < 0 || Larg > LM20_PWLEN) |
507 | return eprint (1, "Minimum password length must be between " | |
1b23b30b CF |
508 | "0 and %d.", LM20_PWLEN); |
509 | break; | |
1fd5e000 CF |
510 | |
511 | case 'S': | |
1f4e5e15 | 512 | if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || lopt || uopt |
d8655020 | 513 | || copt || Copt || eopt || Eopt || popt || Popt || Ropt) |
f59faec4 | 514 | usage (stderr, 1); |
1fd5e000 | 515 | Sopt = 1; |
1b23b30b | 516 | break; |
1fd5e000 | 517 | |
d8655020 CV |
518 | case 'R': |
519 | if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || lopt || uopt | |
520 | || copt || Copt || eopt || Eopt || popt || Popt || Sopt | |
521 | || server) | |
522 | usage (stderr, 1); | |
523 | Ropt = 1; | |
1b23b30b | 524 | break; |
d8655020 | 525 | |
1fd5e000 | 526 | default: |
1b23b30b | 527 | fprintf (stderr, "Try `%s --help' for more information.\n", prog_name); |
92b499ac | 528 | return 1; |
1fd5e000 | 529 | } |
4fa0a398 | 530 | |
d8655020 CV |
531 | if (Ropt) |
532 | { | |
ff73fd1e | 533 | const char *username = NULL; |
d8655020 | 534 | if (optind < argc) |
ff73fd1e CV |
535 | { |
536 | username = argv[optind++]; | |
537 | if (!strcmp (username, getlogin ())) | |
538 | username = NULL; | |
539 | else if (!caller_is_admin ()) | |
540 | return eprint (0, "You may not change the password for %s.", user); | |
541 | ||
542 | if (optind < argc) | |
543 | usage (stderr, 1); | |
544 | } | |
545 | char *text1 = (char *) alloca ((username ? strlen (username) + 2 : 4) | |
546 | + sizeof ("Enter current password: ")); | |
547 | char *text2 = (char *) alloca ((username ? strlen (username) + 2 : 4) | |
548 | + sizeof ("Re-enter current password: ")); | |
549 | sprintf (text1, "Enter %s%s current password: ", | |
550 | username ?: "your", username ? "'s" : ""); | |
551 | sprintf (text2, "Re-enter %s%s current password: ", | |
552 | username ?: "your", username ? "'s" : ""); | |
d8655020 CV |
553 | printf ( |
554 | "This functionality stores a password in the registry for usage by services\n" | |
555 | "which need to change the user context and require network access. Typical\n" | |
556 | "applications are interactive remote logons using sshd, cron task, etc.\n" | |
557 | "This password will always tried first when any privileged application is\n" | |
558 | "about to switch the user context.\n\n" | |
559 | "Note that storing even obfuscated passwords in the registry is not overly\n" | |
560 | "secure. Use this feature only if the machine is adequately locked down.\n" | |
561 | "Don't use this feature if you don't need network access within a remote\n" | |
8d12bd32 | 562 | "session.\n\n" |
ff73fd1e CV |
563 | "You can delete the stored password by specifying an empty password.\n\n"); |
564 | strcpy (newpwd, getpass (text1)); | |
565 | if (strcmp (newpwd, getpass (text2))) | |
1b23b30b | 566 | eprint (0, "Password is not identical."); |
ff73fd1e | 567 | else if (cygwin_internal (CW_SET_PRIV_KEY, newpwd, username)) |
d8655020 CV |
568 | return eprint (0, "Storing password failed: %s", strerror (errno)); |
569 | return 0; | |
570 | } | |
571 | ||
1fd5e000 CF |
572 | if (Larg >= 0 || xarg >= 0 || narg >= 0 || iarg >= 0) |
573 | { | |
574 | if (optind < argc) | |
1b23b30b | 575 | usage (stderr, 1); |
4fa0a398 | 576 | return SetModals (xarg, narg, iarg, Larg, server); |
1fd5e000 CF |
577 | } |
578 | ||
579 | strcpy (user, optind >= argc ? getlogin () : argv[optind]); | |
580 | ||
0e0f5748 | 581 | /* Changing password for calling user? Use logonserver for user as well. */ |
6199f417 | 582 | if (!server && optind >= argc) |
0e0f5748 CV |
583 | { |
584 | myself = 1; | |
585 | if ((logonserver = getenv ("LOGONSERVER"))) | |
586 | { | |
587 | size_t len = mbstowcs (NULL, logonserver, 0); | |
588 | if (len > 0 && len != (size_t) -1) | |
589 | mbstowcs (server = alloca ((len + 1) * sizeof (wchar_t)), | |
590 | logonserver, len + 1); | |
591 | } | |
592 | } | |
1fd5e000 | 593 | |
4fa0a398 | 594 | ui = GetPW (user, 1, server); |
1fd5e000 CF |
595 | if (! ui) |
596 | return 1; | |
597 | ||
1f4e5e15 | 598 | if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt) |
1fd5e000 | 599 | { |
02bd05e3 CV |
600 | USER_INFO_1008 uif; |
601 | ||
02bd05e3 | 602 | uif.usri1008_flags = ui->usri3_flags; |
1fd5e000 | 603 | if (lopt) |
1b23b30b | 604 | { |
1fd5e000 | 605 | if (ui->usri3_priv == USER_PRIV_ADMIN) |
94a23f48 | 606 | return eprint (0, "Locking an admin account is disallowed."); |
1b23b30b CF |
607 | uif.usri1008_flags |= UF_ACCOUNTDISABLE; |
608 | } | |
1fd5e000 | 609 | if (uopt) |
1b23b30b | 610 | uif.usri1008_flags &= ~UF_ACCOUNTDISABLE; |
1f4e5e15 | 611 | if (copt) |
1b23b30b | 612 | uif.usri1008_flags |= UF_PASSWD_CANT_CHANGE; |
1f4e5e15 | 613 | if (Copt) |
1b23b30b | 614 | uif.usri1008_flags &= ~UF_PASSWD_CANT_CHANGE; |
1f4e5e15 | 615 | if (eopt) |
1b23b30b | 616 | uif.usri1008_flags |= UF_DONT_EXPIRE_PASSWD; |
1f4e5e15 | 617 | if (Eopt) |
1b23b30b | 618 | uif.usri1008_flags &= ~UF_DONT_EXPIRE_PASSWD; |
1f4e5e15 | 619 | if (popt) |
1b23b30b | 620 | uif.usri1008_flags |= UF_PASSWD_NOTREQD; |
1f4e5e15 | 621 | if (Popt) |
1b23b30b | 622 | uif.usri1008_flags &= ~UF_PASSWD_NOTREQD; |
1f4e5e15 CV |
623 | |
624 | if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt) | |
1fd5e000 | 625 | { |
1b23b30b CF |
626 | ret = NetUserSetInfo (server, ui->usri3_name, 1008, (LPBYTE) &uif, |
627 | NULL); | |
628 | return EvalRet (ret, NULL); | |
1fd5e000 CF |
629 | } |
630 | // Sopt | |
4fa0a398 | 631 | PrintPW (ui, server); |
1fd5e000 CF |
632 | return 0; |
633 | } | |
634 | ||
0e0f5748 | 635 | if (!caller_is_admin () && !myself) |
1fd5e000 CF |
636 | return eprint (0, "You may not change the password for %s.", user); |
637 | ||
638 | eprint (0, "Enter the new password (minimum of 5, maximum of 8 characters)."); | |
639 | eprint (0, "Please use a combination of upper and lower case letters and numbers."); | |
640 | ||
deb2b467 | 641 | oldpwd[0] = '\0'; |
0e0f5748 | 642 | if (!caller_is_admin ()) |
1fd5e000 CF |
643 | { |
644 | strcpy (oldpwd, getpass ("Old password: ")); | |
4fa0a398 | 645 | if (ChangePW (user, oldpwd, oldpwd, 1, server)) |
1b23b30b | 646 | return 1; |
1fd5e000 CF |
647 | } |
648 | ||
649 | do | |
650 | { | |
651 | strcpy (newpwd, getpass ("New password: ")); | |
652 | if (strcmp (newpwd, getpass ("Re-enter new password: "))) | |
1b23b30b | 653 | eprint (0, "Password is not identical."); |
4fa0a398 | 654 | else if (! ChangePW (user, *oldpwd ? oldpwd : NULL, newpwd, 0, server)) |
1b23b30b | 655 | ret = 1; |
1fd5e000 | 656 | if (! ret && cnt < 2) |
1b23b30b | 657 | eprint (0, "Try again."); |
1fd5e000 CF |
658 | } |
659 | while (! ret && ++cnt < 3); | |
660 | return ! ret; | |
661 | } |