2000-02-18 03:38:33 +08:00
|
|
|
/* passwd.c: Changing passwords and managing account information
|
|
|
|
|
|
|
|
Written by Corinna Vinschen <corinna.vinschen@cityweb.de>
|
|
|
|
|
|
|
|
This file is part of Cygwin.
|
|
|
|
|
|
|
|
This software is a copyrighted work licensed under the terms of the
|
|
|
|
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
|
|
|
details. */
|
|
|
|
|
2002-06-14 19:31:33 +08:00
|
|
|
#include <windows.h>
|
|
|
|
#include <wininet.h>
|
|
|
|
#include <lmaccess.h>
|
|
|
|
#include <lmerr.h>
|
|
|
|
#include <lmcons.h>
|
|
|
|
#include <lmapibuf.h>
|
2014-11-24 19:07:32 +08:00
|
|
|
#include <dsgetdc.h>
|
2002-06-14 19:31:33 +08:00
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2013-04-23 17:44:36 +08:00
|
|
|
#include <inttypes.h>
|
2000-02-18 03:38:33 +08:00
|
|
|
#include <getopt.h>
|
|
|
|
#include <pwd.h>
|
2002-06-14 19:31:33 +08:00
|
|
|
#include <sys/cygwin.h>
|
2011-10-10 22:57:48 +08:00
|
|
|
#include <cygwin/version.h>
|
2000-02-18 03:38:33 +08:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <time.h>
|
2008-11-26 18:19:09 +08:00
|
|
|
#include <errno.h>
|
2009-03-22 18:09:01 +08:00
|
|
|
#include <locale.h>
|
|
|
|
#include <wchar.h>
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
#define USER_PRIV_ADMIN 2
|
|
|
|
|
2002-05-29 15:13:09 +08:00
|
|
|
static char *prog_name;
|
|
|
|
|
|
|
|
static struct option longopts[] =
|
|
|
|
{
|
2003-11-04 18:30:35 +08:00
|
|
|
{"cannot-change", no_argument, NULL, 'c'},
|
|
|
|
{"can-change", no_argument, NULL, 'C'},
|
2005-08-19 04:25:43 +08:00
|
|
|
{"logonserver", required_argument, NULL, 'd'},
|
2003-11-04 18:30:35 +08:00
|
|
|
{"never-expires", no_argument, NULL, 'e'},
|
|
|
|
{"expires", no_argument, NULL, 'E'},
|
2002-05-29 15:13:09 +08:00
|
|
|
{"help", no_argument, NULL, 'h' },
|
|
|
|
{"inactive", required_argument, NULL, 'i'},
|
|
|
|
{"lock", no_argument, NULL, 'l'},
|
|
|
|
{"minage", required_argument, NULL, 'n'},
|
2003-11-04 18:30:35 +08:00
|
|
|
{"pwd-not-required", no_argument, NULL, 'p'},
|
|
|
|
{"pwd-required", no_argument, NULL, 'P'},
|
2002-05-29 15:13:09 +08:00
|
|
|
{"unlock", no_argument, NULL, 'u'},
|
2011-10-10 22:57:48 +08:00
|
|
|
{"version", no_argument, NULL, 'V'},
|
2002-05-29 15:13:09 +08:00
|
|
|
{"maxage", required_argument, NULL, 'x'},
|
|
|
|
{"length", required_argument, NULL, 'L'},
|
|
|
|
{"status", no_argument, NULL, 'S'},
|
2008-11-26 18:19:09 +08:00
|
|
|
{ "reg-store-pwd", no_argument, NULL, 'R'},
|
2002-05-29 15:13:09 +08:00
|
|
|
{NULL, 0, NULL, 0}
|
|
|
|
};
|
|
|
|
|
2012-02-09 18:11:26 +08:00
|
|
|
static char opts[] = "cCd:eEhi:ln:pPuvVx:L:SR";
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
int
|
|
|
|
eprint (int with_name, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
if (with_name)
|
2002-05-29 15:13:09 +08:00
|
|
|
fprintf(stderr, "%s: ", prog_name);
|
2000-02-18 03:38:33 +08:00
|
|
|
va_start (ap, fmt);
|
|
|
|
vfprintf (stderr, fmt, ap);
|
|
|
|
va_end (ap);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
EvalRet (int ret, const char *user)
|
|
|
|
{
|
|
|
|
switch (ret)
|
|
|
|
{
|
|
|
|
case NERR_Success:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case ERROR_ACCESS_DENIED:
|
2014-08-07 03:24:57 +08:00
|
|
|
if (!user)
|
2011-12-18 07:39:47 +08:00
|
|
|
eprint (0, "You may not change password expiry information.");
|
2000-02-18 03:38:33 +08:00
|
|
|
else
|
2011-12-18 07:39:47 +08:00
|
|
|
eprint (0, "You may not change the password for %s.", user);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NERR_PasswordTooShort:
|
|
|
|
eprint (0, "Bad password: Too short.");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NERR_UserNotFound:
|
|
|
|
eprint (1, "unknown user %s", user);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ERROR_INVALID_PASSWORD:
|
|
|
|
case NERR_BadPassword:
|
|
|
|
eprint (0, "Incorrect password for %s.", user);
|
|
|
|
eprint (0, "The password for %s is unchanged.", user);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
eprint (1, "unrecoverable error %d", ret);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PUSER_INFO_3
|
2016-08-31 18:08:34 +08:00
|
|
|
GetPW (char *user, int print_win_name, LPWSTR *server, LPWSTR domain)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2002-06-14 19:31:33 +08:00
|
|
|
char usr_buf[UNLEN + 1];
|
2009-03-22 18:09:01 +08:00
|
|
|
WCHAR name[UNLEN + 1];
|
2000-02-18 03:38:33 +08:00
|
|
|
DWORD ret;
|
|
|
|
PUSER_INFO_3 ui;
|
2002-06-14 19:31:33 +08:00
|
|
|
struct passwd *pw;
|
2016-08-31 18:08:34 +08:00
|
|
|
char dom[INTERNET_MAX_HOST_NAME_LENGTH + 1];
|
2011-12-18 07:39:47 +08:00
|
|
|
|
2014-11-24 19:07:32 +08:00
|
|
|
/* Get the Win32 username and a suitable server. */
|
2016-08-31 18:08:34 +08:00
|
|
|
pw = getpwnam (user);
|
|
|
|
if (!pw)
|
2002-06-14 19:31:33 +08:00
|
|
|
{
|
2016-08-31 18:08:34 +08:00
|
|
|
EvalRet (NERR_UserNotFound, user);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cygwin_internal (CW_EXTRACT_DOMAIN_AND_USER, pw, dom, usr_buf);
|
|
|
|
/* Hack to avoid problem with LookupAccountSid after impersonation
|
|
|
|
using the simple NtCreateToken method. */
|
|
|
|
if (strcasecmp (pw->pw_name, usr_buf) && strcasecmp (usr_buf, "SYSTEM"))
|
|
|
|
{
|
|
|
|
user = usr_buf;
|
|
|
|
if (print_win_name)
|
|
|
|
printf ("Windows username : %s\n", user);
|
2002-06-14 19:31:33 +08:00
|
|
|
}
|
2009-03-22 18:09:01 +08:00
|
|
|
mbstowcs (name, user, UNLEN + 1);
|
2016-08-31 18:08:34 +08:00
|
|
|
mbstowcs (domain, dom, INTERNET_MAX_HOST_NAME_LENGTH + 1);
|
|
|
|
if (!*server)
|
|
|
|
{
|
|
|
|
PDOMAIN_CONTROLLER_INFOW dci;
|
|
|
|
WCHAR machine[INTERNET_MAX_HOST_NAME_LENGTH + 1];
|
|
|
|
DWORD mlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
|
|
|
|
|
|
|
|
/* If the machine name is not the same as the user's domain name we're
|
|
|
|
in a domain. Fetch the DC via DsGetDcName. Otherwise, just stick
|
|
|
|
to a NULL servername, since that's the same as using the local
|
|
|
|
machine. */
|
|
|
|
if ((!GetComputerNameExW (ComputerNameNetBIOS, machine, &mlen)
|
|
|
|
|| wcscasecmp (domain, machine) != 0)
|
|
|
|
&& !DsGetDcNameW (NULL, domain, NULL, NULL, DS_IS_FLAT_NAME, &dci))
|
|
|
|
*server = dci->DomainControllerName;
|
|
|
|
}
|
|
|
|
|
2014-11-24 19:07:32 +08:00
|
|
|
ret = NetUserGetInfo (*server, name, 3, (void *) &ui);
|
2000-02-18 03:38:33 +08:00
|
|
|
return EvalRet (ret, user) ? NULL : ui;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2016-08-31 18:08:34 +08:00
|
|
|
ChangePW (const char *user, PCWSTR domain, PCWSTR name, const char *oldpwd,
|
|
|
|
const char *pwd, int justcheck, PCWSTR server)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2014-11-24 19:07:32 +08:00
|
|
|
WCHAR oldpass[512], pass[512];
|
2000-02-18 03:38:33 +08:00
|
|
|
DWORD ret;
|
|
|
|
|
2009-03-22 18:09:01 +08:00
|
|
|
mbstowcs (pass, pwd, 512);
|
2014-08-07 03:24:57 +08:00
|
|
|
if (!oldpwd)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
USER_INFO_1003 ui;
|
|
|
|
|
|
|
|
ui.usri1003_password = pass;
|
2005-08-19 04:25:43 +08:00
|
|
|
ret = NetUserSetInfo (server, name, 1003, (LPBYTE) &ui, NULL);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-03-22 18:09:01 +08:00
|
|
|
mbstowcs (oldpass, oldpwd, 512);
|
2016-08-31 18:08:34 +08:00
|
|
|
/* NetUserChangePassword has changed between W7 and W8.1. For some
|
|
|
|
reason it doesn't accept the usual "\\server" servername anymore,
|
|
|
|
rather you have to use the domain name as server parameter, otherwise
|
|
|
|
you suffer an error 1265, ERROR_DOWNGRADE_DETECTED. */
|
|
|
|
ret = NetUserChangePassword (domain, name, oldpass, pass);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2002-01-30 19:57:16 +08:00
|
|
|
if (justcheck && ret != ERROR_INVALID_PASSWORD)
|
|
|
|
return 0;
|
2014-08-07 03:24:57 +08:00
|
|
|
if (!EvalRet (ret, user) && !justcheck)
|
|
|
|
eprint (0, "Password changed.");
|
2000-02-18 03:38:33 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-08-31 18:08:34 +08:00
|
|
|
PrintPW (PUSER_INFO_3 ui, PCWSTR server)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
time_t t = time (NULL) - ui->usri3_password_age;
|
|
|
|
int ret;
|
|
|
|
PUSER_MODALS_INFO_0 mi;
|
|
|
|
|
2003-11-04 18:30:35 +08:00
|
|
|
printf ("Account disabled : %s",
|
2011-12-18 07:39:47 +08:00
|
|
|
(ui->usri3_flags & UF_ACCOUNTDISABLE) ? "yes\n" : "no\n");
|
2003-11-04 18:54:47 +08:00
|
|
|
printf ("Password not required : %s",
|
2011-12-18 07:39:47 +08:00
|
|
|
(ui->usri3_flags & UF_PASSWD_NOTREQD) ? "yes\n" : "no\n");
|
2003-11-04 18:30:35 +08:00
|
|
|
printf ("User can't change password : %s",
|
2011-12-18 07:39:47 +08:00
|
|
|
(ui->usri3_flags & UF_PASSWD_CANT_CHANGE) ? "yes\n" : "no\n");
|
2003-11-04 18:30:35 +08:00
|
|
|
printf ("Password never expires : %s",
|
2011-12-18 07:39:47 +08:00
|
|
|
(ui->usri3_flags & UF_DONT_EXPIRE_PASSWD) ? "yes\n" : "no\n");
|
2003-11-04 18:30:35 +08:00
|
|
|
printf ("Password expired : %s",
|
|
|
|
(ui->usri3_password_expired) ? "yes\n" : "no\n");
|
|
|
|
printf ("Latest password change : %s", ctime(&t));
|
2005-08-19 04:25:43 +08:00
|
|
|
ret = NetUserModalsGet (server, 0, (void *) &mi);
|
2014-08-07 03:24:57 +08:00
|
|
|
if (!ret)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2003-11-04 18:30:35 +08:00
|
|
|
if (mi->usrmod0_max_passwd_age == TIMEQ_FOREVER)
|
2011-12-18 07:39:47 +08:00
|
|
|
mi->usrmod0_max_passwd_age = 0;
|
2003-11-04 18:30:35 +08:00
|
|
|
if (mi->usrmod0_min_passwd_age == TIMEQ_FOREVER)
|
2011-12-18 07:39:47 +08:00
|
|
|
mi->usrmod0_min_passwd_age = 0;
|
2003-11-04 18:30:35 +08:00
|
|
|
if (mi->usrmod0_force_logoff == TIMEQ_FOREVER)
|
2011-12-18 07:39:47 +08:00
|
|
|
mi->usrmod0_force_logoff = 0;
|
2000-02-18 03:38:33 +08:00
|
|
|
if (ui->usri3_priv == USER_PRIV_ADMIN)
|
2011-12-18 07:39:47 +08:00
|
|
|
mi->usrmod0_min_passwd_len = 0;
|
2003-11-04 18:30:35 +08:00
|
|
|
printf ("\nSystem password settings:\n");
|
2013-04-23 17:44:36 +08:00
|
|
|
printf ("Max. password age %" PRIu32 " days\n",
|
|
|
|
(unsigned int) (mi->usrmod0_max_passwd_age / ONE_DAY));
|
|
|
|
printf ("Min. password age %" PRIu32 " days\n",
|
|
|
|
(unsigned int) (mi->usrmod0_min_passwd_age / ONE_DAY));
|
|
|
|
printf ("Force logout after %" PRIu32 " days\n",
|
|
|
|
(unsigned int) (mi->usrmod0_force_logoff / ONE_DAY));
|
|
|
|
printf ("Min. password length: %" PRIu32 "\n",
|
|
|
|
(unsigned int) mi->usrmod0_min_passwd_len);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2016-08-31 18:08:34 +08:00
|
|
|
SetModals (int xarg, int narg, int iarg, int Larg, PCWSTR server)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
PUSER_MODALS_INFO_0 mi;
|
|
|
|
|
2005-08-19 04:25:43 +08:00
|
|
|
ret = NetUserModalsGet (server, 0, (void *) &mi);
|
2014-08-07 03:24:57 +08:00
|
|
|
if (!ret)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
if (xarg == 0)
|
|
|
|
mi->usrmod0_max_passwd_age = TIMEQ_FOREVER;
|
|
|
|
else if (xarg > 0)
|
|
|
|
mi->usrmod0_max_passwd_age = xarg * ONE_DAY;
|
|
|
|
|
|
|
|
if (narg == 0)
|
|
|
|
{
|
|
|
|
mi->usrmod0_min_passwd_age = TIMEQ_FOREVER;
|
|
|
|
mi->usrmod0_password_hist_len = 0;
|
|
|
|
}
|
|
|
|
else if (narg > 0)
|
|
|
|
mi->usrmod0_min_passwd_age = narg * ONE_DAY;
|
|
|
|
|
|
|
|
if (iarg == 0)
|
|
|
|
mi->usrmod0_force_logoff = TIMEQ_FOREVER;
|
|
|
|
else if (iarg > 0)
|
|
|
|
mi->usrmod0_force_logoff = iarg * ONE_DAY;
|
|
|
|
|
|
|
|
if (Larg >= 0)
|
|
|
|
mi->usrmod0_min_passwd_len = Larg;
|
|
|
|
|
2005-08-19 04:25:43 +08:00
|
|
|
ret = NetUserModalsSet (server, 0, (LPBYTE) mi, NULL);
|
2000-02-18 03:38:33 +08:00
|
|
|
NetApiBufferFree (mi);
|
|
|
|
}
|
|
|
|
return EvalRet (ret, NULL);
|
|
|
|
}
|
|
|
|
|
2020-08-07 19:29:43 +08:00
|
|
|
static void __attribute__ ((__noreturn__))
|
2002-05-29 15:13:09 +08:00
|
|
|
usage (FILE * stream, int status)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2002-05-29 15:13:09 +08:00
|
|
|
fprintf (stream, ""
|
2003-11-04 18:30:35 +08:00
|
|
|
"Usage: %s [OPTION] [USER]\n"
|
2011-10-10 22:57:48 +08:00
|
|
|
"\n"
|
2003-11-04 18:30:35 +08:00
|
|
|
"Change USER's password or password attributes.\n"
|
2002-05-29 15:13:09 +08:00
|
|
|
"\n"
|
|
|
|
"User operations:\n"
|
2003-11-04 18:30:35 +08:00
|
|
|
" -l, --lock lock USER's account.\n"
|
|
|
|
" -u, --unlock unlock USER's account.\n"
|
|
|
|
" -c, --cannot-change USER can't change password.\n"
|
|
|
|
" -C, --can-change USER can change password.\n"
|
|
|
|
" -e, --never-expires USER's password never expires.\n"
|
|
|
|
" -E, --expires USER's password expires according to system's\n"
|
|
|
|
" password aging rule.\n"
|
|
|
|
" -p, --pwd-not-required no password required for USER.\n"
|
|
|
|
" -P, --pwd-required password is required for USER.\n"
|
2008-11-26 18:19:09 +08:00
|
|
|
" -R, --reg-store-pwd enter password to store it in the registry for\n"
|
|
|
|
" later usage by services to be able to switch\n"
|
|
|
|
" to this user context with network credentials.\n"
|
2002-05-29 15:13:09 +08:00
|
|
|
"\n"
|
|
|
|
"System operations:\n"
|
2003-11-04 18:30:35 +08:00
|
|
|
" -i, --inactive NUM set NUM of days before inactive accounts are disabled\n"
|
|
|
|
" (inactive accounts are those with expired passwords).\n"
|
2014-08-07 03:24:57 +08:00
|
|
|
" -n, --minage MINDAYS set system minimum password age to MINDAYS days.\n"
|
|
|
|
" -x, --maxage MAXDAYS set system maximum password age to MAXDAYS days.\n"
|
2003-11-04 18:30:35 +08:00
|
|
|
" -L, --length LEN set system minimum password length to LEN.\n"
|
2002-05-29 15:13:09 +08:00
|
|
|
"\n"
|
|
|
|
"Other options:\n"
|
2005-08-19 04:25:43 +08:00
|
|
|
" -d, --logonserver SERVER connect to SERVER (e.g. domain controller).\n"
|
2014-11-24 19:07:32 +08:00
|
|
|
" Usually not required.\n"
|
2003-11-04 18:30:35 +08:00
|
|
|
" -S, --status display password status for USER (locked, expired,\n"
|
|
|
|
" etc.) plus global system password settings.\n"
|
|
|
|
" -h, --help output usage information and exit.\n"
|
2011-10-10 22:57:48 +08:00
|
|
|
" -V, --version output version information and exit.\n"
|
2003-11-04 18:30:35 +08:00
|
|
|
"\n"
|
|
|
|
"If no option is given, change USER's password. If no user name is given,\n"
|
|
|
|
"operate on current user. System operations must not be mixed with user\n"
|
2008-11-26 18:19:09 +08:00
|
|
|
"operations. Don't specify a USER when triggering a system operation.\n"
|
|
|
|
"\n"
|
|
|
|
"Don't specify a user or any other option together with the -R option.\n"
|
2009-01-22 01:14:39 +08:00
|
|
|
"Non-Admin users can only store their password if cygserver is running\n"
|
|
|
|
"as service under the SYSTEM account.\n"
|
2008-11-26 18:19:09 +08:00
|
|
|
"Note that storing even obfuscated passwords in the registry is not overly\n"
|
|
|
|
"secure. Use this feature only if the machine is adequately locked down.\n"
|
|
|
|
"Don't use this feature if you don't need network access within a remote\n"
|
|
|
|
"session. You can delete your stored password by using `passwd -R' and\n"
|
2011-10-10 22:57:48 +08:00
|
|
|
"specifying an empty password.\n\n", prog_name);
|
2002-05-29 15:13:09 +08:00
|
|
|
exit (status);
|
|
|
|
}
|
|
|
|
|
2009-03-24 00:37:49 +08:00
|
|
|
static int
|
|
|
|
caller_is_admin ()
|
|
|
|
{
|
|
|
|
static int is_admin = -1;
|
|
|
|
HANDLE token;
|
|
|
|
DWORD size;
|
|
|
|
PTOKEN_GROUPS grps;
|
|
|
|
SID_IDENTIFIER_AUTHORITY nt_auth = {SECURITY_NT_AUTHORITY};
|
2011-12-18 07:39:47 +08:00
|
|
|
PSID admin_grp;
|
2009-03-24 00:37:49 +08:00
|
|
|
DWORD i;
|
|
|
|
|
|
|
|
if (is_admin == -1)
|
|
|
|
{
|
|
|
|
is_admin = 0;
|
|
|
|
if (OpenProcessToken (GetCurrentProcess (), TOKEN_READ, &token))
|
|
|
|
{
|
|
|
|
GetTokenInformation (token, TokenGroups, NULL, 0, &size);
|
|
|
|
grps = (PTOKEN_GROUPS) alloca (size);
|
|
|
|
if (!GetTokenInformation(token, TokenGroups, grps, size, &size)
|
|
|
|
|| !AllocateAndInitializeSid (&nt_auth, 2,
|
|
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
|
|
0, 0, 0, 0, 0, 0, &admin_grp))
|
|
|
|
is_admin = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < grps->GroupCount; ++i)
|
|
|
|
if (EqualSid (admin_grp, grps->Groups[i].Sid)
|
|
|
|
&& (grps->Groups[i].Attributes
|
|
|
|
& (SE_GROUP_ENABLED | SE_GROUP_USE_FOR_DENY_ONLY))
|
|
|
|
== SE_GROUP_ENABLED)
|
|
|
|
{
|
|
|
|
is_admin = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
FreeSid (admin_grp);
|
|
|
|
}
|
|
|
|
CloseHandle (token);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return is_admin;
|
|
|
|
}
|
|
|
|
|
2002-05-29 15:13:09 +08:00
|
|
|
static void
|
|
|
|
print_version ()
|
|
|
|
{
|
2011-10-10 22:57:48 +08:00
|
|
|
printf ("passwd (cygwin) %d.%d.%d\n"
|
2011-12-18 07:39:47 +08:00
|
|
|
"Password Utility\n"
|
2016-05-24 17:16:39 +08:00
|
|
|
"Copyright (C) 1999 - %s Cygwin Authors\n"
|
2011-12-18 07:39:47 +08:00
|
|
|
"This is free software; see the source for copying conditions. There is NO\n"
|
2011-10-10 22:57:48 +08:00
|
|
|
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
|
2011-12-18 07:39:47 +08:00
|
|
|
CYGWIN_VERSION_DLL_MAJOR / 1000,
|
|
|
|
CYGWIN_VERSION_DLL_MAJOR % 1000,
|
|
|
|
CYGWIN_VERSION_DLL_MINOR,
|
|
|
|
strrchr (__DATE__, ' ') + 1);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main (int argc, char **argv)
|
|
|
|
{
|
2011-10-10 22:57:48 +08:00
|
|
|
char *logonserver;
|
2016-08-31 18:08:34 +08:00
|
|
|
char user[UNLEN + 1];
|
|
|
|
WCHAR domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
|
|
|
|
char oldpwd[_PASSWORD_LEN + 1], newpwd[_PASSWORD_LEN + 1];
|
2000-02-18 03:38:33 +08:00
|
|
|
int ret = 0;
|
|
|
|
int cnt = 0;
|
2009-03-22 18:09:01 +08:00
|
|
|
int opt;
|
2000-02-18 03:38:33 +08:00
|
|
|
int Larg = -1;
|
|
|
|
int xarg = -1;
|
|
|
|
int narg = -1;
|
|
|
|
int iarg = -1;
|
|
|
|
int lopt = 0;
|
|
|
|
int uopt = 0;
|
2003-11-04 18:30:35 +08:00
|
|
|
int copt = 0;
|
|
|
|
int Copt = 0;
|
|
|
|
int eopt = 0;
|
|
|
|
int Eopt = 0;
|
|
|
|
int popt = 0;
|
|
|
|
int Popt = 0;
|
2000-02-18 03:38:33 +08:00
|
|
|
int Sopt = 0;
|
2008-11-26 18:19:09 +08:00
|
|
|
int Ropt = 0;
|
2009-03-24 00:37:49 +08:00
|
|
|
PUSER_INFO_3 ui;
|
|
|
|
int myself = 0;
|
2005-08-19 04:25:43 +08:00
|
|
|
LPWSTR server = NULL;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2011-10-10 22:57:48 +08:00
|
|
|
prog_name = program_invocation_short_name;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2009-05-15 19:30:18 +08:00
|
|
|
/* Use locale from environment. If not set or set to "C", use UTF-8. */
|
|
|
|
setlocale (LC_CTYPE, "");
|
|
|
|
if (!strcmp (setlocale (LC_CTYPE, NULL), "C"))
|
|
|
|
setlocale (LC_CTYPE, "en_US.UTF-8");
|
2002-05-29 15:13:09 +08:00
|
|
|
while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
|
2000-02-18 03:38:33 +08:00
|
|
|
switch (opt)
|
|
|
|
{
|
2002-05-29 15:13:09 +08:00
|
|
|
case 'h':
|
|
|
|
usage (stdout, 0);
|
2011-12-18 07:39:47 +08:00
|
|
|
break;
|
2002-05-29 15:13:09 +08:00
|
|
|
|
|
|
|
case 'i':
|
2008-11-26 18:19:09 +08:00
|
|
|
if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt || Ropt)
|
2003-11-04 18:30:35 +08:00
|
|
|
usage (stderr, 1);
|
2002-05-29 15:13:09 +08:00
|
|
|
if ((iarg = atoi (optarg)) < 0 || iarg > 999)
|
|
|
|
return eprint (1, "Force logout time must be between 0 and 999.");
|
2011-12-18 07:39:47 +08:00
|
|
|
break;
|
2002-05-29 15:13:09 +08:00
|
|
|
|
|
|
|
case 'l':
|
2008-11-26 18:19:09 +08:00
|
|
|
if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || uopt || Sopt || Ropt)
|
2002-05-29 15:13:09 +08:00
|
|
|
usage (stderr, 1);
|
|
|
|
lopt = 1;
|
2011-12-18 07:39:47 +08:00
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
case 'n':
|
2008-11-26 18:19:09 +08:00
|
|
|
if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt || Ropt)
|
2003-11-04 18:30:35 +08:00
|
|
|
usage (stderr, 1);
|
2000-02-18 03:38:33 +08:00
|
|
|
if ((narg = atoi (optarg)) < 0 || narg > 999)
|
|
|
|
return eprint (1, "Minimum password age must be between 0 and 999.");
|
|
|
|
if (xarg >= 0 && narg > xarg)
|
|
|
|
return eprint (1, "Minimum password age must be less than "
|
2011-12-18 07:39:47 +08:00
|
|
|
"maximum password age.");
|
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2002-05-29 15:13:09 +08:00
|
|
|
case 'u':
|
2008-11-26 18:19:09 +08:00
|
|
|
if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || lopt || Sopt || Ropt)
|
2002-05-29 15:13:09 +08:00
|
|
|
usage (stderr, 1);
|
|
|
|
uopt = 1;
|
2011-12-18 07:39:47 +08:00
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2003-11-04 18:30:35 +08:00
|
|
|
case 'c':
|
2008-11-26 18:19:09 +08:00
|
|
|
if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt)
|
2003-11-04 18:30:35 +08:00
|
|
|
usage (stderr, 1);
|
|
|
|
copt = 1;
|
2011-12-18 07:39:47 +08:00
|
|
|
break;
|
2003-11-04 18:30:35 +08:00
|
|
|
|
|
|
|
case 'C':
|
2008-11-26 18:19:09 +08:00
|
|
|
if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt)
|
2003-11-04 18:30:35 +08:00
|
|
|
usage (stderr, 1);
|
|
|
|
Copt = 1;
|
2011-12-18 07:39:47 +08:00
|
|
|
break;
|
2003-11-04 18:30:35 +08:00
|
|
|
|
2005-08-19 04:25:43 +08:00
|
|
|
case 'd':
|
2011-12-18 07:39:47 +08:00
|
|
|
{
|
2008-11-26 18:19:09 +08:00
|
|
|
if (Ropt)
|
|
|
|
usage (stderr, 1);
|
2005-08-19 04:25:43 +08:00
|
|
|
char *tmpbuf = alloca (strlen (optarg) + 3);
|
|
|
|
tmpbuf[0] = '\0';
|
|
|
|
if (*optarg != '\\')
|
|
|
|
strcpy (tmpbuf, "\\\\");
|
|
|
|
strcat (tmpbuf, optarg);
|
2009-03-22 18:09:01 +08:00
|
|
|
size_t len = mbstowcs (NULL, tmpbuf, 0);
|
|
|
|
if (len > 0 && len != (size_t) -1)
|
|
|
|
mbstowcs (server = alloca ((len + 1) * sizeof (wchar_t)),
|
|
|
|
tmpbuf, len + 1);
|
2005-08-19 04:25:43 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2003-11-04 18:30:35 +08:00
|
|
|
case 'e':
|
2008-11-26 18:19:09 +08:00
|
|
|
if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt)
|
2003-11-04 18:30:35 +08:00
|
|
|
usage (stderr, 1);
|
|
|
|
eopt = 1;
|
2011-12-18 07:39:47 +08:00
|
|
|
break;
|
2003-11-04 18:30:35 +08:00
|
|
|
|
|
|
|
case 'E':
|
2008-11-26 18:19:09 +08:00
|
|
|
if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt)
|
2003-11-04 18:30:35 +08:00
|
|
|
usage (stderr, 1);
|
|
|
|
Eopt = 1;
|
2011-12-18 07:39:47 +08:00
|
|
|
break;
|
2003-11-04 18:30:35 +08:00
|
|
|
|
|
|
|
case 'p':
|
2008-11-26 18:19:09 +08:00
|
|
|
if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt)
|
2003-11-04 18:30:35 +08:00
|
|
|
usage (stderr, 1);
|
|
|
|
popt = 1;
|
2011-12-18 07:39:47 +08:00
|
|
|
break;
|
2003-11-04 18:30:35 +08:00
|
|
|
|
|
|
|
case 'P':
|
2008-11-26 18:19:09 +08:00
|
|
|
if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt)
|
2003-11-04 18:30:35 +08:00
|
|
|
usage (stderr, 1);
|
|
|
|
Popt = 1;
|
2011-12-18 07:39:47 +08:00
|
|
|
break;
|
2003-11-04 18:30:35 +08:00
|
|
|
|
2011-10-10 22:57:48 +08:00
|
|
|
case 'V':
|
2014-11-24 19:07:32 +08:00
|
|
|
case 'v': /* Keep this option for historical reasons,
|
2012-02-09 18:11:26 +08:00
|
|
|
but don't advertize it. */
|
2002-05-29 15:13:09 +08:00
|
|
|
print_version ();
|
2011-12-18 07:39:47 +08:00
|
|
|
exit (0);
|
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2002-05-29 15:13:09 +08:00
|
|
|
case 'x':
|
2008-11-26 18:19:09 +08:00
|
|
|
if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt || Ropt)
|
2003-11-04 18:30:35 +08:00
|
|
|
usage (stderr, 1);
|
2002-05-29 15:13:09 +08:00
|
|
|
if ((xarg = atoi (optarg)) < 0 || xarg > 999)
|
|
|
|
return eprint (1, "Maximum password age must be between 0 and 999.");
|
|
|
|
if (narg >= 0 && xarg < narg)
|
|
|
|
return eprint (1, "Maximum password age must be greater than "
|
2011-12-18 07:39:47 +08:00
|
|
|
"minimum password age.");
|
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2002-05-29 15:13:09 +08:00
|
|
|
case 'L':
|
2008-11-26 18:19:09 +08:00
|
|
|
if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt || Ropt)
|
2003-11-04 18:30:35 +08:00
|
|
|
usage (stderr, 1);
|
2002-05-29 15:13:09 +08:00
|
|
|
if ((Larg = atoi (optarg)) < 0 || Larg > LM20_PWLEN)
|
|
|
|
return eprint (1, "Minimum password length must be between "
|
2011-12-18 07:39:47 +08:00
|
|
|
"0 and %d.", LM20_PWLEN);
|
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
case 'S':
|
2003-11-04 18:30:35 +08:00
|
|
|
if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || lopt || uopt
|
2008-11-26 18:19:09 +08:00
|
|
|
|| copt || Copt || eopt || Eopt || popt || Popt || Ropt)
|
2002-05-29 15:13:09 +08:00
|
|
|
usage (stderr, 1);
|
2000-02-18 03:38:33 +08:00
|
|
|
Sopt = 1;
|
2011-12-18 07:39:47 +08:00
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2008-11-26 18:19:09 +08:00
|
|
|
case 'R':
|
|
|
|
if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || lopt || uopt
|
|
|
|
|| copt || Copt || eopt || Eopt || popt || Popt || Sopt
|
|
|
|
|| server)
|
|
|
|
usage (stderr, 1);
|
|
|
|
Ropt = 1;
|
2011-12-18 07:39:47 +08:00
|
|
|
break;
|
2008-11-26 18:19:09 +08:00
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
default:
|
2011-12-18 07:39:47 +08:00
|
|
|
fprintf (stderr, "Try `%s --help' for more information.\n", prog_name);
|
2011-10-10 22:57:48 +08:00
|
|
|
return 1;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2005-08-19 04:25:43 +08:00
|
|
|
|
2008-11-26 18:19:09 +08:00
|
|
|
if (Ropt)
|
|
|
|
{
|
2011-04-04 17:09:43 +08:00
|
|
|
const char *username = NULL;
|
2008-11-26 18:19:09 +08:00
|
|
|
if (optind < argc)
|
2011-04-04 17:09:43 +08:00
|
|
|
{
|
|
|
|
username = argv[optind++];
|
|
|
|
if (!strcmp (username, getlogin ()))
|
|
|
|
username = NULL;
|
|
|
|
else if (!caller_is_admin ())
|
2014-06-16 21:27:08 +08:00
|
|
|
return eprint (0, "You may not change the password for %s.",
|
|
|
|
username);
|
2011-04-04 17:09:43 +08:00
|
|
|
|
|
|
|
if (optind < argc)
|
|
|
|
usage (stderr, 1);
|
|
|
|
}
|
|
|
|
char *text1 = (char *) alloca ((username ? strlen (username) + 2 : 4)
|
|
|
|
+ sizeof ("Enter current password: "));
|
|
|
|
char *text2 = (char *) alloca ((username ? strlen (username) + 2 : 4)
|
|
|
|
+ sizeof ("Re-enter current password: "));
|
|
|
|
sprintf (text1, "Enter %s%s current password: ",
|
|
|
|
username ?: "your", username ? "'s" : "");
|
|
|
|
sprintf (text2, "Re-enter %s%s current password: ",
|
|
|
|
username ?: "your", username ? "'s" : "");
|
2008-11-26 18:19:09 +08:00
|
|
|
printf (
|
|
|
|
"This functionality stores a password in the registry for usage by services\n"
|
|
|
|
"which need to change the user context and require network access. Typical\n"
|
|
|
|
"applications are interactive remote logons using sshd, cron task, etc.\n"
|
|
|
|
"This password will always tried first when any privileged application is\n"
|
|
|
|
"about to switch the user context.\n\n"
|
|
|
|
"Note that storing even obfuscated passwords in the registry is not overly\n"
|
|
|
|
"secure. Use this feature only if the machine is adequately locked down.\n"
|
|
|
|
"Don't use this feature if you don't need network access within a remote\n"
|
2008-12-16 01:33:08 +08:00
|
|
|
"session.\n\n"
|
2011-04-04 17:09:43 +08:00
|
|
|
"You can delete the stored password by specifying an empty password.\n\n");
|
|
|
|
strcpy (newpwd, getpass (text1));
|
|
|
|
if (strcmp (newpwd, getpass (text2)))
|
2011-12-18 07:39:47 +08:00
|
|
|
eprint (0, "Password is not identical.");
|
2011-04-04 17:09:43 +08:00
|
|
|
else if (cygwin_internal (CW_SET_PRIV_KEY, newpwd, username))
|
2008-11-26 18:19:09 +08:00
|
|
|
return eprint (0, "Storing password failed: %s", strerror (errno));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
if (Larg >= 0 || xarg >= 0 || narg >= 0 || iarg >= 0)
|
|
|
|
{
|
|
|
|
if (optind < argc)
|
2011-12-18 07:39:47 +08:00
|
|
|
usage (stderr, 1);
|
2005-08-19 04:25:43 +08:00
|
|
|
return SetModals (xarg, narg, iarg, Larg, server);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2016-10-23 23:16:30 +08:00
|
|
|
user[0] = '\0';
|
|
|
|
strncat (user, optind >= argc ? getlogin () : argv[optind], UNLEN);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2009-03-24 00:37:49 +08:00
|
|
|
/* Changing password for calling user? Use logonserver for user as well. */
|
2009-03-24 04:40:17 +08:00
|
|
|
if (!server && optind >= argc)
|
2009-03-24 00:37:49 +08:00
|
|
|
{
|
|
|
|
myself = 1;
|
|
|
|
if ((logonserver = getenv ("LOGONSERVER")))
|
|
|
|
{
|
|
|
|
size_t len = mbstowcs (NULL, logonserver, 0);
|
|
|
|
if (len > 0 && len != (size_t) -1)
|
|
|
|
mbstowcs (server = alloca ((len + 1) * sizeof (wchar_t)),
|
|
|
|
logonserver, len + 1);
|
|
|
|
}
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2016-08-31 18:08:34 +08:00
|
|
|
ui = GetPW (user, 1, &server, domain);
|
2014-08-07 03:24:57 +08:00
|
|
|
if (!ui)
|
2000-02-18 03:38:33 +08:00
|
|
|
return 1;
|
|
|
|
|
2003-11-04 18:30:35 +08:00
|
|
|
if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2003-11-04 18:54:47 +08:00
|
|
|
USER_INFO_1008 uif;
|
|
|
|
|
|
|
|
uif.usri1008_flags = ui->usri3_flags;
|
2000-02-18 03:38:33 +08:00
|
|
|
if (lopt)
|
2011-12-18 07:39:47 +08:00
|
|
|
{
|
2000-02-18 03:38:33 +08:00
|
|
|
if (ui->usri3_priv == USER_PRIV_ADMIN)
|
2002-06-14 19:31:33 +08:00
|
|
|
return eprint (0, "Locking an admin account is disallowed.");
|
2011-12-18 07:39:47 +08:00
|
|
|
uif.usri1008_flags |= UF_ACCOUNTDISABLE;
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
if (uopt)
|
2011-12-18 07:39:47 +08:00
|
|
|
uif.usri1008_flags &= ~UF_ACCOUNTDISABLE;
|
2003-11-04 18:30:35 +08:00
|
|
|
if (copt)
|
2011-12-18 07:39:47 +08:00
|
|
|
uif.usri1008_flags |= UF_PASSWD_CANT_CHANGE;
|
2003-11-04 18:30:35 +08:00
|
|
|
if (Copt)
|
2011-12-18 07:39:47 +08:00
|
|
|
uif.usri1008_flags &= ~UF_PASSWD_CANT_CHANGE;
|
2003-11-04 18:30:35 +08:00
|
|
|
if (eopt)
|
2011-12-18 07:39:47 +08:00
|
|
|
uif.usri1008_flags |= UF_DONT_EXPIRE_PASSWD;
|
2003-11-04 18:30:35 +08:00
|
|
|
if (Eopt)
|
2011-12-18 07:39:47 +08:00
|
|
|
uif.usri1008_flags &= ~UF_DONT_EXPIRE_PASSWD;
|
2003-11-04 18:30:35 +08:00
|
|
|
if (popt)
|
2011-12-18 07:39:47 +08:00
|
|
|
uif.usri1008_flags |= UF_PASSWD_NOTREQD;
|
2003-11-04 18:30:35 +08:00
|
|
|
if (Popt)
|
2011-12-18 07:39:47 +08:00
|
|
|
uif.usri1008_flags &= ~UF_PASSWD_NOTREQD;
|
2003-11-04 18:30:35 +08:00
|
|
|
|
|
|
|
if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2011-12-18 07:39:47 +08:00
|
|
|
ret = NetUserSetInfo (server, ui->usri3_name, 1008, (LPBYTE) &uif,
|
|
|
|
NULL);
|
|
|
|
return EvalRet (ret, NULL);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
// Sopt
|
2005-08-19 04:25:43 +08:00
|
|
|
PrintPW (ui, server);
|
2000-02-18 03:38:33 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-24 00:37:49 +08:00
|
|
|
if (!caller_is_admin () && !myself)
|
2000-02-18 03:38:33 +08:00
|
|
|
return eprint (0, "You may not change the password for %s.", user);
|
|
|
|
|
2000-07-31 21:35:39 +08:00
|
|
|
oldpwd[0] = '\0';
|
2009-03-24 00:37:49 +08:00
|
|
|
if (!caller_is_admin ())
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
strcpy (oldpwd, getpass ("Old password: "));
|
2016-08-31 18:08:34 +08:00
|
|
|
if (ChangePW (user, domain, ui->usri3_name, oldpwd, oldpwd, 1, server))
|
2011-12-18 07:39:47 +08:00
|
|
|
return 1;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
strcpy (newpwd, getpass ("New password: "));
|
|
|
|
if (strcmp (newpwd, getpass ("Re-enter new password: ")))
|
2011-12-18 07:39:47 +08:00
|
|
|
eprint (0, "Password is not identical.");
|
2016-08-31 18:08:34 +08:00
|
|
|
else if (!ChangePW (user, domain, ui->usri3_name,
|
|
|
|
*oldpwd ? oldpwd : NULL, newpwd, 0, server))
|
2011-12-18 07:39:47 +08:00
|
|
|
ret = 1;
|
2014-08-07 03:24:57 +08:00
|
|
|
if (!ret && cnt < 2)
|
2011-12-18 07:39:47 +08:00
|
|
|
eprint (0, "Try again.");
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2014-08-07 03:24:57 +08:00
|
|
|
while (!ret && ++cnt < 3);
|
|
|
|
return !ret;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|