From d8655020634cad32686b9d21d54c1db6f706e6ca Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 26 Nov 2008 10:19:09 +0000 Subject: [PATCH] * passwd.c (longopts): Add --reg-store-pwd option. (opts): Add -R option. (usage): Add text for -R/--reg-store-pwd option. (main): Fix size of local user and password string arrays. Handle -R option. * utils.sgml: Add text for passwd -R/--reg-store-pwd option. --- winsup/utils/ChangeLog | 9 +++++ winsup/utils/passwd.c | 81 ++++++++++++++++++++++++++++++++--------- winsup/utils/utils.sgml | 37 +++++++++++++++++++ 3 files changed, 110 insertions(+), 17 deletions(-) diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog index 57fae5ee7..580ab6fa8 100644 --- a/winsup/utils/ChangeLog +++ b/winsup/utils/ChangeLog @@ -1,3 +1,12 @@ +2008-11-26 Corinna Vinschen + + * passwd.c (longopts): Add --reg-store-pwd option. + (opts): Add -R option. + (usage): Add text for -R/--reg-store-pwd option. + (main): Fix size of local user and password string arrays. + Handle -R option. + * utils.sgml: Add text for passwd -R/--reg-store-pwd option. + 2008-10-29 Christopher Faylor * Makefile.in (ALL_LDFLAGS): Link libgcc statically for everything diff --git a/winsup/utils/passwd.c b/winsup/utils/passwd.c index 017d12283..7b9e26420 100644 --- a/winsup/utils/passwd.c +++ b/winsup/utils/passwd.c @@ -1,6 +1,6 @@ /* 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 @@ -26,6 +26,7 @@ details. */ #include #include #include +#include #define USER_PRIV_ADMIN 2 @@ -50,10 +51,11 @@ static struct option longopts[] = {"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, ...) @@ -263,6 +265,9 @@ usage (FILE * stream, int status) " 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" @@ -281,7 +286,16 @@ usage (FILE * stream, int status) "\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 \n", prog_name); exit (status); @@ -314,7 +328,7 @@ int 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; @@ -331,6 +345,7 @@ main (int argc, char **argv) int popt = 0; int Popt = 0; int Sopt = 0; + int Ropt = 0; PUSER_INFO_3 ui, li; LPWSTR server = NULL; @@ -353,20 +368,20 @@ main (int argc, char **argv) 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."); @@ -376,25 +391,27 @@ main (int argc, char **argv) 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 != '\\') @@ -408,25 +425,25 @@ main (int argc, char **argv) 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; @@ -437,7 +454,7 @@ main (int argc, char **argv) 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."); @@ -447,7 +464,7 @@ main (int argc, char **argv) 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 " @@ -456,15 +473,45 @@ main (int argc, char **argv) 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); diff --git a/winsup/utils/utils.sgml b/winsup/utils/utils.sgml index 3c7a386dd..7f8ed7bc4 100644 --- a/winsup/utils/utils.sgml +++ b/winsup/utils/utils.sgml @@ -899,6 +899,9 @@ User operations: 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 @@ -916,6 +919,15 @@ Other options: 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. passwd changes passwords for user accounts. @@ -976,6 +988,31 @@ to LEN characters. Allowed values for the minimum password length are 0 to 14. In any of the above cases, a value of 0 means `no restrictions'. +Users can use the passwd -R 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 +set{e}uid(user_id) 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, ssh 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 + section. + +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 passwd -R, it's required to run +cygserver as a service under the LocalSystem account +and the environment variable CYGWIN +(see ) +must be set to contain the "server" setting before running +passwd -R. This only affects storing passwords. +Using passwords in privileged processes does not require +cygserver to run. + Limitations: Users may not be able to change their password on some systems.