/* passwd.c: Changing passwords and managing account information
- Copyright 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+ Copyright 1999, 2000, 2001, 2002, 2003, 2008 Red Hat, Inc.
Written by Corinna Vinschen <corinna.vinschen@cityweb.de>
#include <sys/cygwin.h>
#include <sys/types.h>
#include <time.h>
+#include <errno.h>
#define USER_PRIV_ADMIN 2
{"maxage", required_argument, NULL, 'x'},
{"length", required_argument, NULL, 'L'},
{"status", no_argument, NULL, 'S'},
+ { "reg-store-pwd", no_argument, NULL, 'R'},
{NULL, 0, NULL, 0}
};
-static char opts[] = "cCd:eEhi:ln:pPuvx:L:S";
+static char opts[] = "cCd:eEhi:ln:pPuvx:L:SR";
int
eprint (int with_name, const char *fmt, ...)
" password aging rule.\n"
" -p, --pwd-not-required no password required for USER.\n"
" -P, --pwd-required password is required for USER.\n"
+ " -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"
"\n"
"System operations:\n"
" -i, --inactive NUM set NUM of days before inactive accounts are disabled\n"
"\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"
- "operations. Don't specify a USER when triggering a system operation. \n"
+ "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"
+ "Non-Admin users can only store their password if cygserver is running and\n"
+ "the CYGWIN environment variable is set to contain the word 'server'.\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"
+ "session. You can delete your stored password by using `passwd -R' and\n"
+ "specifying an empty password.\n"
"\n"
"Report bugs to <cygwin@cygwin.com>\n", prog_name);
exit (status);
main (int argc, char **argv)
{
char *c;
- char user[64], oldpwd[64], newpwd[64];
+ char user[UNLEN + 1], oldpwd[_PASSWORD_LEN + 1], newpwd[_PASSWORD_LEN + 1];
int ret = 0;
int cnt = 0;
int opt, len;
int popt = 0;
int Popt = 0;
int Sopt = 0;
+ int Ropt = 0;
PUSER_INFO_3 ui, li;
LPWSTR server = NULL;
break;
case 'i':
- if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt)
+ if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt || Ropt)
usage (stderr, 1);
if ((iarg = atoi (optarg)) < 0 || iarg > 999)
return eprint (1, "Force logout time must be between 0 and 999.");
break;
case 'l':
- if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || uopt || Sopt)
+ if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || uopt || Sopt || Ropt)
usage (stderr, 1);
lopt = 1;
break;
case 'n':
- if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt)
+ if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt || Ropt)
usage (stderr, 1);
if ((narg = atoi (optarg)) < 0 || narg > 999)
return eprint (1, "Minimum password age must be between 0 and 999.");
break;
case 'u':
- if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || lopt || Sopt)
+ if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || lopt || Sopt || Ropt)
usage (stderr, 1);
uopt = 1;
break;
case 'c':
- if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt)
+ if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt)
usage (stderr, 1);
copt = 1;
break;
case 'C':
- if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt)
+ if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt)
usage (stderr, 1);
Copt = 1;
break;
case 'd':
{
+ if (Ropt)
+ usage (stderr, 1);
char *tmpbuf = alloca (strlen (optarg) + 3);
tmpbuf[0] = '\0';
if (*optarg != '\\')
break;
case 'e':
- if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt)
+ if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt)
usage (stderr, 1);
eopt = 1;
break;
case 'E':
- if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt)
+ if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt)
usage (stderr, 1);
Eopt = 1;
break;
case 'p':
- if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt)
+ if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt)
usage (stderr, 1);
popt = 1;
break;
case 'P':
- if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt)
+ if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || Sopt || Ropt)
usage (stderr, 1);
Popt = 1;
break;
break;
case 'x':
- if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt)
+ if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt || Ropt)
usage (stderr, 1);
if ((xarg = atoi (optarg)) < 0 || xarg > 999)
return eprint (1, "Maximum password age must be between 0 and 999.");
break;
case 'L':
- if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt)
+ if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt || Ropt)
usage (stderr, 1);
if ((Larg = atoi (optarg)) < 0 || Larg > LM20_PWLEN)
return eprint (1, "Minimum password length must be between "
case 'S':
if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || lopt || uopt
- || copt || Copt || eopt || Eopt || popt || Popt)
+ || copt || Copt || eopt || Eopt || popt || Popt || Ropt)
usage (stderr, 1);
Sopt = 1;
break;
+ 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;
+ break;
+
default:
usage (stderr, 1);
}
+ if (Ropt)
+ {
+ if (optind < argc)
+ usage (stderr, 1);
+ 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"
+"session. You can delete your stored password by specifying an empty password.\n\n");
+ strcpy (newpwd, getpass ("Enter your current password: "));
+ if (strcmp (newpwd, getpass ("Re-enter your current password: ")))
+ eprint (0, "Password is not identical.");
+ else if (cygwin_internal (CW_SET_PRIV_KEY, newpwd))
+ return eprint (0, "Storing password failed: %s", strerror (errno));
+ return 0;
+ }
+
if (!server)
{
len = GetEnvironmentVariableW (L"LOGONSERVER", NULL, 0);
password aging rule.
-p, --pwd-not-required no password required for USER.
-P, --pwd-required password is required for USER.
+ -R, --reg-store-pwd enter password to store it in the registry for
+ later usage by services to be able to switch
+ to this user context with network credentials."
System operations:
-i, --inactive NUM set NUM of days before inactive accounts are disabled
If no option is given, change USER's password. If no user name is given,
operate on current user. System operations must not be mixed with user
operations. Don't specify a USER when triggering a system operation.
+
+Don't specify a user or any other option together with the -R option.
+Non-Admin users can only store their password if cygserver is running and
+the CYGWIN environment variable is set to contain the word 'server'.
+Note that storing even obfuscated passwords in the registry is not overly
+secure. Use this feature only if the machine is adequately locked down.
+Don't use this feature if you don't need network access within a remote
+session. You can delete your stored password by using `passwd -R' and
+specifying an empty password.
</screen>
<para> <command>passwd</command> changes passwords for user accounts.
password length are 0 to 14. In any of the above cases, a value of 0
means `no restrictions'.</para>
+<para>Users can use the <command>passwd -R</command> to enter
+a password which then gets stored in a special area of the registry,
+which is also used by Windows to store passwords of accounts running
+Windows services. When a privileged Cygwin application calls the
+<command>set{e}uid(user_id)</command> system call, Cygwin checks if a
+password for that user has been stored in this registry area. If so, it
+uses this password to switch to this user account using that password.
+This allows to logon through, for instance, <command>ssh</command> with
+public key authentication and to get a full qualified user token with
+all credentials for network access. However, the method has some
+drawbacks security-wise. This is explained in more detail in the
+<xref linkend="ntsec"></xref> section.</para>
+
+<para>Please note that storing password in that registry area is a
+privileged operation which only administrative accounts are allowed to
+do. If normal, non-admin users should be allowed to enter their
+passwords using <command>passwd -R</command>, it's required to run
+<command>cygserver</command> as a service under the LocalSystem account
+and the environment variable CYGWIN
+(see <xref linkend="using-cygwinenv"></xref>)
+must be set to contain the "server" setting before running
+<command>passwd -R</command>. This only affects storing passwords.
+Using passwords in privileged processes does not require
+<command>cygserver</command> to run.</para>
+
<para>Limitations: Users may not be able to change their password on
some systems.</para>