658 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			658 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* passwd.c: Changing passwords and managing account information
 | 
						|
 | 
						|
   Copyright 1999, 2000, 2001, 2002, 2003, 2008, 2009, 2011 Red Hat, Inc.
 | 
						|
 | 
						|
   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. */
 | 
						|
 | 
						|
#include <windows.h>
 | 
						|
#include <wininet.h>
 | 
						|
#include <lmaccess.h>
 | 
						|
#include <lmerr.h>
 | 
						|
#include <lmcons.h>
 | 
						|
#include <lmapibuf.h>
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <getopt.h>
 | 
						|
#include <pwd.h>
 | 
						|
#include <sys/cygwin.h>
 | 
						|
#include <cygwin/version.h>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <time.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <locale.h>
 | 
						|
#include <wchar.h>
 | 
						|
 | 
						|
#define USER_PRIV_ADMIN		 2
 | 
						|
 | 
						|
static char *prog_name;
 | 
						|
 | 
						|
static struct option longopts[] =
 | 
						|
{
 | 
						|
  {"cannot-change", no_argument, NULL, 'c'},
 | 
						|
  {"can-change", no_argument, NULL, 'C'},
 | 
						|
  {"logonserver", required_argument, NULL, 'd'},
 | 
						|
  {"never-expires", no_argument, NULL, 'e'},
 | 
						|
  {"expires", no_argument, NULL, 'E'},
 | 
						|
  {"help", no_argument, NULL, 'h' },
 | 
						|
  {"inactive", required_argument, NULL, 'i'},
 | 
						|
  {"lock", no_argument, NULL, 'l'},
 | 
						|
  {"minage", required_argument, NULL, 'n'},
 | 
						|
  {"pwd-not-required", no_argument, NULL, 'p'},
 | 
						|
  {"pwd-required", no_argument, NULL, 'P'},
 | 
						|
  {"unlock", no_argument, NULL, 'u'},
 | 
						|
  {"version", no_argument, NULL, 'V'},
 | 
						|
  {"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:SR";
 | 
						|
 | 
						|
int
 | 
						|
eprint (int with_name, const char *fmt, ...)
 | 
						|
{
 | 
						|
  va_list ap;
 | 
						|
 | 
						|
  if (with_name)
 | 
						|
    fprintf(stderr, "%s: ", prog_name);
 | 
						|
  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:
 | 
						|
      if (! user)
 | 
						|
	eprint (0, "You may not change password expiry information.");
 | 
						|
      else
 | 
						|
	eprint (0, "You may not change the password for %s.", user);
 | 
						|
      break;
 | 
						|
 | 
						|
      eprint (0, "Bad password: Invalid.");
 | 
						|
      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
 | 
						|
GetPW (char *user, int print_win_name, LPCWSTR server)
 | 
						|
{
 | 
						|
  char usr_buf[UNLEN + 1];
 | 
						|
  WCHAR name[UNLEN + 1];
 | 
						|
  DWORD ret;
 | 
						|
  PUSER_INFO_3 ui;
 | 
						|
  struct passwd *pw;
 | 
						|
  char *domain = (char *) alloca (INTERNET_MAX_HOST_NAME_LENGTH + 1);
 | 
						|
 | 
						|
  /* Try getting a Win32 username in case the user edited /etc/passwd */
 | 
						|
  if ((pw = getpwnam (user)))
 | 
						|
    {
 | 
						|
      cygwin_internal (CW_EXTRACT_DOMAIN_AND_USER, pw, domain, usr_buf);
 | 
						|
      if (strcasecmp (pw->pw_name, usr_buf))
 | 
						|
	{
 | 
						|
	  /* Hack to avoid problem with LookupAccountSid after impersonation */
 | 
						|
	  if (strcasecmp (usr_buf, "SYSTEM"))
 | 
						|
	    {
 | 
						|
	      user = usr_buf;
 | 
						|
	      if (print_win_name)
 | 
						|
		printf ("Windows username : %s\n", user);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
  mbstowcs (name, user, UNLEN + 1);
 | 
						|
  ret = NetUserGetInfo (server, name, 3, (void *) &ui);
 | 
						|
  return EvalRet (ret, user) ? NULL : ui;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ChangePW (const char *user, const char *oldpwd, const char *pwd, int justcheck,
 | 
						|
	  LPCWSTR server)
 | 
						|
{
 | 
						|
  WCHAR name[UNLEN + 1], oldpass[512], pass[512];
 | 
						|
  DWORD ret;
 | 
						|
 | 
						|
  mbstowcs (name, user, UNLEN + 1);
 | 
						|
  mbstowcs (pass, pwd, 512);
 | 
						|
  if (! oldpwd)
 | 
						|
    {
 | 
						|
      USER_INFO_1003 ui;
 | 
						|
 | 
						|
      ui.usri1003_password = pass;
 | 
						|
      ret = NetUserSetInfo (server, name, 1003, (LPBYTE) &ui, NULL);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      mbstowcs (oldpass, oldpwd, 512);
 | 
						|
      ret = NetUserChangePassword (server, name, oldpass, pass);
 | 
						|
    }
 | 
						|
  if (justcheck && ret != ERROR_INVALID_PASSWORD)
 | 
						|
    return 0;
 | 
						|
  if (! EvalRet (ret, user) && ! justcheck)
 | 
						|
    {
 | 
						|
      eprint (0, "Password changed.");
 | 
						|
    }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
PrintPW (PUSER_INFO_3 ui, LPCWSTR server)
 | 
						|
{
 | 
						|
  time_t t = time (NULL) - ui->usri3_password_age;
 | 
						|
  int ret;
 | 
						|
  PUSER_MODALS_INFO_0 mi;
 | 
						|
 | 
						|
  printf ("Account disabled           : %s",
 | 
						|
	(ui->usri3_flags & UF_ACCOUNTDISABLE) ? "yes\n" : "no\n");
 | 
						|
  printf ("Password not required      : %s",
 | 
						|
	(ui->usri3_flags & UF_PASSWD_NOTREQD) ? "yes\n" : "no\n");
 | 
						|
  printf ("User can't change password : %s",
 | 
						|
	(ui->usri3_flags & UF_PASSWD_CANT_CHANGE) ? "yes\n" : "no\n");
 | 
						|
  printf ("Password never expires     : %s",
 | 
						|
	(ui->usri3_flags & UF_DONT_EXPIRE_PASSWD) ? "yes\n" : "no\n");
 | 
						|
  printf ("Password expired           : %s",
 | 
						|
	(ui->usri3_password_expired) ? "yes\n" : "no\n");
 | 
						|
  printf ("Latest password change     : %s", ctime(&t));
 | 
						|
  ret = NetUserModalsGet (server, 0, (void *) &mi);
 | 
						|
  if (! ret)
 | 
						|
    {
 | 
						|
      if (mi->usrmod0_max_passwd_age == TIMEQ_FOREVER)
 | 
						|
	mi->usrmod0_max_passwd_age = 0;
 | 
						|
      if (mi->usrmod0_min_passwd_age == TIMEQ_FOREVER)
 | 
						|
	mi->usrmod0_min_passwd_age = 0;
 | 
						|
      if (mi->usrmod0_force_logoff == TIMEQ_FOREVER)
 | 
						|
	mi->usrmod0_force_logoff = 0;
 | 
						|
      if (ui->usri3_priv == USER_PRIV_ADMIN)
 | 
						|
	mi->usrmod0_min_passwd_len = 0;
 | 
						|
      printf ("\nSystem password settings:\n");
 | 
						|
      printf ("Max. password age %ld days\n",
 | 
						|
	      mi->usrmod0_max_passwd_age / ONE_DAY);
 | 
						|
      printf ("Min. password age %ld days\n",
 | 
						|
	      mi->usrmod0_min_passwd_age / ONE_DAY);
 | 
						|
      printf ("Force logout after %ld days\n",
 | 
						|
	      mi->usrmod0_force_logoff / ONE_DAY);
 | 
						|
      printf ("Min. password length: %ld\n",
 | 
						|
	      mi->usrmod0_min_passwd_len);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
SetModals (int xarg, int narg, int iarg, int Larg, LPCWSTR server)
 | 
						|
{
 | 
						|
  int ret;
 | 
						|
  PUSER_MODALS_INFO_0 mi;
 | 
						|
 | 
						|
  ret = NetUserModalsGet (server, 0, (void *) &mi);
 | 
						|
  if (! ret)
 | 
						|
    {
 | 
						|
      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;
 | 
						|
 | 
						|
      ret = NetUserModalsSet (server, 0, (LPBYTE) mi, NULL);
 | 
						|
      NetApiBufferFree (mi);
 | 
						|
    }
 | 
						|
  return EvalRet (ret, NULL);
 | 
						|
}
 | 
						|
 | 
						|
static void usage (FILE * stream, int status) __attribute__ ((noreturn));
 | 
						|
static void
 | 
						|
usage (FILE * stream, int status)
 | 
						|
{
 | 
						|
  fprintf (stream, ""
 | 
						|
  "Usage: %s [OPTION] [USER]\n"
 | 
						|
  "\n"
 | 
						|
  "Change USER's password or password attributes.\n"
 | 
						|
  "\n"
 | 
						|
  "User operations:\n"
 | 
						|
  "  -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"
 | 
						|
  "  -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"
 | 
						|
  "                           (inactive accounts are those with expired passwords).\n"
 | 
						|
  "  -n, --minage DAYS        set system minimum password age to DAYS days.\n"
 | 
						|
  "  -x, --maxage DAYS        set system maximum password age to DAYS days.\n"
 | 
						|
  "  -L, --length LEN         set system minimum password length to LEN.\n"
 | 
						|
  "\n"
 | 
						|
  "Other options:\n"
 | 
						|
  "  -d, --logonserver SERVER connect to SERVER (e.g. domain controller).\n"
 | 
						|
  "                           Default server is the local system, unless\n"
 | 
						|
  "                           changing the current user, in which case the\n"
 | 
						|
  "                           default is the content of $LOGONSERVER.\n"
 | 
						|
  "  -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"
 | 
						|
  "  -V, --version            output version information and exit.\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"
 | 
						|
  "\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\n"
 | 
						|
  "as service under the SYSTEM account.\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", prog_name);
 | 
						|
  exit (status);
 | 
						|
}
 | 
						|
 | 
						|
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};
 | 
						|
  PSID admin_grp;
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
print_version ()
 | 
						|
{
 | 
						|
  printf ("passwd (cygwin) %d.%d.%d\n"
 | 
						|
	  "Password Utility\n"
 | 
						|
	  "Copyright (C) 1999 - %s Red Hat, Inc.\n"
 | 
						|
	  "This is free software; see the source for copying conditions.  There is NO\n"
 | 
						|
	  "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
 | 
						|
	  CYGWIN_VERSION_DLL_MAJOR / 1000,
 | 
						|
	  CYGWIN_VERSION_DLL_MAJOR % 1000,
 | 
						|
	  CYGWIN_VERSION_DLL_MINOR,
 | 
						|
	  strrchr (__DATE__, ' ') + 1);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
main (int argc, char **argv)
 | 
						|
{
 | 
						|
  char *logonserver;
 | 
						|
  char user[UNLEN + 1], oldpwd[_PASSWORD_LEN + 1], newpwd[_PASSWORD_LEN + 1];
 | 
						|
  int ret = 0;
 | 
						|
  int cnt = 0;
 | 
						|
  int opt;
 | 
						|
  int Larg = -1;
 | 
						|
  int xarg = -1;
 | 
						|
  int narg = -1;
 | 
						|
  int iarg = -1;
 | 
						|
  int lopt = 0;
 | 
						|
  int uopt = 0;
 | 
						|
  int copt = 0;
 | 
						|
  int Copt = 0;
 | 
						|
  int eopt = 0;
 | 
						|
  int Eopt = 0;
 | 
						|
  int popt = 0;
 | 
						|
  int Popt = 0;
 | 
						|
  int Sopt = 0;
 | 
						|
  int Ropt = 0;
 | 
						|
  PUSER_INFO_3 ui;
 | 
						|
  int myself = 0;
 | 
						|
  LPWSTR server = NULL;
 | 
						|
 | 
						|
  prog_name = program_invocation_short_name;
 | 
						|
 | 
						|
  /* 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");
 | 
						|
  while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
 | 
						|
    switch (opt)
 | 
						|
      {
 | 
						|
      case 'h':
 | 
						|
	usage (stdout, 0);
 | 
						|
	break;
 | 
						|
 | 
						|
      case 'i':
 | 
						|
	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 || Ropt)
 | 
						|
	  usage (stderr, 1);
 | 
						|
	lopt = 1;
 | 
						|
	break;
 | 
						|
 | 
						|
      case 'n':
 | 
						|
	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.");
 | 
						|
	if (xarg >= 0 && narg > xarg)
 | 
						|
	  return eprint (1, "Minimum password age must be less than "
 | 
						|
			    "maximum password age.");
 | 
						|
	break;
 | 
						|
 | 
						|
      case 'u':
 | 
						|
	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 || Ropt)
 | 
						|
	  usage (stderr, 1);
 | 
						|
	copt = 1;
 | 
						|
	break;
 | 
						|
 | 
						|
      case 'C':
 | 
						|
	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 != '\\')
 | 
						|
	    strcpy (tmpbuf, "\\\\");
 | 
						|
	  strcat (tmpbuf, optarg);
 | 
						|
	  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);
 | 
						|
	}
 | 
						|
	break;
 | 
						|
 | 
						|
      case 'e':
 | 
						|
	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 || Ropt)
 | 
						|
	  usage (stderr, 1);
 | 
						|
	Eopt = 1;
 | 
						|
	break;
 | 
						|
 | 
						|
      case 'p':
 | 
						|
	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 || Ropt)
 | 
						|
	  usage (stderr, 1);
 | 
						|
	Popt = 1;
 | 
						|
	break;
 | 
						|
 | 
						|
      case 'V':
 | 
						|
	print_version ();
 | 
						|
	exit (0);
 | 
						|
	break;
 | 
						|
 | 
						|
      case 'x':
 | 
						|
	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.");
 | 
						|
	if (narg >= 0 && xarg < narg)
 | 
						|
	  return eprint (1, "Maximum password age must be greater than "
 | 
						|
			    "minimum password age.");
 | 
						|
	break;
 | 
						|
 | 
						|
      case 'L':
 | 
						|
	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 "
 | 
						|
			    "0 and %d.", LM20_PWLEN);
 | 
						|
	break;
 | 
						|
 | 
						|
      case 'S':
 | 
						|
	if (xarg >= 0 || narg >= 0 || iarg >= 0 || Larg >= 0 || lopt || uopt
 | 
						|
	    || 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:
 | 
						|
	fprintf (stderr, "Try `%s --help' for more information.\n", prog_name);
 | 
						|
	return 1;
 | 
						|
      }
 | 
						|
 | 
						|
  if (Ropt)
 | 
						|
    {
 | 
						|
      const char *username = NULL;
 | 
						|
      if (optind < argc)
 | 
						|
	{
 | 
						|
	  username = argv[optind++];
 | 
						|
	  if (!strcmp (username, getlogin ()))
 | 
						|
	    username = NULL;
 | 
						|
	  else if (!caller_is_admin ())
 | 
						|
	    return eprint (0, "You may not change the password for %s.", user);
 | 
						|
 | 
						|
	  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" : "");
 | 
						|
      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.\n\n"
 | 
						|
"You can delete the stored password by specifying an empty password.\n\n");
 | 
						|
      strcpy (newpwd, getpass (text1));
 | 
						|
      if (strcmp (newpwd, getpass (text2)))
 | 
						|
	eprint (0, "Password is not identical.");
 | 
						|
      else if (cygwin_internal (CW_SET_PRIV_KEY, newpwd, username))
 | 
						|
	return eprint (0, "Storing password failed: %s", strerror (errno));
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
  if (Larg >= 0 || xarg >= 0 || narg >= 0 || iarg >= 0)
 | 
						|
    {
 | 
						|
      if (optind < argc)
 | 
						|
	usage (stderr, 1);
 | 
						|
      return SetModals (xarg, narg, iarg, Larg, server);
 | 
						|
    }
 | 
						|
 | 
						|
  strcpy (user, optind >= argc ? getlogin () : argv[optind]);
 | 
						|
 | 
						|
  /* Changing password for calling user?  Use logonserver for user as well. */
 | 
						|
  if (!server && optind >= argc)
 | 
						|
    {
 | 
						|
      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);
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  ui = GetPW (user, 1, server);
 | 
						|
  if (! ui)
 | 
						|
    return 1;
 | 
						|
 | 
						|
  if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt || Sopt)
 | 
						|
    {
 | 
						|
      USER_INFO_1008 uif;
 | 
						|
 | 
						|
      uif.usri1008_flags = ui->usri3_flags;
 | 
						|
      if (lopt)
 | 
						|
	{
 | 
						|
	  if (ui->usri3_priv == USER_PRIV_ADMIN)
 | 
						|
	    return eprint (0, "Locking an admin account is disallowed.");
 | 
						|
	  uif.usri1008_flags |= UF_ACCOUNTDISABLE;
 | 
						|
	}
 | 
						|
      if (uopt)
 | 
						|
	uif.usri1008_flags &= ~UF_ACCOUNTDISABLE;
 | 
						|
      if (copt)
 | 
						|
	uif.usri1008_flags |= UF_PASSWD_CANT_CHANGE;
 | 
						|
      if (Copt)
 | 
						|
	uif.usri1008_flags &= ~UF_PASSWD_CANT_CHANGE;
 | 
						|
      if (eopt)
 | 
						|
	uif.usri1008_flags |= UF_DONT_EXPIRE_PASSWD;
 | 
						|
      if (Eopt)
 | 
						|
	uif.usri1008_flags &= ~UF_DONT_EXPIRE_PASSWD;
 | 
						|
      if (popt)
 | 
						|
	uif.usri1008_flags |= UF_PASSWD_NOTREQD;
 | 
						|
      if (Popt)
 | 
						|
	uif.usri1008_flags &= ~UF_PASSWD_NOTREQD;
 | 
						|
 | 
						|
      if (lopt || uopt || copt || Copt || eopt || Eopt || popt || Popt)
 | 
						|
	{
 | 
						|
	  ret = NetUserSetInfo (server, ui->usri3_name, 1008, (LPBYTE) &uif,
 | 
						|
				NULL);
 | 
						|
	  return EvalRet (ret, NULL);
 | 
						|
	}
 | 
						|
      // Sopt
 | 
						|
      PrintPW (ui, server);
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
  if (!caller_is_admin () && !myself)
 | 
						|
    return eprint (0, "You may not change the password for %s.", user);
 | 
						|
 | 
						|
  eprint (0, "Enter the new password (minimum of 5, maximum of 8 characters).");
 | 
						|
  eprint (0, "Please use a combination of upper and lower case letters and numbers.");
 | 
						|
 | 
						|
  oldpwd[0] = '\0';
 | 
						|
  if (!caller_is_admin ())
 | 
						|
    {
 | 
						|
      strcpy (oldpwd, getpass ("Old password: "));
 | 
						|
      if (ChangePW (user, oldpwd, oldpwd, 1, server))
 | 
						|
	return 1;
 | 
						|
    }
 | 
						|
 | 
						|
  do
 | 
						|
    {
 | 
						|
      strcpy (newpwd, getpass ("New password: "));
 | 
						|
      if (strcmp (newpwd, getpass ("Re-enter new password: ")))
 | 
						|
	eprint (0, "Password is not identical.");
 | 
						|
      else if (! ChangePW (user, *oldpwd ? oldpwd : NULL, newpwd, 0, server))
 | 
						|
	ret = 1;
 | 
						|
      if (! ret && cnt < 2)
 | 
						|
	eprint (0, "Try again.");
 | 
						|
    }
 | 
						|
  while (! ret && ++cnt < 3);
 | 
						|
  return ! ret;
 | 
						|
}
 |