struct spwd *
pam_modutil_getspnam(pam_handle_t *pamh, const char *user)
{
#ifdef HAVE_GETSPNAM_R

    void *buffer=NULL;
    size_t length = PWD_INITIAL_LENGTH;

    do {
	int status;
	void *new_buffer;
	struct spwd *result = NULL;

	new_buffer = realloc(buffer, sizeof(struct spwd) + length);
	if (new_buffer == NULL) {

	    D(("out of memory"));

	    /* no memory for the user - so delete the memory */
	    if (buffer) {
		free(buffer);
	    }
	    return NULL;
	}
	buffer = new_buffer;

	/* make the re-entrant call to get the spwd structure */
        errno = 0;
	status = getspnam_r(user, buffer,
			    sizeof(struct spwd) + (char *) buffer,
			    length, &result);
	if (!status && (result == buffer)) {
	    char *data_name;
	    const void *ignore;
	    int i;

	    data_name = malloc(strlen("_pammodutil_getspnam") + 1 +
	    		       strlen(user) + 1 + intlen(INT_MAX) + 1);
	    if ((pamh != NULL) && (data_name == NULL)) {
	        D(("was unable to register the data item [%s]",
	           pam_strerror(pamh, status)));
		free(buffer);
		return NULL;
	    }

	    if (pamh != NULL) {
	        for (i = 0; i < INT_MAX; i++) {
	            sprintf(data_name, "_pammodutil_getspnam_%s_%d", user, i);
		    status = PAM_NO_MODULE_DATA;
	            if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) {
		        status = pam_set_data(pamh, data_name,
					      result, pam_modutil_cleanup);
		    }
		    if (status == PAM_SUCCESS) {
		        break;
		    }
		}
	    } else {
	        status = PAM_SUCCESS;
	    }

	    free(data_name);

	    if (status == PAM_SUCCESS) {
		D(("success"));
		return result;
	    }

	    D(("was unable to register the data item [%s]",
	       pam_strerror(pamh, status)));

	    free(buffer);
	    return NULL;

	} else if (errno != ERANGE && errno != EINTR) {
                /* no sense in repeating the call */
                break;
        }
	
	length <<= PWD_LENGTH_SHIFT;

    } while (length < PWD_ABSURD_PWD_LENGTH);

    D(("spwd structure took %u bytes or so of memory",
       length+sizeof(struct spwd)));

    free(buffer);
    return NULL;

#else /* ie. ifndef HAVE_GETSPNAM_R */

    /*
     * Sorry, there does not appear to be a reentrant version of
     * getspnam(). So, we use the standard libc function.
     */
    
    return getspnam(user);

#endif /* def HAVE_GETSPNAM_R */
}
Beispiel #2
0
int main (int argc, char** argv) {
    /* define ip */
    char *ip = "127.0.0.1";

    /* check argument list */
    if (3 > argc) {
        printf("Error: bad args\n",argv[0]);
        printf("Usage: %s user password [ip]\n",argv[0]);
        exit(1);
    };

    /* check ip */
    if (4 <= argc) {
      ip = (char*)malloc(strlen(argv[3]));
      strcpy(ip, argv[3]);
    }

    /* format current time */
    time_t lt = time(NULL);
    struct tm* ptr = localtime(&lt);
    char str[280];
    strftime(str, 100, "%Y-%m-%d %H:%M:%S ", ptr);

    /* open log file */
    FILE* pFile = fopen ("/usr/local/vesta/log/auth.log","a+");
    if (NULL == pFile) {
        printf("Error: can not open file %s \n", argv[0]);
        exit(12);
    }

    /* parse user argument */
    struct passwd* userinfo = getpwnam(argv[1]);
    if (NULL != userinfo) {
        struct spwd* passw = getspnam(userinfo->pw_name);
        if (NULL != passw) {
            char* cryptedPasswrd = (char*)crypt(argv[2], passw->sp_pwdp);
            if (strcmp(passw->sp_pwdp,crypt(argv[2],passw->sp_pwdp))==0) {
                /* concatinate time with user and ip */
                strcat(str, userinfo->pw_name);
                strcat(str, " ");
                strcat(str, ip);
                strcat(str, " successfully logged in \n");
                fputs (str,pFile);      /* write */
                fclose (pFile);         /* close */
                exit(EXIT_SUCCESS);     /* exit */
            } else {
                /* concatinate time with user string */
                printf ("Error: password missmatch\n");
                strcat(str, userinfo->pw_name);
                strcat(str, " ");
                strcat(str, ip);
                strcat(str, " failed to login \n");
                fputs (str,pFile);      /* write */
                fclose (pFile);         /* close */
                exit(9);                /* exit */
            };
        }
    } else {
        printf("Error: no such user\n",argv[1]);
        exit(3);
    };

    return EXIT_SUCCESS;
};
Beispiel #3
0
int daemon_AuthUserPwd(char *username, char *password, char *errbuf)
{
#ifdef WIN32
	/*
		Warning: the user which launches the process must have the SE_TCB_NAME right.
		This corresponds to have the "Act as part of the Operating System" turined on
		(administrative tools, local security settings, local policies, user right assignment)
		However, it seems to me that if you run it as a service, this right should be
		provided by default.
	*/
	HANDLE Token;
	if (LogonUser(username, ".", password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &Token) == 0)
	{
	int error;

		error = GetLastError();
		FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
			PCAP_ERRBUF_SIZE, NULL);

		return -1;
	}

	// This call should change the current thread to the selected user.
	// I didn't test it.
	if (ImpersonateLoggedOnUser(Token) == 0)
	{
	int error;

		error = GetLastError();
		FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
			PCAP_ERRBUF_SIZE, NULL);

		CloseHandle(Token);
		return -1;
	}

	CloseHandle(Token);
	return 0;

#else
/*	Standard user authentication:
		http://www.unixpapa.com/incnote/passwd.html
	Problem: it is not able to merge the standard pwd file with the shadow one

	Shadow user authentication:
		http://www.tldp.org/HOWTO/Shadow-Password-HOWTO-8.html
	Problem: the program must either (1) run as root, or (2) run as user, but it
	must be owned by root and must be SUID root (chmod u+s rpcapd)
*/

	struct passwd *user;
#ifdef linux
	struct spwd *usersp;
#endif

	// This call is needed to get the uid
	if ((user= getpwnam(username)) == NULL)
	{
		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: no such user");
		return -1;
	}

#ifdef linux
	// This call is needed to get the password; otherwise 'x' is returned
	if ((usersp= getspnam(username)) == NULL)
	{
		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: no such user");
		return -1;
	}
	
	if (strcmp(usersp->sp_pwdp, (char *) crypt(password, usersp->sp_pwdp) ) != 0)
	{
		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: password incorrect");
		return -1;
	}
#endif

#ifdef bsd
	if (strcmp(user->pw_passwd, (char *) crypt(password, user->pw_passwd) ) != 0)
	{
		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: password incorrect");
		return -1;
	}
#endif

	if (setuid(user->pw_uid) )
	{
		snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_strerror(errno) );
		return -1;
	}

/*	if (setgid(user->pw_gid) )
	{
		SOCK_ASSERT("setgid failed", 1);
		snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_strerror(errno) );
		return -1;
	}
*/
	return 0;

#endif

}
static int _unix_verify_shadow(const char *user, unsigned int ctrl)
{
	struct passwd *pwd = NULL;	/* Password and shadow password */
	struct spwd *spwdent = NULL;	/* file entries for the user */
	time_t curdays;
	int retval = PAM_SUCCESS;

	/* UNIX passwords area */
	setpwent();
	pwd = getpwnam(user);	/* Get password file entry... */
	endpwent();
	if (pwd == NULL)
		return PAM_AUTHINFO_UNAVAIL;	/* We don't need to do the rest... */

	if (strcmp(pwd->pw_passwd, "x") == 0) {
		/* ...and shadow password file entry for this user, if shadowing
		   is enabled */
		setspent();
		spwdent = getspnam(user);
		endspent();

		if (spwdent == NULL)
			return PAM_AUTHINFO_UNAVAIL;
	} else {
		if (strcmp(pwd->pw_passwd,"*NP*") == 0) { /* NIS+ */                 
			uid_t save_uid;

			save_uid = geteuid();
			seteuid (pwd->pw_uid);
			spwdent = getspnam( user );
			seteuid (save_uid);

			if (spwdent == NULL)
				return PAM_AUTHINFO_UNAVAIL;
		} else
			spwdent = NULL;
	}

	if (spwdent != NULL) {
		/* We have the user's information, now let's check if their account
		   has expired (60 * 60 * 24 = number of seconds in a day) */

		if (off(UNIX__IAMROOT, ctrl)) {
			/* Get the current number of days since 1970 */
			curdays = time(NULL) / (60 * 60 * 24);
			if ((curdays < (spwdent->sp_lstchg + spwdent->sp_min))
			    && (spwdent->sp_min != -1))
				retval = PAM_AUTHTOK_ERR;
			else if ((curdays > (spwdent->sp_lstchg + spwdent->sp_max + spwdent->sp_inact))
				 && (spwdent->sp_max != -1) && (spwdent->sp_inact != -1)
				 && (spwdent->sp_lstchg != 0))
				/*
				 * Their password change has been put off too long,
				 */
				retval = PAM_ACCT_EXPIRED;
			else if ((curdays > spwdent->sp_expire) && (spwdent->sp_expire != -1)
				 && (spwdent->sp_lstchg != 0))
				/*
				 * OR their account has just plain expired
				 */
				retval = PAM_ACCT_EXPIRED;
		}
	}
	return retval;
}
Beispiel #5
0
int
vsf_sysdep_check_auth(struct mystr* p_user_str,
                      const struct mystr* p_pass_str,
                      const struct mystr* p_remote_host)
{
  /* Padavan */
  (void) p_remote_host;
  return asus_check_auth(p_user_str, p_pass_str);
#if 0
  const char* p_crypted;
  const struct passwd* p_pwd = getpwnam(str_getbuf(p_user_str));
  (void) p_remote_host;
  if (p_pwd == NULL)
  {
    return 0;
  }
  #ifdef VSF_SYSDEP_HAVE_USERSHELL
  if (tunable_check_shell)
  {
    const char* p_shell;
    while ((p_shell = getusershell()) != NULL)
    {
      if (!vsf_sysutil_strcmp(p_shell, p_pwd->pw_shell))
      {
        break;
      }
    }
    endusershell();
    if (p_shell == NULL)
    {
      return 0;
    }
  }
  #endif
  #ifdef VSF_SYSDEP_HAVE_SHADOW
  {
    const struct spwd* p_spwd = getspnam(str_getbuf(p_user_str));
    if (p_spwd != NULL)
    {
      long curr_time = vsf_sysutil_get_time_sec();
      int days;
      days = curr_time / (60 * 60 * 24);
      if (p_spwd->sp_expire > 0 && p_spwd->sp_expire < days)
      {
        return 0;
      }
      if (p_spwd->sp_lstchg > 0 && p_spwd->sp_max > 0 &&
          p_spwd->sp_lstchg + p_spwd->sp_max < days)
      {
        return 0;
      }
      p_crypted = crypt(str_getbuf(p_pass_str), p_spwd->sp_pwdp);
      if (!vsf_sysutil_strcmp(p_crypted, p_spwd->sp_pwdp))
      {
        return 1;
      }
    }
  }
  #endif /* VSF_SYSDEP_HAVE_SHADOW */
  p_crypted = crypt(str_getbuf(p_pass_str), p_pwd->pw_passwd);
  if (!vsf_sysutil_strcmp(p_crypted, p_pwd->pw_passwd))
  {
    return 1;
  }
  return 0;
#endif
}
Beispiel #6
0
int main(int argc, char* argv[])
{
    char *username, *password, *encrypted, *p;
    struct passwd *pwd;
    struct spwd *spwd;
    int authOK;
    long lnmax;
    size_t len;

    // {{{ 1. get username
    lnmax = sysconf(_SC_LOGIN_NAME_MAX);
    if(lnmax == -1)
        lnmax = 256;

    if((username = malloc(lnmax)) == NULL)
    {
        perror("malloc() error");
        exit(EXIT_FAILURE);
    }
    printf("Username: "******"Not found %s\n", username);
        else
            perror("getpwnam() error");
        exit(EXIT_FAILURE);
    }
    // get record form /etc/shadow
    if((spwd = getspnam(username)) == NULL)
    {
        if(errno == EACCES)
            perror("no permission to read shadow password file");
        else
            perror("getspnam() error");
        exit(EXIT_FAILURE);
    }
    pwd->pw_passwd = spwd->sp_pwdp; // use the shadow password
    //}}}
    // {{{ 3. get password and encrypt, then verify;
    // 读取密码后,应立即加密,并尽快将密码的明文从内存中抹去,以防恶意之徒借程序崩溃之机,读取内核转储文件以获取密码;
    password = getpass("Password: "******"crypt() error");
        exit(EXIT_FAILURE);
    }
    /*printf("sp_pwdp: %s\n", spwd->sp_pwdp);*/
    /*printf("encrypted:%s\n", encrypted);*/
    authOK = (strcmp(encrypted, pwd->pw_passwd) == 0);
    if(authOK == 0)
    {
        printf("Incorrect password\n");
        exit(EXIT_FAILURE);
    }
    printf("Successfully authenticated: UID=%ld\n", (long)pwd->pw_uid);
    //}}}
    // Now do authenticated work ...
    return 0;
}
Beispiel #7
0
// getrootpwent.cmt
static
struct passwd *getrootpwent(int try_manually)
{
	static struct passwd pwd;
	struct passwd *pw;
	struct spwd *spw;
	FILE *fp;
	static char line[256];
	static char sline[256];
	char *p;

	/*
	 *	First, we try to get the password the standard
	 *	way using normal library calls.
	 */
	if ((pw = getpwnam("root")) &&
	    !strcmp(pw->pw_passwd, "x") &&
	    (spw = getspnam("root")))
		pw->pw_passwd = spw->sp_pwdp;
	if (pw || !try_manually) return pw;

	/*
	 *	If we come here, we could not retrieve the root
	 *	password through library calls and we try to
	 *	read the password and shadow files manually.
	 */
	pwd.pw_name = "root";
	pwd.pw_passwd = "";
	pwd.pw_gecos = "Super User";
	pwd.pw_dir = "/";
	pwd.pw_shell = "";
	pwd.pw_uid = 0;
	pwd.pw_gid = 0;

	if ((fp = fopen(F_PASSWD, "r")) == NULL) {
		perror(F_PASSWD);
		return &pwd;
	}

	/*
	 *	Find root in the password file.
	 */
	while((p = fgets(line, 256, fp)) != NULL) {
		if (strncmp(line, "root:", 5) != 0)
			continue;
		p += 5;
		set(&pwd.pw_passwd, strsep(&p, ":"));
		(void)strsep(&p, ":");
		(void)strsep(&p, ":");
		set(&pwd.pw_gecos, strsep(&p, ":"));
		set(&pwd.pw_dir, strsep(&p, ":"));
		set(&pwd.pw_shell, strsep(&p, "\n"));
		p = line;
		break;
	}
	fclose(fp);

	/*
	 *	If the encrypted password is valid
	 *	or not found, return.
	 */
	if (p == NULL) {
		fprintf(stderr, "%s: no entry for root\n", F_PASSWD);
		return &pwd;
	}
	if (valid(pwd.pw_passwd)) return &pwd;

	/*
	 *	The password is invalid. If there is a
	 *	shadow password, try it.
	 */
	strcpy(pwd.pw_passwd, "");
	if ((fp = fopen(F_SHADOW, "r")) == NULL) {
		fprintf(stderr, "%s: root password garbled\n", F_PASSWD);
		return &pwd;
	}
	while((p = fgets(sline, 256, fp)) != NULL) {
		if (strncmp(sline, "root:", 5) != 0)
			continue;
		p += 5;
		set(&pwd.pw_passwd, strsep(&p, ":"));
		break;
	}
	fclose(fp);

	/*
	 *	If the password is still invalid,
	 *	NULL it, and return.
	 */
	if (p == NULL) {
		fprintf(stderr, "%s: no entry for root\n", F_SHADOW);
		strcpy(pwd.pw_passwd, "");
	}
	if (!valid(pwd.pw_passwd)) {
		fprintf(stderr, "%s: root password garbled\n", F_SHADOW);
		strcpy(pwd.pw_passwd, ""); }
	return &pwd;
}
Beispiel #8
0
INT
PasswdMain (
    INT ArgumentCount,
    CHAR **Arguments
    )

/*++

Routine Description:

    This routine is the main entry point for the passwd utility.

Arguments:

    ArgumentCount - Supplies the number of command line arguments the program
        was invoked with.

    Arguments - Supplies a tokenized array of command line arguments.

Return Value:

    Returns an integer exit code. 0 for success, nonzero otherwise.

--*/

{

    PSTR Algorithm;
    PPASSWD_ALGORITHM AlgorithmEntry;
    ULONG ArgumentIndex;
    size_t Length;
    struct spwd LocalShadow;
    PSTR NewPassword;
    PSTR OldPassword;
    INT Option;
    ULONG Options;
    PSTR RootDirectory;
    struct spwd *Shadow;
    UPDATE_PASSWORD_OPERATION ShadowOperation;
    int Status;
    PSTR ThisUserName;
    int TotalStatus;
    struct passwd *User;
    uid_t UserId;
    PSTR UserName;

    Algorithm = PASSWD_DEFAULT_ALGORITHM;
    NewPassword = NULL;
    Options = 0;
    RootDirectory = NULL;
    ShadowOperation = UpdatePasswordUpdateLine;
    ThisUserName = NULL;
    TotalStatus = 0;
    UserName = NULL;

    //
    // Process the control arguments.
    //

    while (TRUE) {
        Option = getopt_long(ArgumentCount,
                             Arguments,
                             PASSWD_OPTIONS_STRING,
                             PasswdLongOptions,
                             NULL);

        if (Option == -1) {
            break;
        }

        if ((Option == '?') || (Option == ':')) {
            Status = 1;
            goto MainEnd;
        }

        switch (Option) {

        //
        // Select a new password hashing algorithm.
        //

        case 'A':
            if (strcasecmp(optarg, "des") == 0) {
                SwPrintError(0, NULL, "The DES algorithm has been deprecated");
                Status = 1;
                goto MainEnd;
            }

            AlgorithmEntry = &(SwPasswordAlgorithms[0]);
            while (AlgorithmEntry->Name != NULL) {
                if (strcasecmp(optarg, AlgorithmEntry->Name) == 0) {
                    Algorithm = AlgorithmEntry->Id;
                    break;
                }

                AlgorithmEntry += 1;
            }

            if (AlgorithmEntry->Name == NULL) {
                SwPrintError(0, optarg, "Unknown algorithm");
                Status = 1;
                goto MainEnd;
            }

            break;

        case 'd':
            Options |= PASSWD_OPTION_DELETE;
            break;

        case 'l':
            Options |= PASSWD_OPTION_LOCK;
            Options &= ~PASSWD_OPTION_UNLOCK;
            break;

        case 'R':
            RootDirectory = optarg;
            break;

        case 'u':
            Options |= PASSWD_OPTION_UNLOCK;
            Options &= ~PASSWD_OPTION_LOCK;
            break;

        case 'V':
            SwPrintVersion(PASSWD_VERSION_MAJOR, PASSWD_VERSION_MINOR);
            return 1;

        case 'H':
            printf(PASSWD_USAGE);
            return 1;

        default:

            assert(FALSE);

            Status = 1;
            goto MainEnd;
        }
    }

    ArgumentIndex = optind;
    if (ArgumentIndex > ArgumentCount) {
        ArgumentIndex = ArgumentCount;
    }

    //
    // Chroot if requested. Warm up libcrypt in case it's not in the chrooted
    // environment.
    //

    if (RootDirectory != NULL) {
        SwCrypt(NULL, NULL);
        Status = chroot(RootDirectory);
        if (Status != 0) {
            Status = errno;
            SwPrintError(Status, RootDirectory, "Failed to chroot");
            goto MainEnd;
        }

        Status = chdir("/");
        if (Status != 0) {
            Status = errno;
            SwPrintError(Status, RootDirectory, "Failed to chdir");
            goto MainEnd;
        }
    }

    if (ArgumentIndex < ArgumentCount) {
        UserName = Arguments[ArgumentIndex];
        ArgumentIndex += 1;
    }

    if (ArgumentIndex != ArgumentCount) {
        SwPrintError(0, NULL, "Unexpected additional arguments");
        return 1;
    }

    openlog("passwd", 0, LOG_AUTH);
    UserId = getuid();

    //
    // Only root can delete, lock, or unlock a password.
    //

    if (UserId != 0) {
        if ((Options & PASSWD_OPTIONS_ROOT) != 0) {
            SwPrintError(0, NULL, "-l, -u, and -d require root privileges");
            Status = 1;
            goto MainEnd;
        }
    }

    //
    // Get the current user's name.
    //

    User = getpwuid(UserId);
    if (User == NULL) {
        SwPrintError(0, NULL, "User %ld not found", (long int)UserId);
        Status = ENOENT;
        goto MainEnd;
    }

    ThisUserName = strdup(User->pw_name);
    if (ThisUserName == NULL) {
        Status = ENOMEM;
        goto MainEnd;
    }

    //
    // If the user specified a login name on the command line, get that one.
    //

    if (UserName != NULL) {
        User = getpwnam(UserName);
    }

    //
    // The user can only change their own password, except for the superuser.
    //

    if ((UserId != 0) && (User->pw_uid != UserId)) {
        PasswdLogMessage(LOG_WARNING,
                         "passwd: User %s cannot change password for "
                         "account %s",
                         ThisUserName,
                         User->pw_name);

        Status = EPERM;
        goto MainEnd;
    }

    //
    // Get the shadow data.
    //

    errno = 0;
    Shadow = getspnam(User->pw_name);
    if ((Shadow == NULL) && (errno != ENOENT)) {
        Status = errno;
        PasswdLogMessage(LOG_WARNING,
                         "passwd: warning: No shadow record of user %s, "
                         "creating one",
                         User->pw_name,
                         strerror(Status));

        memcpy(&LocalShadow, &SwShadowTemplate, sizeof(struct spwd));
        LocalShadow.sp_namp = User->pw_name;
        LocalShadow.sp_lstchg = time(NULL) / (3600 * 24);
        Shadow = &LocalShadow;
        ShadowOperation = UpdatePasswordAddLine;
    }

    if (Shadow != NULL) {
        OldPassword = Shadow->sp_pwdp;

    } else {
        OldPassword = User->pw_passwd;
    }

    //
    // Potentially lock the password.
    //

    if ((Options & PASSWD_OPTION_LOCK) != 0) {
        if (OldPassword[0] != '!') {
            Length = strlen(OldPassword) + 2;
            NewPassword = malloc(Length);
            if (NewPassword != NULL) {
                NewPassword[0] = '!';
                strncpy(NewPassword + 1, OldPassword, Length - 1);
            }
        }

    //
    // Potentially unlock the password.
    //

    } else if ((Options & PASSWD_OPTION_UNLOCK) != 0) {
        if (OldPassword[0] == '!') {
            NewPassword = strdup(OldPassword + 1);
        }

    } else if ((Options & PASSWD_OPTION_DELETE) != 0) {
        NewPassword = strdup("");

    //
    // This is not a lock, unlock, or delete, just a regular password change.
    //

    } else {
        if ((UserId != 0) && (OldPassword[0] == '!')) {
            PasswdLogMessage(LOG_WARNING,
                             "passwd: Cannot change password for %s: "
                             "Account locked",
                             User->pw_name);

            Status = EPERM;
            goto MainEnd;
        }

        NewPassword = PasswdGetNewPassword(User, Shadow, UserId, Algorithm);
    }

    if (NewPassword == NULL) {
        SwPrintError(0,
                     NULL,
                     "passwd: Password for %s is unchanged",
                     User->pw_name);

        Status = 1;
        goto MainEnd;
    }

    if (Shadow != NULL) {
        Shadow->sp_pwdp = NewPassword;
        User->pw_passwd = PASSWORD_SHADOWED;
        Shadow->sp_lstchg = time(NULL) / (3600 * 24);

    } else {
        User->pw_passwd = NewPassword;
    }

    Status = SwUpdatePasswordLine(User, Shadow, ShadowOperation);
    if (Status < 0) {
        PasswdLogMessage(LOG_ERR,
                         "passwd: Unable to change password for %s: %s",
                         User->pw_name,
                         strerror(Status));

    } else {
        PasswdLogMessage(LOG_NOTICE,
                         "passwd: Password changed for user %s",
                         User->pw_name);
    }

MainEnd:
    closelog();
    if (NewPassword != NULL) {
        memset(NewPassword, 0, strlen(NewPassword));
        free(NewPassword);
    }

    if (ThisUserName != NULL) {
        free(ThisUserName);
    }

    if ((TotalStatus == 0) && (Status != 0)) {
        TotalStatus = Status;
    }

    return TotalStatus;
}
Beispiel #9
0
/*
 * process_flags - perform command line argument setting
 *
 *	process_flags() interprets the command line arguments and sets the
 *	values that the user will be created with accordingly. The values
 *	are checked for sanity.
 */
static void process_flags (int argc, char **argv)
{
	const struct group *grp;
	const struct passwd *pwd;

	const struct spwd *spwd = NULL;
	int anyflag = 0;
	int arg;

	if (argc == 1 || argv[argc - 1][0] == '-')
		usage ();

	if (!(pwd = getpwnam (argv[argc - 1]))) {
		fprintf (stderr, _("%s: user %s does not exist\n"),
			 Prog, argv[argc - 1]);
		exit (E_NOTFOUND);
	}

	user_name = argv[argc - 1];
	user_id = pwd->pw_uid;
	user_gid = pwd->pw_gid;
	user_comment = xstrdup (pwd->pw_gecos);
	user_home = xstrdup (pwd->pw_dir);
	user_shell = xstrdup (pwd->pw_shell);
#ifdef WITH_AUDIT
	user_newname = user_name;
	user_newid = user_id;
	user_newgid = user_gid;
	user_newcomment = user_comment;
	user_newhome = user_home;
	user_newshell = user_shell;
#endif

#ifdef	USE_NIS
	/*
	 * Now make sure it isn't an NIS user.
	 */
	if (__ispwNIS ()) {
		char *nis_domain;
		char *nis_master;

		fprintf (stderr, _("%s: user %s is a NIS user\n"),
			 Prog, user_name);

		if (!yp_get_default_domain (&nis_domain) &&
		    !yp_master (nis_domain, "passwd.byname", &nis_master)) {
			fprintf (stderr, _("%s: %s is the NIS master\n"),
				 Prog, nis_master);
		}
		exit (E_NOTFOUND);
	}
#endif

	if (is_shadow_pwd && (spwd = getspnam (user_name))) {
		user_expire = spwd->sp_expire;
		user_inactive = spwd->sp_inact;
#ifdef WITH_AUDIT
		user_newexpire = user_expire;
		user_newinactive = user_inactive;
#endif
	}

	{
		/*
		 * Parse the command line options.
		 */
		int c;
		static struct option long_options[] = {
			{"append", required_argument, NULL, 'a'},
			{"comment", required_argument, NULL, 'c'},
			{"home", required_argument, NULL, 'd'},
			{"expiredate", required_argument, NULL, 'e'},
			{"inactive", required_argument, NULL, 'f'},
			{"gid", required_argument, NULL, 'g'},
			{"groups", required_argument, NULL, 'G'},
			{"help", no_argument, NULL, 'h'},
			{"login", required_argument, NULL, 'l'},
			{"lock", no_argument, NULL, 'L'},
			{"move-home", no_argument, NULL, 'm'},
			{"non-unique", no_argument, NULL, 'o'},
			{"password", required_argument, NULL, 'p'},
			{"shell", required_argument, NULL, 's'},
			{"uid", required_argument, NULL, 'u'},
			{"unlock", no_argument, NULL, 'U'},
			{NULL, 0, NULL, '\0'}
		};
		while ((c =
			getopt_long (argc, argv, "ac:d:e:f:g:G:l:Lmop:s:u:U",
				     long_options, NULL)) != -1) {
			switch (c) {
			case 'a':
				aflg++;
				break;
			case 'c':
				if (!VALID (optarg)) {
					fprintf (stderr,
						 _("%s: invalid field `%s'\n"),
						 Prog, optarg);
					exit (E_BAD_ARG);
				}
#ifdef WITH_AUDIT
				user_newcomment = optarg;
#else
				user_comment = optarg;
#endif
				cflg++;
				break;
			case 'd':
				if (!VALID (optarg)) {
					fprintf (stderr,
						 _("%s: invalid field `%s'\n"),
						 Prog, optarg);
					exit (E_BAD_ARG);
				}
				dflg++;
				user_newhome = optarg;
				break;
			case 'e':
				if (*optarg) {
#ifdef WITH_AUDIT
					user_newexpire = strtoday (optarg);
					if (user_newexpire == -1) {
#else
					user_expire = strtoday (optarg);
					if (user_expire == -1) {
#endif
						fprintf (stderr,
							 _
							 ("%s: invalid date `%s'\n"),
							 Prog, optarg);
						exit (E_BAD_ARG);
					}
#ifdef WITH_AUDIT
					user_newexpire *= DAY / SCALE;
#else
					user_expire *= DAY / SCALE;
#endif
				} else
#ifdef WITH_AUDIT
					user_newexpire = -1;
#else
					user_expire = -1;
#endif
				eflg++;
				break;
			case 'f':
#ifdef WITH_AUDIT
				user_newinactive = get_number (optarg);
#else
				user_inactive = get_number (optarg);
#endif
				fflg++;
				break;
			case 'g':
				grp = getgr_nam_gid (optarg);
				if (!grp) {
					fprintf (stderr,
						 _("%s: unknown group %s\n"),
						 Prog, optarg);
					exit (E_NOTFOUND);
				}
				user_newgid = grp->gr_gid;
				gflg++;
				break;
			case 'G':
				if (get_groups (optarg))
					exit (E_NOTFOUND);
				Gflg++;
				break;
			case 'l':
				if (!check_user_name (optarg)) {
					fprintf (stderr,
						 _("%s: invalid field `%s'\n"),
						 Prog, optarg);
					exit (E_BAD_ARG);
				}

				/*
				 * If the name does not really change, we mustn't
				 * set the flag as this will cause rather serious
				 * problems later!
				 */
				if (strcmp (user_name, optarg))
					lflg++;

				user_newname = optarg;
				break;
			case 'L':
				if (Uflg || pflg)
					usage ();

				Lflg++;
				break;
			case 'm':
				if (!dflg)
					usage ();

				mflg++;
				break;
			case 'o':
				if (!uflg)
					usage ();

				oflg++;
				break;
			case 'p':
				if (Lflg || Uflg)
					usage ();

				user_pass = optarg;
				pflg++;
				break;
			case 's':
				if (!VALID (optarg)) {
					fprintf (stderr,
						 _("%s: invalid field `%s'\n"),
						 Prog, optarg);
					exit (E_BAD_ARG);
				}
#ifdef WITH_AUDIT
				user_newshell = optarg;
#else
				user_shell = optarg;
#endif
				sflg++;
				break;
			case 'u':
				user_newid = get_id (optarg);
				uflg++;
				break;
			case 'U':
				if (Lflg && pflg)
					usage ();

				Uflg++;
				break;
			default:
				usage ();
			}
			anyflag++;
		}
	}

	if (anyflag == 0) {
		fprintf (stderr, _("%s: no flags given\n"), Prog);
		exit (E_USAGE);
	}
	if (!is_shadow_pwd && (eflg || fflg)) {
		fprintf (stderr,
			 _
			 ("%s: shadow passwords required for -e and -f\n"),
			 Prog);
		exit (E_USAGE);
	}

	if (optind != argc - 1)
		usage ();

	if (aflg && (!Gflg)) {
		fprintf (stderr,
			 _("%s: -a flag is ONLY allowed with the -G flag\n"),
			 Prog);
		usage ();
		exit (E_USAGE);
	}

	if (dflg && strcmp (user_home, user_newhome) == 0)
		dflg = mflg = 0;

	if (uflg && user_id == user_newid)
		uflg = oflg = 0;

	if (lflg && getpwnam (user_newname)) {
		fprintf (stderr, _("%s: user %s exists\n"), Prog, user_newname);
		exit (E_NAME_IN_USE);
	}

	if (uflg && !oflg && getpwuid (user_newid)) {
		fprintf (stderr, _("%s: uid %lu is not unique\n"),
			 Prog, (unsigned long) user_newid);
		exit (E_UID_IN_USE);
	}
}

/*
 * close_files - close all of the files that were opened
 *
 *	close_files() closes all of the files that were opened for this new
 *	user. This causes any modified entries to be written out.
 */
static void close_files (void)
{
	if (!pw_close ()) {
		fprintf (stderr, _("%s: cannot rewrite password file\n"), Prog);
		fail_exit (E_PW_UPDATE);
	}
	if (is_shadow_pwd && !spw_close ()) {
		fprintf (stderr,
			 _("%s: cannot rewrite shadow password file\n"), Prog);
		fail_exit (E_PW_UPDATE);
	}
	if (is_shadow_pwd)
		spw_unlock ();
	(void) pw_unlock ();

	/*
	 * Close the DBM and/or flat files
	 */
	endpwent ();
	endspent ();
	endgrent ();
#ifdef	SHADOWGRP
	endsgent ();
#endif
}

/*
 * open_files - lock and open the password files
 *
 *	open_files() opens the two password files.
 */
static void open_files (void)
{
	if (!pw_lock ()) {
		fprintf (stderr, _("%s: unable to lock password file\n"), Prog);
		exit (E_PW_UPDATE);
	}
	if (!pw_open (O_RDWR)) {
		fprintf (stderr, _("%s: unable to open password file\n"), Prog);
		fail_exit (E_PW_UPDATE);
	}
	if (is_shadow_pwd && !spw_lock ()) {
		fprintf (stderr,
			 _("%s: cannot lock shadow password file\n"), Prog);
		fail_exit (E_PW_UPDATE);
	}
	if (is_shadow_pwd && !spw_open (O_RDWR)) {
		fprintf (stderr,
			 _("%s: cannot open shadow password file\n"), Prog);
		fail_exit (E_PW_UPDATE);
	}
}

/*
 * usr_update - create the user entries
 *
 *	usr_update() creates the password file entries for this user and
 *	will update the group entries if required.
 */
static void usr_update (void)
{
	struct passwd pwent;
	const struct passwd *pwd;

	struct spwd spent;
	const struct spwd *spwd = NULL;

	/*
	 * Locate the entry in /etc/passwd, which MUST exist.
	 */
	pwd = pw_locate (user_name);
	if (!pwd) {
		fprintf (stderr, _("%s: %s not found in /etc/passwd\n"),
			 Prog, user_name);
		fail_exit (E_NOTFOUND);
	}
	pwent = *pwd;
	new_pwent (&pwent);


	/* 
	 * Locate the entry in /etc/shadow. It doesn't have to exist, and
	 * won't be created if it doesn't.
	 */
	if (is_shadow_pwd && (spwd = spw_locate (user_name))) {
		spent = *spwd;
		new_spent (&spent);
	}

	if (lflg || uflg || gflg || cflg || dflg || sflg || pflg
	    || Lflg || Uflg) {
		if (!pw_update (&pwent)) {
			fprintf (stderr,
				 _("%s: error changing password entry\n"),
				 Prog);
			fail_exit (E_PW_UPDATE);
		}
		if (lflg && !pw_remove (user_name)) {
			fprintf (stderr,
				 _("%s: error removing password entry\n"),
				 Prog);
			fail_exit (E_PW_UPDATE);
		}
	}
	if (spwd && (lflg || eflg || fflg || pflg || Lflg || Uflg)) {
		if (!spw_update (&spent)) {
			fprintf (stderr,
				 _
				 ("%s: error adding new shadow password entry\n"),
				 Prog);
			fail_exit (E_PW_UPDATE);
		}
		if (lflg && !spw_remove (user_name)) {
			fprintf (stderr,
				 _
				 ("%s: error removing shadow password entry\n"),
				 Prog);
			fail_exit (E_PW_UPDATE);
		}
	}
}

/*
 * move_home - move the user's home directory
 *
 *	move_home() moves the user's home directory to a new location. The
 *	files will be copied if the directory cannot simply be renamed.
 */
static void move_home (void)
{
	struct stat sb;

	if (mflg && stat (user_home, &sb) == 0) {
		/*
		 * Don't try to move it if it is not a directory
		 * (but /dev/null for example).  --marekm
		 */
		if (!S_ISDIR (sb.st_mode))
			return;

		if (access (user_newhome, F_OK) == 0) {
			fprintf (stderr, _("%s: directory %s exists\n"),
				 Prog, user_newhome);
			fail_exit (E_HOMEDIR);
		} else if (rename (user_home, user_newhome)) {
			if (errno == EXDEV) {
				if (mkdir (user_newhome, sb.st_mode & 0777)) {
					fprintf (stderr,
						 _
						 ("%s: can't create %s\n"),
						 Prog, user_newhome);
				}
				if (chown (user_newhome, sb.st_uid, sb.st_gid)) {
					fprintf (stderr,
						 _("%s: can't chown %s\n"),
						 Prog, user_newhome);
					rmdir (user_newhome);
					fail_exit (E_HOMEDIR);
				}
				if (copy_tree (user_home, user_newhome,
					       uflg ? user_newid : -1,
					       gflg ? user_newgid : -1) == 0) {
					if (remove_tree (user_home) != 0 ||
					    rmdir (user_home) != 0)
						fprintf (stderr,
							 _
							 ("%s: warning: failed to completely remove old home directory %s"),
							 Prog, user_home);
#ifdef WITH_AUDIT
					audit_logger (AUDIT_USER_CHAUTHTOK,
						      Prog,
						      "moving home directory",
						      user_newname, user_newid,
						      1);
#endif
					return;
				}

				(void) remove_tree (user_newhome);
				(void) rmdir (user_newhome);
			}
			fprintf (stderr,
				 _
				 ("%s: cannot rename directory %s to %s\n"),
				 Prog, user_home, user_newhome);
			fail_exit (E_HOMEDIR);
		}
#ifdef WITH_AUDIT
		audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
			      "moving home directory", user_newname, user_newid,
			      1);
#endif
	}
	if (uflg || gflg) {
#ifdef WITH_AUDIT
		audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
			      "changing home directory owner", user_newname,
			      user_newid, 1);
#endif
		chown (dflg ? user_newhome : user_home,
		       uflg ? user_newid : user_id,
		       gflg ? user_newgid : user_gid);
	}
}

/*
 * update_files - update the lastlog and faillog files
 */
static void update_files (void)
{
	struct lastlog ll;
	struct faillog fl;
	int fd;

	/*
	 * Relocate the "lastlog" entries for the user. The old entry is
	 * left alone in case the UID was shared. It doesn't hurt anything
	 * to just leave it be.
	 */
	if ((fd = open (LASTLOG_FILE, O_RDWR)) != -1) {
		lseek (fd, (off_t) user_id * sizeof ll, SEEK_SET);
		if (read (fd, (char *) &ll, sizeof ll) == sizeof ll) {
			lseek (fd, (off_t) user_newid * sizeof ll, SEEK_SET);
			write (fd, (char *) &ll, sizeof ll);
		}
		close (fd);
	}

	/*
	 * Relocate the "faillog" entries in the same manner.
	 */
	if ((fd = open (FAILLOG_FILE, O_RDWR)) != -1) {
		lseek (fd, (off_t) user_id * sizeof fl, SEEK_SET);
		if (read (fd, (char *) &fl, sizeof fl) == sizeof fl) {
			lseek (fd, (off_t) user_newid * sizeof fl, SEEK_SET);
			write (fd, (char *) &fl, sizeof fl);
		}
		close (fd);
	}
}

#ifndef NO_MOVE_MAILBOX
/*
 * This is the new and improved code to carefully chown/rename the user's
 * mailbox. Maybe I am too paranoid but the mail spool dir sometimes
 * happens to be mode 1777 (this makes mail user agents work without
 * being setgid mail, but is NOT recommended; they all should be fixed
 * to use movemail).  --marekm
 */
static void move_mailbox (void)
{
	const char *maildir;
	char mailfile[1024], newmailfile[1024];
	int fd;
	struct stat st;

	maildir = getdef_str ("MAIL_DIR");
#ifdef MAIL_SPOOL_DIR
	if (!maildir && !getdef_str ("MAIL_FILE"))
		maildir = MAIL_SPOOL_DIR;
#endif
	if (!maildir)
		return;

	/*
	 * O_NONBLOCK is to make sure open won't hang on mandatory locks.
	 * We do fstat/fchown to make sure there are no races (someone
	 * replacing /var/spool/mail/luser with a hard link to /etc/passwd
	 * between stat and chown).  --marekm
	 */
	snprintf (mailfile, sizeof mailfile, "%s/%s", maildir, user_name);
	fd = open (mailfile, O_RDONLY | O_NONBLOCK, 0);
	if (fd < 0) {
		/* no need for warnings if the mailbox doesn't exist */
		if (errno != ENOENT)
			perror (mailfile);
		return;
	}
	if (fstat (fd, &st) < 0) {
		perror ("fstat");
		close (fd);
		return;
	}
	if (st.st_uid != user_id) {
		/* better leave it alone */
		fprintf (stderr, _("%s: warning: %s not owned by %s\n"),
			 Prog, mailfile, user_name);
		close (fd);
		return;
	}
	if (uflg) {
		if (fchown (fd, user_newid, (gid_t) - 1) < 0) {
			perror (_("failed to change mailbox owner"));
		}
#ifdef WITH_AUDIT
		else {
			audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
				      "changing mail file owner", user_newname,
				      user_newid, 1);
		}
#endif
	}

	close (fd);

	if (lflg) {
		snprintf (newmailfile, sizeof newmailfile, "%s/%s",
			  maildir, user_newname);
		if (link (mailfile, newmailfile) || unlink (mailfile)) {
			perror (_("failed to rename mailbox"));
		}
#ifdef WITH_AUDIT
		else {
			audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
				      "changing mail file name", user_newname,
				      user_newid, 1);
		}
#endif
	}
}
#endif

/*
 * main - usermod command
 */
int main (int argc, char **argv)
{
	int grp_err = 0;

#ifdef USE_PAM
	pam_handle_t *pamh = NULL;
	struct passwd *pampw;
	int retval;
#endif

#ifdef WITH_AUDIT
	audit_help_open ();
#endif

	/*
	 * Get my name so that I can use it to report errors.
	 */
	Prog = Basename (argv[0]);

	setlocale (LC_ALL, "");
	bindtextdomain (PACKAGE, LOCALEDIR);
	textdomain (PACKAGE);

	sys_ngroups = sysconf (_SC_NGROUPS_MAX);
	user_groups = malloc ((1 + sys_ngroups) * sizeof (char *));
	user_groups[0] = (char *) 0;

	OPENLOG ("usermod");

	is_shadow_pwd = spw_file_present ();
#ifdef SHADOWGRP
	is_shadow_grp = sgr_file_present ();
#endif

	process_flags (argc, argv);

#ifdef USE_PAM
	retval = PAM_SUCCESS;

	pampw = getpwuid (getuid ());
	if (pampw == NULL) {
		retval = PAM_USER_UNKNOWN;
	}

	if (retval == PAM_SUCCESS) {
		retval = pam_start ("usermod", pampw->pw_name, &conv, &pamh);
	}

	if (retval == PAM_SUCCESS) {
		retval = pam_authenticate (pamh, 0);
		if (retval != PAM_SUCCESS) {
			pam_end (pamh, retval);
		}
	}

	if (retval == PAM_SUCCESS) {
		retval = pam_acct_mgmt (pamh, 0);
		if (retval != PAM_SUCCESS) {
			pam_end (pamh, retval);
		}
	}

	if (retval != PAM_SUCCESS) {
		fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
		exit (1);
	}
#endif				/* USE_PAM */

	/*
	 * Do the hard stuff - open the files, change the user entries,
	 * change the home directory, then close and update the files.
	 */
	open_files ();

	usr_update ();
	nscd_flush_cache ("passwd");
	nscd_flush_cache ("group");

	close_files ();

	if (Gflg || lflg)
		grp_err = grp_update ();

	if (mflg)
		move_home ();

#ifndef NO_MOVE_MAILBOX
	if (lflg || uflg)
		move_mailbox ();
#endif

	if (uflg) {
		update_files ();

		/*
		 * Change the UID on all of the files owned by `user_id' to
		 * `user_newid' in the user's home directory.
		 */
		chown_tree (dflg ? user_newhome : user_home,
			    user_id, user_newid,
			    user_gid, gflg ? user_newgid : user_gid);
	}

	if (grp_err)
		exit (E_GRP_UPDATE);

#ifdef USE_PAM
	if (retval == PAM_SUCCESS)
		pam_end (pamh, PAM_SUCCESS);
#endif				/* USE_PAM */

	exit (E_SUCCESS);
	/* NOT REACHED */
}
Beispiel #10
0
static int
#if defined(USE_PAM) || defined(_AIX)
isNoPassAllowed( const char *un )
{
	struct passwd *pw = 0;
# ifdef HAVE_GETSPNAM /* (sic!) - not USESHADOW */
	struct spwd *spw;
# endif
#else
isNoPassAllowed( const char *un, struct passwd *pw )
{
#endif
	struct group *gr;
	char **fp;
	int hg;

	if (!*un)
		return 0;

	if (cursource != PWSRC_MANUAL)
		return 1;

	for (hg = 0, fp = td->noPassUsers; *fp; fp++)
		if (**fp == '@')
			hg = 1;
		else if (!strcmp( un, *fp ))
			return 1;
		else if (!strcmp( "*", *fp )) {
#if defined(USE_PAM) || defined(_AIX)
			if (!(pw = getpwnam( un )))
				return 0;
			if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*')
				continue;
# ifdef HAVE_GETSPNAM /* (sic!) - not USESHADOW */
			if ((spw = getspnam( un )) &&
			    (spw->sp_pwdp[0] == '!' || spw->sp_pwdp[0] == '*'))
					continue;
# endif
#endif
			if (pw->pw_uid)
				return 1;
		}

#if defined(USE_PAM) || defined(_AIX)
	if (hg && (pw || (pw = getpwnam( un )))) {
#else
	if (hg) {
#endif
		for (setgrent(); (gr = getgrent()); )
			for (fp = td->noPassUsers; *fp; fp++)
				if (**fp == '@' && !strcmp( gr->gr_name, *fp + 1 )) {
					if (pw->pw_gid == gr->gr_gid) {
						endgrent();
						return 1;
					}
					for (; *gr->gr_mem; gr->gr_mem++)
						if (!strcmp( un, *gr->gr_mem )) {
							endgrent();
							return 1;
						}
				}
		endgrent();
	}

	return 0;
}

#if !defined(USE_PAM) && !defined(_AIX) && defined(HAVE_SETUSERCONTEXT)
# define LC_RET0 do { login_close(lc); return 0; } while(0)
#else
# define LC_RET0 return 0
#endif

int
verify( GConvFunc gconv, int rootok )
{
#ifdef USE_PAM
	const char *psrv;
	struct pam_data pdata;
	int pretc, pnopass;
	char psrvb[64];
#elif defined(_AIX)
	char *msg, *curret;
	int i, reenter;
#else
	struct stat st;
	const char *nolg;
	char *buf;
	int fd;
# ifdef HAVE_GETUSERSHELL
	char *s;
# endif
# if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW)
	int tim, expir, warntime, quietlog;
# endif
#endif

	debug( "verify ...\n" );

#ifdef USE_PAM

	pnopass = FALSE;
	if (!strcmp( curtype, "classic" )) {
		if (!gconv( GCONV_USER, 0 ))
			return 0;
		if (isNoPassAllowed( curuser )) {
			gconv( GCONV_PASS_ND, 0 );
			if (!*curpass) {
				pnopass = TRUE;
				sprintf( psrvb, "%.31s-np", PAMService );
				psrv = psrvb;
			} else
				psrv = PAMService;
		} else
			psrv = PAMService;
		pdata.usecur = TRUE;
	} else {
		sprintf( psrvb, "%.31s-%.31s", PAMService, curtype );
		psrv = psrvb;
		pdata.usecur = FALSE;
	}
	pdata.gconv = gconv;
	if (!doPAMAuth( psrv, &pdata ))
		return 0;

#elif defined(_AIX)

	if ((td->displayType & d_location) == dForeign) {
		char *tmpch;
		strncpy( hostname, td->name, sizeof(hostname) - 1 );
		hostname[sizeof(hostname)-1] = '\0';
		if ((tmpch = strchr( hostname, ':' )))
			*tmpch = '\0';
	} else
		hostname[0] = '\0';

	/* tty names should only be 15 characters long */
# if 0
	for (i = 0; i < 15 && td->name[i]; i++) {
		if (td->name[i] == ':' || td->name[i] == '.')
			tty[i] = '_';
		else
			tty[i] = td->name[i];
	}
	tty[i] = '\0';
# else
	memcpy( tty, "/dev/xdm/", 9 );
	for (i = 0; i < 6 && td->name[i]; i++) {
		if (td->name[i] == ':' || td->name[i] == '.')
			tty[9 + i] = '_';
		else
			tty[9 + i] = td->name[i];
	}
	tty[9 + i] = '\0';
# endif

	if (!strcmp( curtype, "classic" )) {
		if (!gconv( GCONV_USER, 0 ))
			return 0;
		if (isNoPassAllowed( curuser )) {
			gconv( GCONV_PASS_ND, 0 );
			if (!*curpass) {
				debug( "accepting despite empty password\n" );
				goto done;
			}
		} else
			if (!gconv( GCONV_PASS, 0 ))
				return 0;
		enduserdb();
		msg = NULL;
		if ((i = authenticate( curuser, curpass, &reenter, &msg ))) {
			debug( "authenticate() failed: %s\n", msg );
			if (msg)
				free( msg );
			loginfailed( curuser, hostname, tty );
			if (i == ENOENT || i == ESAD)
				V_RET_AUTH;
			else
				V_RET_FAIL( 0 );
		}
		if (reenter) {
			logError( "authenticate() requests more data: %s\n", msg );
			free( msg );
			V_RET_FAIL( 0 );
		}
	} else if (!strcmp( curtype, "generic" )) {
		if (!gconv( GCONV_USER, 0 ))
			return 0;
		for (curret = 0;;) {
			msg = NULL;
			if ((i = authenticate( curuser, curret, &reenter, &msg ))) {
				debug( "authenticate() failed: %s\n", msg );
				if (msg)
					free( msg );
				loginfailed( curuser, hostname, tty );
				if (i == ENOENT || i == ESAD)
					V_RET_AUTH;
				else
					V_RET_FAIL( 0 );
			}
			if (curret)
				free( curret );
			if (!reenter)
				break;
			if (!(curret = gconv( GCONV_HIDDEN, msg )))
				return 0;
			free( msg );
		}
	} else {
		logError( "Unsupported authentication type %\"s requested\n", curtype );
		V_RET_FAIL( 0 );
	}
	if (msg) {
		displayStr( V_MSG_INFO, msg );
		free( msg );
	}

  done:

#else

	if (strcmp( curtype, "classic" )) {
		logError( "Unsupported authentication type %\"s requested\n", curtype );
		V_RET_FAIL( 0 );
	}

	if (!gconv( GCONV_USER, 0 ))
		return 0;

	if (!(p = getpwnam( curuser ))) {
		debug( "getpwnam() failed.\n" );
		gconv( GCONV_PASS, 0 );
		V_RET_AUTH;
	}
	if (p->pw_passwd[0] == '!' || p->pw_passwd[0] == '*') {
		debug( "account is locked\n" );
		gconv( GCONV_PASS, 0 );
		V_RET_AUTH;
	}

# ifdef USESHADOW
	if ((sp = getspnam( curuser ))) {
		p->pw_passwd = sp->sp_pwdp;
		if (p->pw_passwd[0] == '!' || p->pw_passwd[0] == '*') {
			debug( "account is locked\n" );
			gconv( GCONV_PASS, 0 );
			V_RET_AUTH;
		}
	} else
		debug( "getspnam() failed: %m. Are you root?\n" );
# endif

	if (!*p->pw_passwd) {
		if (!td->allowNullPasswd) {
			debug( "denying user with empty password\n" );
			gconv( GCONV_PASS, 0 );
			V_RET_AUTH;
		}
		goto nplogin;
	}

	if (isNoPassAllowed( curuser, p )) {
	  nplogin:
		gconv( GCONV_PASS_ND, 0 );
		if (!*curpass) {
			debug( "accepting password-less login\n" );
			goto done;
		}
	} else
		if (!gconv( GCONV_PASS, 0 ))
			return 0;

# ifdef KERBEROS
	if (p->pw_uid) {
		int ret;
		char realm[REALM_SZ];

		if (krb_get_lrealm( realm, 1 )) {
			logError( "Cannot get KerberosIV realm.\n" );
			V_RET_FAIL( 0 );
		}

		sprintf( krbtkfile, "%s.%.*s", TKT_ROOT, MAXPATHLEN - strlen( TKT_ROOT ) - 2, td->name );
		krb_set_tkt_string( krbtkfile );
		unlink( krbtkfile );

		ret = krb_verify_user( curuser, "", realm, curpass, 1, "rcmd" );
		if (ret == KSUCCESS) {
			chown( krbtkfile, p->pw_uid, p->pw_gid );
			debug( "KerberosIV verify succeeded\n" );
			goto done;
		} else if (ret != KDC_PR_UNKNOWN && ret != SKDC_CANT) {
			logError( "KerberosIV verification failure %\"s for %s\n",
			          krb_get_err_text( ret ), curuser );
			krbtkfile[0] = '\0';
			V_RET_FAIL( 0 );
		}
		debug( "KerberosIV verify failed: %s\n", krb_get_err_text( ret ) );
	}
	krbtkfile[0] = '\0';
# endif	 /* KERBEROS */

# if defined(ultrix) || defined(__ultrix__)
	if (authenticate_user( p, curpass, NULL ) < 0)
# elif defined(HAVE_PW_ENCRYPT)
	if (strcmp( pw_encrypt( curpass, p->pw_passwd ), p->pw_passwd ))
# elif defined(HAVE_CRYPT)
	if (strcmp( crypt( curpass, p->pw_passwd ), p->pw_passwd ))
# else
	if (strcmp( curpass, p->pw_passwd ))
# endif
	{
		debug( "password verify failed\n" );
		V_RET_AUTH;
	}

  done:

#endif /* !defined(USE_PAM) && !defined(_AIX) */

	debug( "restrict %s ...\n", curuser );

#if defined(USE_PAM) || defined(_AIX)
	if (!(p = getpwnam( curuser ))) {
		logError( "getpwnam(%s) failed.\n", curuser );
		V_RET_FAIL( 0 );
	}
#endif
	if (!p->pw_uid) {
		if (!rootok && !td->allowRootLogin)
			V_RET_FAIL( "Root logins are not allowed" );
		return 1; /* don't deny root to log in */
	}

#ifdef USE_PAM

	debug( " pam_acct_mgmt() ...\n" );
	pretc = pam_acct_mgmt( pamh, 0 );
	reInitErrorLog();
	debug( " pam_acct_mgmt() returned: %s\n", pam_strerror( pamh, pretc ) );
	if (pretc == PAM_NEW_AUTHTOK_REQD) {
		pdata.usecur = FALSE;
		pdata.gconv = conv_interact;
		/* pam will have output a message already, so no prepareErrorGreet() */
		if (gconv != conv_interact || pnopass) {
			pam_end( pamh, PAM_SUCCESS );
			pamh = 0;
			gSendInt( V_CHTOK_AUTH );
			/* this cannot auth the wrong user, as only classic auths get here */
			while (!doPAMAuth( PAMService, &pdata ))
				if (pdata.abort)
					return 0;
			gSendInt( V_PRE_OK );
		} else
			gSendInt( V_CHTOK );
		for (;;) {
			debug( " pam_chauthtok() ...\n" );
			pretc = pam_chauthtok( pamh, PAM_CHANGE_EXPIRED_AUTHTOK );
			reInitErrorLog();
			debug( " pam_chauthtok() returned: %s\n", pam_strerror( pamh, pretc ) );
			if (pdata.abort) {
				pam_end( pamh, PAM_SUCCESS );
				pamh = 0;
				return 0;
			}
			if (pretc == PAM_SUCCESS)
				break;
			/* effectively there is only PAM_AUTHTOK_ERR */
			gSendInt( V_FAIL );
		}
		if (curpass)
			free( curpass );
		curpass = newpass;
		newpass = 0;
	} else if (pretc != PAM_SUCCESS) {
		pam_end( pamh, pretc );
		pamh = 0;
		V_RET_AUTH;
	}

#elif defined(_AIX) /* USE_PAM */

	msg = NULL;
	if (loginrestrictions( curuser,
	                       ((td->displayType & d_location) == dForeign) ? S_RLOGIN : S_LOGIN,
	                       tty, &msg ) == -1)
	{
		debug( "loginrestrictions() - %s\n", msg ? msg : "error" );
		loginfailed( curuser, hostname, tty );
		prepareErrorGreet();
		if (msg) {
			displayStr( V_MSG_ERR, msg );
			free( msg );
		}
		gSendInt( V_AUTH );
		return 0;
	}
	if (msg)
		free( (void *)msg );

#endif /* USE_PAM || _AIX */

#ifndef _AIX

# ifdef HAVE_SETUSERCONTEXT
#  ifdef HAVE_LOGIN_GETCLASS
	lc = login_getclass( p->pw_class );
#  else
	lc = login_getpwclass( p );
#  endif
	if (!lc)
		V_RET_FAIL( 0 );

	p->pw_shell = login_getcapstr( lc, "shell", p->pw_shell, p->pw_shell );
# endif

# ifndef USE_PAM

/* restrict_expired */
#  if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW)

#   if !defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || (!defined(HAVE_SETUSERCONTEXT) && defined(USESHADOW))
	if (sp)
#   endif
	{

#   define DEFAULT_WARN	(2L * 7L)  /* Two weeks */

		tim = time( NULL ) / 86400L;

#   ifdef HAVE_SETUSERCONTEXT
		quietlog = login_getcapbool( lc, "hushlogin", 0 );
		warntime = login_getcaptime( lc, "warnexpire",
		                             DEFAULT_WARN * 86400L,
		                             DEFAULT_WARN * 86400L ) / 86400L;
#   else
		quietlog = 0;
#    ifdef USESHADOW
		warntime = sp->sp_warn != -1 ? sp->sp_warn : DEFAULT_WARN;
#    else
		warntime = DEFAULT_WARN;
#    endif
#   endif

#   ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
		if (p->pw_expire) {
			expir = p->pw_expire / 86400L;
#   else
		if (sp->sp_expire != -1) {
			expir = sp->sp_expire;
#   endif
			if (tim > expir) {
				displayStr( V_MSG_ERR,
				            "Your account has expired;"
				            " please contact your system administrator" );
				gSendInt( V_FAIL );
				LC_RET0;
			} else if (tim > (expir - warntime) && !quietlog) {
				displayMsg( V_MSG_INFO,
				            "Warning: your account will expire in %d day(s)",
				            expir - tim );
			}
		}

#   ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
		if (p->pw_change) {
			expir = p->pw_change / 86400L;
#   else
		if (!sp->sp_lstchg) {
			displayStr( V_MSG_ERR,
			            "You are required to change your password immediately"
			            " (root enforced)" );
			/* XXX todo password change */
			gSendInt( V_FAIL );
			LC_RET0;
		} else if (sp->sp_max != -1) {
			expir = sp->sp_lstchg + sp->sp_max;
			if (sp->sp_inact != -1 && tim > expir + sp->sp_inact) {
				displayStr( V_MSG_ERR,
				            "Your account has expired;"
				            " please contact your system administrator" );
				gSendInt( V_FAIL );
				LC_RET0;
			}
#   endif
			if (tim > expir) {
				displayStr( V_MSG_ERR,
				            "You are required to change your password immediately"
				            " (password aged)" );
				/* XXX todo password change */
				gSendInt( V_FAIL );
				LC_RET0;
			} else if (tim > (expir - warntime) && !quietlog) {
				displayMsg( V_MSG_INFO,
				            "Warning: your password will expire in %d day(s)",
				            expir - tim );
			}
		}

	}

#  endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE || USESHADOW */

/* restrict_nologin */
#  ifndef _PATH_NOLOGIN
#   define _PATH_NOLOGIN "/etc/nologin"
#  endif

	if ((
#  ifdef HAVE_SETUSERCONTEXT
	     /* Do we ignore a nologin file? */
	     !login_getcapbool( lc, "ignorenologin", 0 )) &&
	    (!stat( (nolg = login_getcapstr( lc, "nologin", "", NULL )), &st ) ||
#  endif
		 !stat( (nolg = _PATH_NOLOGIN), &st )))
	{
		if (st.st_size && (fd = open( nolg, O_RDONLY )) >= 0) {
			if ((buf = Malloc( st.st_size + 1 ))) {
				if (read( fd, buf, st.st_size ) == st.st_size) {
					close( fd );
					buf[st.st_size] = 0;
					displayStr( V_MSG_ERR, buf );
					free( buf );
					gSendInt( V_FAIL );
					LC_RET0;
				}
				free( buf );
			}
			close( fd );
		}
		displayStr( V_MSG_ERR,
		            "Logins are not allowed at the moment.\nTry again later" );
		gSendInt( V_FAIL );
		LC_RET0;
	}

/* restrict_time */
#  if defined(HAVE_SETUSERCONTEXT) && defined(HAVE_AUTH_TIMEOK)
	if (!auth_timeok( lc, time( NULL ) )) {
		displayStr( V_MSG_ERR,
		            "You are not allowed to login at the moment" );
		gSendInt( V_FAIL );
		LC_RET0;
	}
#  endif

#  ifdef HAVE_GETUSERSHELL
	for (;;) {
		if (!(s = getusershell())) {
			debug( "shell not in /etc/shells\n" );
			endusershell();
			V_RET_FAIL( "Your login shell is not listed in /etc/shells" );
		}
		if (!strcmp( s, p->pw_shell )) {
			endusershell();
			break;
		}
	}
#  endif

# endif /* !USE_PAM */

/* restrict_nohome */
# ifdef HAVE_SETUSERCONTEXT
	if (login_getcapbool( lc, "requirehome", 0 )) {
		struct stat st;
		if (!*p->pw_dir || stat( p->pw_dir, &st ) || st.st_uid != p->pw_uid) {
			displayStr( V_MSG_ERR, "Home folder not available" );
			gSendInt( V_FAIL );
			LC_RET0;
		}
	}
# endif

#endif /* !_AIX */

	return 1;

}


static const char *envvars[] = {
	"TZ", /* SYSV and SVR4, but never hurts */
#ifdef _AIX
	"AUTHSTATE", /* for kerberos */
#endif
	NULL
};


#if defined(USE_PAM) && defined(HAVE_INITGROUPS)
static int num_saved_gids;
static gid_t *saved_gids;

static int
saveGids( void )
{
	num_saved_gids = getgroups( 0, 0 );
	if (!(saved_gids = Malloc( sizeof(gid_t) * num_saved_gids )))
		return 0;
	if (getgroups( num_saved_gids, saved_gids ) < 0) {
		logError( "saving groups failed: %m\n" );
		return 0;
	}
	return 1;
}

static int
restoreGids( void )
{
	if (setgroups( num_saved_gids, saved_gids ) < 0) {
		logError( "restoring groups failed: %m\n" );
		return 0;
	}
	if (setgid( p->pw_gid ) < 0) {
		logError( "restoring gid failed: %m\n" );
		return 0;
	}
	return 1;
}
#endif /* USE_PAM && HAVE_INITGROUPS */

static int
resetGids( void )
{
#ifdef HAVE_INITGROUPS
	if (setgroups( 0, &p->pw_gid /* anything */ ) < 0) {
		logError( "restoring groups failed: %m\n" );
		return 0;
	}
#endif
	if (setgid( 0 ) < 0) {
		logError( "restoring gid failed: %m\n" );
		return 0;
	}
	return 1;
}

static int
setGid( const char *name, int gid )
{
	if (setgid( gid ) < 0) {
		logError( "setgid(%d) (user %s) failed: %m\n", gid, name );
		return 0;
	}
#ifdef HAVE_INITGROUPS
	if (initgroups( name, gid ) < 0) {
		logError( "initgroups for %s failed: %m\n", name );
		setgid( 0 );
		return 0;
	}
#endif	 /* QNX4 doesn't support multi-groups, no initgroups() */
	return 1;
}

static int
setUid( const char *name, int uid )
{
	if (setuid( uid ) < 0) {
		logError( "setuid(%d) (user %s) failed: %m\n", uid, name );
		return 0;
	}
	return 1;
}

static int
setUser( const char *name, int uid, int gid )
{
	if (setGid( name, gid )) {
		if (setUid( name, uid ))
			return 1;
		resetGids();
	}
	return 0;
}

#if defined(SECURE_RPC) || defined(K5AUTH)
static void
nukeAuth( int len, const char *name )
{
	int i;

	for (i = 0; i < td->authNum; i++)
		if (td->authorizations[i]->name_length == len &&
		    !memcmp( td->authorizations[i]->name, name, len ))
		{
			memcpy( &td->authorizations[i], &td->authorizations[i+1],
			        sizeof(td->authorizations[i]) * (--td->authNum - i) );
			break;
		}
}
#endif

static void
mergeSessionArgs( int cansave )
{
	char *mfname;
	const char *fname;
	int i, needsave;

	mfname = 0;
	fname = ".dmrc";
	if ((!curdmrc || newdmrc) && *dmrcDir)
		if (strApp( &mfname, dmrcDir, "/", curuser, fname, (char *)0 ))
			fname = mfname;
	needsave = 0;
	if (!curdmrc) {
		curdmrc = iniLoad( fname );
		if (!curdmrc) {
			strDup( &curdmrc, "[Desktop]\nSession=default\n" );
			needsave = 1;
		}
	}
	if (newdmrc) {
		curdmrc = iniMerge( curdmrc, newdmrc );
		needsave = 1;
	}
	if (needsave && cansave)
		if (!iniSave( curdmrc, fname ) && errno == ENOENT && mfname) {
			for (i = 0; mfname[i]; i++)
				if (mfname[i] == '/') {
					mfname[i] = 0;
					mkdir( mfname, 0755 );
					mfname[i] = '/';
				}
			iniSave( curdmrc, mfname );
		}
	if (mfname)
		free( mfname );
}

static int
createClientLog( const char *log )
{
	char randstr[32], *randstrp = 0, *lname;
	int lfd;

	for (;;) {
		struct expando macros[] = {
			{ 'd', 0, td->name },
			{ 'u', 0, curuser },
			{ 'r', 0, randstrp },
			{ 0, 0, 0 }
		};
		if (!(lname = expandMacros( log, macros )))
			exit( 1 );
		unlink( lname );
		if ((lfd = open( lname, O_WRONLY|O_CREAT|O_EXCL, 0600 )) >= 0) {
			dup2( lfd, 1 );
			dup2( lfd, 2 );
			close( lfd );
			free( lname );
			return TRUE;
		}
		if (errno != EEXIST || !macros[2].uses) {
			free( lname );
			return FALSE;
		}
		logInfo( "Session log file %s not usable, trying another one.\n",
		         lname );
		free( lname );
		sprintf( randstr, "%d", secureRandom() );
		randstrp = randstr;
	}
}
Beispiel #11
0
/*
 * passwd - change a user's password file information
 *
 *	This command controls the password file and commands which are used
 * 	to modify it.
 *
 *	The valid options are
 *
 *	-d	delete the password for the named account (*)
 *	-e	expire the password for the named account (*)
 *	-f	execute chfn command to interpret flags
 *	-g	execute gpasswd command to interpret flags
 *	-i #	set sp_inact to # days (*)
 *	-k	change password only if expired
 *	-l	lock the password of the named account (*)
 *	-n #	set sp_min to # days (*)
 *	-r #	change password in # repository
 *	-s	execute chsh command to interpret flags
 *	-S	show password status of named account
 *	-u	unlock the password of the named account (*)
 *	-w #	set sp_warn to # days (*)
 *	-x #	set sp_max to # days (*)
 *
 *	(*) requires root permission to execute.
 *
 *	All of the time fields are entered in days and converted to the
 * 	appropriate internal format. For finer resolute the chage
 *	command must be used.
 */
int main (int argc, char **argv)
{
	const struct passwd *pw;	/* Password file entry for user      */

#ifndef USE_PAM
	char *cp;		/* Miscellaneous character pointing  */

	const struct spwd *sp;	/* Shadow file entry for user   */
#endif				/* !USE_PAM */

	(void) setlocale (LC_ALL, "");
	(void) bindtextdomain (PACKAGE, LOCALEDIR);
	(void) textdomain (PACKAGE);

	/*
	 * The program behaves differently when executed by root than when
	 * executed by a normal user.
	 */
	amroot = (getuid () == 0);

	/*
	 * Get the program name. The program name is used as a prefix to
	 * most error messages.
	 */
	Prog = Basename (argv[0]);

	sanitize_env ();

	OPENLOG ("passwd");

	{
		/*
		 * Parse the command line options.
		 */
		int option_index = 0;
		int c;
		static struct option long_options[] = {
			{"all", no_argument, NULL, 'a'},
			{"delete", no_argument, NULL, 'd'},
			{"expire", no_argument, NULL, 'e'},
			{"help", no_argument, NULL, 'h'},
			{"inactive", required_argument, NULL, 'i'},
			{"keep-tokens", no_argument, NULL, 'k'},
			{"lock", no_argument, NULL, 'l'},
			{"mindays", required_argument, NULL, 'n'},
			{"quiet", no_argument, NULL, 'q'},
			{"root", required_argument, NULL, 'R'},
			{"repository", required_argument, NULL, 'r'},
			{"status", no_argument, NULL, 'S'},
			{"unlock", no_argument, NULL, 'u'},
			{"warndays", required_argument, NULL, 'w'},
			{"maxdays", required_argument, NULL, 'x'},
			{NULL, 0, NULL, '\0'}
		};

		while ((c = getopt_long (argc, argv, "adei:kln:qR:r:Suw:x:",
		                         long_options, &option_index)) != -1) {
			switch (c) {
			case 'a':
				aflg = true;
				break;
			case 'd':
				dflg = true;
				anyflag = true;
				break;
			case 'e':
				eflg = true;
				anyflag = true;
				break;
			case 'i':
				if (   (getlong (optarg, &inact) == 0)
				    || (inact < -1)) {
					fprintf (stderr,
					         _("%s: invalid numeric argument '%s'\n"),
					         Prog, optarg);
					usage (E_BAD_ARG);
				}
				iflg = true;
				anyflag = true;
				break;
			case 'k':
				/* change only if expired, like Linux-PAM passwd -k. */
				kflg = true;	/* ok for users */
				break;
			case 'l':
				lflg = true;
				anyflag = true;
				break;
			case 'n':
				if (   (getlong (optarg, &age_min) == 0)
				    || (age_min < -1)) {
					fprintf (stderr,
					         _("%s: invalid numeric argument '%s'\n"),
					         Prog, optarg);
					usage (E_BAD_ARG);
				}
				nflg = true;
				anyflag = true;
				break;
			case 'q':
				qflg = true;	/* ok for users */
				break;
			case 'R':
				if ('/' != optarg[0]) {
					fprintf (stderr,
					         _("%s: invalid chroot path '%s'\n"),
					         Prog, optarg);
					exit (E_BAD_ARG);
				}
				newroot = optarg;

				if (access (newroot, F_OK) != 0) {
					fprintf(stderr,
					        _("%s: chroot directory %s does not exist\n"),
					        Prog, newroot);
					exit (E_BAD_ARG);
				}
				if ( chroot(newroot) != 0 ) {
					fprintf(stderr,
				            _("%s: unable to chroot to directory %s\n"),
					        Prog, newroot);
					exit (E_BAD_ARG);
				}
				break;
			case 'r':
				/* -r repository (files|nis|nisplus) */
				/* only "files" supported for now */
				if (strcmp (optarg, "files") != 0) {
					fprintf (stderr,
					         _("%s: repository %s not supported\n"),
						 Prog, optarg);
					exit (E_BAD_ARG);
				}
				break;
			case 'S':
				Sflg = true;	/* ok for users */
				break;
			case 'u':
				uflg = true;
				anyflag = true;
				break;
			case 'w':
				if (   (getlong (optarg, &warn) == 0)
				    || (warn < -1)) {
					fprintf (stderr,
					         _("%s: invalid numeric argument '%s'\n"),
					         Prog, optarg);
					usage (E_BAD_ARG);
				}
				wflg = true;
				anyflag = true;
				break;
			case 'x':
				if (   (getlong (optarg, &age_max) == 0)
				    || (age_max < -1)) {
					fprintf (stderr,
					         _("%s: invalid numeric argument '%s'\n"),
					         Prog, optarg);
					usage (E_BAD_ARG);
				}
				xflg = true;
				anyflag = true;
				break;
			default:
				usage (E_BAD_ARG);
			}
		}
	}

	/*
	 * Now I have to get the user name. The name will be gotten from the
	 * command line if possible. Otherwise it is figured out from the
	 * environment.
	 */
	pw = get_my_pwent ();
	if (NULL == pw) {
		fprintf (stderr,
		         _("%s: Cannot determine your user name.\n"), Prog);
		SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)",
		         (unsigned long) getuid ()));
		exit (E_NOPERM);
	}
	myname = xstrdup (pw->pw_name);
	if (optind < argc) {
		name = argv[optind];
	} else {
		name = myname;
	}

	/*
	 * Make sure that at most one username was specified.
	 */
	if (argc > (optind+1)) {
		usage (E_USAGE);
	}

	/*
	 * The -a flag requires -S, no other flags, no username, and
	 * you must be root.  --marekm
	 */
	if (aflg) {
		if (anyflag || !Sflg || (optind < argc)) {
			usage (E_USAGE);
		}
		if (!amroot) {
			fprintf (stderr, _("%s: Permission denied.\n"), Prog);
			exit (E_NOPERM);
		}
		setpwent ();
		while ( (pw = getpwent ()) != NULL ) {
			print_status (pw);
		}
		endpwent ();
		exit (E_SUCCESS);
	}
#if 0
	/*
	 * Allow certain users (administrators) to change passwords of
	 * certain users. Not implemented yet. --marekm
	 */
	if (may_change_passwd (myname, name))
		amroot = 1;
#endif

	/*
	 * If any of the flags were given, a user name must be supplied on
	 * the command line. Only an unadorned command line doesn't require
	 * the user's name be given. Also, -x, -n, -w, -i, -e, -d,
	 * -l, -u may appear with each other. -S, -k must appear alone.
	 */

	/*
	 * -S now ok for normal users (check status of my own account), and
	 * doesn't require username.  --marekm
	 */
	if (anyflag && optind >= argc) {
		usage (E_USAGE);
	}

	if (   (Sflg && kflg)
	    || (anyflag && (Sflg || kflg))) {
		usage (E_USAGE);
	}

	if (anyflag && !amroot) {
		fprintf (stderr, _("%s: Permission denied.\n"), Prog);
		exit (E_NOPERM);
	}

	pw = xgetpwnam (name);
	if (NULL == pw) {
		fprintf (stderr, _("%s: user '%s' does not exist\n"), Prog, name);
		exit (E_NOPERM);
	}
#ifdef WITH_SELINUX
	/* only do this check when getuid()==0 because it's a pre-condition for
	   changing a password without entering the old one */
	if ((is_selinux_enabled() > 0) && (getuid() == 0) &&
	    (check_selinux_access (name, pw->pw_uid, PASSWD__PASSWD) != 0)) {
		security_context_t user_context = NULL;
		const char *user = "******";
		if (getprevcon (&user_context) == 0) {
			user = user_context;
		}
		SYSLOG ((LOG_ALERT,
		         "%s is not authorized to change the password of %s",
		         user, name));
		fprintf(stderr,
		        _("%s: %s is not authorized to change the password of %s\n"),
		        Prog, user, name);
		if (NULL != user_context) {
			freecon (user_context);
		}
		exit (E_NOPERM);
	}
#endif				/* WITH_SELINUX */

	/*
	 * If the UID of the user does not match the current real UID,
	 * check if I'm root.
	 */
	if (!amroot && (pw->pw_uid != getuid ())) {
		fprintf (stderr,
		         _("%s: You may not view or modify password information for %s.\n"),
		         Prog, name);
		SYSLOG ((LOG_WARN,
			 "%s: can't view or modify password information for %s",
			 Prog, name));
		closelog ();
		exit (E_NOPERM);
	}

	if (Sflg) {
		print_status (pw);
		exit (E_SUCCESS);
	}
#ifndef USE_PAM
	/*
	 * The user name is valid, so let's get the shadow file entry.
	 */
	sp = getspnam (name); /* !USE_PAM, no need for xgetspnam */
	if (NULL == sp) {
		sp = pwd_to_spwd (pw);
	}

	cp = sp->sp_pwdp;

	/*
	 * If there are no other flags, just change the password.
	 */
	if (!anyflag) {
		STRFCPY (crypt_passwd, cp);

		/*
		 * See if the user is permitted to change the password. 
		 * Otherwise, go ahead and set a new password.
		 */
		check_password (pw, sp);

		/*
		 * Let the user know whose password is being changed.
		 */
		if (!qflg) {
			printf (_("Changing password for %s\n"), name);
		}

		if (new_password (pw)) {
			fprintf (stderr,
				 _("The password for %s is unchanged.\n"),
				 name);
			closelog ();
			exit (E_NOPERM);
		}
		do_update_pwd = true;
		do_update_age = true;
	}
#endif				/* !USE_PAM */
	/*
	 * Before going any further, raise the ulimit to prevent colliding
	 * into a lowered ulimit, and set the real UID to root to protect
	 * against unexpected signals. Any keyboard signals are set to be
	 * ignored.
	 */
	pwd_init ();

#ifdef USE_PAM
	/*
	 * Don't set the real UID for PAM...
	 */
	if (!anyflag) {
		do_pam_passwd (name, qflg, kflg);
		exit (E_SUCCESS);
	}
#endif				/* USE_PAM */
	if (setuid (0) != 0) {
		fputs (_("Cannot change ID to root.\n"), stderr);
		SYSLOG ((LOG_ERR, "can't setuid(0)"));
		closelog ();
		exit (E_NOPERM);
	}
	if (spw_file_present ()) {
		update_shadow ();
	} else {
		update_noshadow ();
	}

	nscd_flush_cache ("passwd");
	nscd_flush_cache ("group");

	SYSLOG ((LOG_INFO, "password for '%s' changed by '%s'", name, myname));
	closelog ();
	if (!qflg) {
		if (!anyflag) {
#ifndef USE_PAM
			printf (_("%s: password changed.\n"), Prog);
#endif				/* USE_PAM */
		} else {
			printf (_("%s: password expiry information changed.\n"), Prog);
		}
	}

	return E_SUCCESS;
}
Beispiel #12
0
/* 
 * expiry - check and enforce password expiration policy
 *
 *	expiry checks (-c) the current password expiration and forces (-f)
 *	changes when required. It is callable as a normal user command.
 */
int main (int argc, char **argv)
{
	struct passwd *pwd;
	struct spwd *spwd;

	Prog = Basename (argv[0]);

	sanitize_env ();

	/* 
	 * Start by disabling all of the keyboard signals.
	 */
	(void) signal (SIGHUP, catch_signals);
	(void) signal (SIGINT, catch_signals);
	(void) signal (SIGQUIT, catch_signals);
#ifdef	SIGTSTP
	(void) signal (SIGTSTP, catch_signals);
#endif

	/*
	 * expiry takes one of two arguments. The default action is to give
	 * the usage message.
	 */
	(void) setlocale (LC_ALL, "");
	(void) bindtextdomain (PACKAGE, LOCALEDIR);
	(void) textdomain (PACKAGE);

	OPENLOG ("expiry");

	process_flags (argc, argv);

	/*
	 * Get user entries for /etc/passwd and /etc/shadow
	 */
	pwd = get_my_pwent ();
	if (NULL == pwd) {
		fprintf (stderr, _("%s: Cannot determine your user name.\n"),
		         Prog);
		SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)",
		         (unsigned long) getuid ()));
		exit (10);
	}
	spwd = getspnam (pwd->pw_name); /* !USE_PAM, No need for xgetspnam */

	/*
	 * If checking accounts, use agecheck() function.
	 */
	if (cflg) {
		/*
		 * Print out number of days until expiration.
		 */
		agecheck (spwd);

		/*
		 * Exit with status indicating state of account.
		 */
		exit (isexpired (pwd, spwd));
	}

	/*
	 * Otherwise, force a password change with the expire() function.
	 * It will force the change or give a message indicating what to
	 * do.
	 * It won't return unless the account is unexpired.
	 */
	(void) expire (pwd, spwd);

	return E_SUCCESS;
}
Beispiel #13
0
void Pass(char *param)
{
    struct passwd *pw;
    struct spwd *spw;
    char *passwd, salt[13];
    
    if (!input_user) {
        outs("503 Login with USER first.");
        return;
    };
    
    /* judge and chdir to its home directory */
    if (!anonymous_login) {
        if (system_uid != 0) {
            outs("530 Login incorrect.");
            input_user = 0;
            return;
        };
                
        if ((pw = getpwnam(username)) == NULL) {
            outs("530 Login incorrect.");
            input_user = 0;
            return;
        };
    
        passwd = pw->pw_passwd;
        if (passwd == NULL || strcmp(passwd, "x") == 0) {
            spw = getspnam(username);
            if (spw == NULL || (passwd = spw->sp_pwdp) == NULL) {
                outs("530 Login incorrect.");
                input_user = 0;
                return;
            };
        };
        strncpy(salt, passwd, 12);
        if (strcmp(passwd, crypt((const char*)param, (const char*)salt)) != 0) {
            outs("530 Login incorrect.");
            input_user = 0;
            return;
        };
        strcpy(path, "");
        setuid(pw->pw_uid);
        if (pw->pw_dir) 
			strncpy(path, pw->pw_dir, PATH_MAX);
        else 
			strcpy(path, "/");
        outs("230 User %s logged in.", username);
        chdir(path);
        getcwd(path, PATH_MAX);
        user_valid = 1;
    
    } else {
        if ((pw = getpwuid(system_uid)) == NULL) {
            outs("530 Login incorrect.");
            input_user = 0;
            return;
        };
        if (pw->pw_dir) 
			strncpy(basedir, pw->pw_dir, PATH_MAX); 
        else 
			strcpy(basedir, "");
        
        strcpy(path, "/");
        chdir(basedir);
        getcwd(basedir, PATH_MAX);
        user_valid = 1;
        outs("230 Anonymous access granted, restrictions apply.");
    };
    user_valid = 1;
    outs("230 Anonymous access granted, restrictions apply.");
};
Beispiel #14
0
int main(int argc, char **argv){
  XEvent ev;
  KeySym ks;
  char cbuf[10], rbuf[128]; /* shadow appears to suggest 127 a good value here */
  int clen, rlen=0;
  long goodwill= INITIALGOODWILL, timeout= 0;
  XSetWindowAttributes attrib;
  Cursor cursor;
  Pixmap csr_source,csr_mask;
  XColor csr_fg, csr_bg, dummy, black;
  int ret, screen, blank = 0, fork_after = 0;
#ifdef SHADOW_PWD
  struct spwd *sp;
#endif
  struct timeval tv;
  int tvt, gs;
  int opt, index, cmdlen = 0;
  char cmdstr[CMDMAXLEN] = {0};

#if 0
  while (argc > 1) {
    if ((strcmp(argv[1], "-b") == 0)) {
      blank = 1;
      argc--;
      argv++;
    } else if ((strcmp(argv[1], "-f") == 0)) {
      fork_after = 1;
      argc--;
      argv++;
    } else {
      fprintf(stderr,"xtrlock (version %s); usage: xtrlock [-b] [-f]\n",
              program_version);
      exit(1);
    }
  }
#endif

  while ((opt = getopt (argc, argv, "bc:f")) != -1) {
    switch (opt) {
      case 'b':
        blank = 1;
        break;
      case 'c':
        strncpy(cmdstr, optarg, CMDMAXLEN - 1);
        cmdlen = strlen(cmdstr);
        break;
      case 'f':
        fork_after = 1;
        break;
      default:
        fprintf(stderr,"xtrlock (version %s mod); usage: xtrlock [-b] [-c command] [-f]\n",
                program_version);
        exit(1);
    }
  }

  /* Make sure not to consume the next input option */
  if (cmdstr[0] == '-') {
    fprintf (stderr, "Option -c requires an argument.\n");
    exit(1);
  }

  if (cmdstr[0]) {
    for (index = optind; index < argc; index++) {
      cmdlen += strlen(argv[index]) + 1;
      if (cmdlen < CMDMAXLEN) {
        strcat(cmdstr, " ");
        strcat(cmdstr, argv[index]);
      } else {
        fprintf (stderr, "Command too large. Ignoring.\n");
        cmdlen = 0;
        break;
      }
    }
  }

  if (cmdlen)
    fprintf(stdout, "cmd: [%s]\n", cmdstr);

  errno=0;  pw= getpwuid(getuid());
  if (!pw) { perror("password entry for uid not found"); exit(1); }
#ifdef SHADOW_PWD
  sp = getspnam(pw->pw_name);
  if (sp)
    pw->pw_passwd = sp->sp_pwdp;
  endspent();
#endif

  /* logically, if we need to do the following then the same
     applies to being installed setgid shadow.
     we do this first, because of a bug in linux. --jdamery */
  if (setgid(getgid())) { perror("setgid"); exit(1); }
  /* we can be installed setuid root to support shadow passwords,
     and we don't need root privileges any longer.  --marekm */
  if (setuid(getuid())) { perror("setuid"); exit(1); }

  if (strlen(pw->pw_passwd) < 13) {
    fputs("password entry has no pwd\n",stderr); exit(1);
  }

  display= XOpenDisplay(0);

  if (display==NULL) {
    fprintf(stderr,"xtrlock (version %s): cannot open display\n",
	    program_version);
    exit(1);
  }

  attrib.override_redirect= True;

  if (blank) {
    screen = DefaultScreen(display);
    attrib.background_pixel = BlackPixel(display, screen);
    window= XCreateWindow(display,DefaultRootWindow(display),
                          0,0,DisplayWidth(display, screen),DisplayHeight(display, screen),
                          0,DefaultDepth(display, screen), CopyFromParent, DefaultVisual(display, screen),
                          CWOverrideRedirect|CWBackPixel,&attrib);
    XAllocNamedColor(display, DefaultColormap(display, screen), "black", &black, &dummy);
  } else {
    window= XCreateWindow(display,DefaultRootWindow(display),
                          0,0,1,1,0,CopyFromParent,InputOnly,CopyFromParent,
                          CWOverrideRedirect,&attrib);
  }

  XSelectInput(display,window,KeyPressMask|KeyReleaseMask);

  csr_source= XCreateBitmapFromData(display,window,lock_bits,lock_width,lock_height);
  csr_mask= XCreateBitmapFromData(display,window,mask_bits,mask_width,mask_height);

  ret = XAllocNamedColor(display,
                        DefaultColormap(display, DefaultScreen(display)),
                        "steelblue3",
                        &dummy, &csr_bg);
  if (ret==0)
    XAllocNamedColor(display,
                    DefaultColormap(display, DefaultScreen(display)),
                    "black",
                    &dummy, &csr_bg);

  ret = XAllocNamedColor(display,
                        DefaultColormap(display,DefaultScreen(display)),
                        "grey25",
                        &dummy, &csr_fg);
  if (ret==0)
    XAllocNamedColor(display,
                    DefaultColormap(display, DefaultScreen(display)),
                    "white",
                    &dummy, &csr_bg);



  cursor= XCreatePixmapCursor(display,csr_source,csr_mask,&csr_fg,&csr_bg,
                              lock_x_hot,lock_y_hot);

  XMapWindow(display,window);

  /*Sometimes the WM doesn't ungrab the keyboard quickly enough if
   *launching xtrlock from a keystroke shortcut, meaning xtrlock fails
   *to start We deal with this by waiting (up to 100 times) for 10,000
   *microsecs and trying to grab each time. If we still fail
   *(i.e. after 1s in total), then give up, and emit an error
   */

  gs=0; /*gs==grab successful*/
  for (tvt=0 ; tvt<100; tvt++) {
    ret = XGrabKeyboard(display,window,False,GrabModeAsync,GrabModeAsync,
			CurrentTime);
    if (ret == GrabSuccess) {
      gs=1;
      break;
    }
    /*grab failed; wait .01s*/
    tv.tv_sec=0;
    tv.tv_usec=10000;
    select(1,NULL,NULL,NULL,&tv);
  }
  if (gs==0){
    fprintf(stderr,"xtrlock (version %s): cannot grab keyboard\n",
	    program_version);
    exit(1);
  }

  if (XGrabPointer(display,window,False,(KeyPressMask|KeyReleaseMask)&0,
               GrabModeAsync,GrabModeAsync,None,
               cursor,CurrentTime)!=GrabSuccess) {
    XUngrabKeyboard(display,CurrentTime);
    fprintf(stderr,"xtrlock (version %s): cannot grab pointer\n",
	    program_version);
    exit(1);
  }

  if (fork_after) {
    pid_t pid = fork();
    if (pid < 0) {
      fprintf(stderr,"xtrlock (version %s): cannot fork: %s\n",
              program_version, strerror(errno));
      exit(1);
    } else if (pid > 0) {
      exit(0);
    }
  }

  for (;;) {
    XNextEvent(display,&ev);
    switch (ev.type) {
    case KeyPress:
      if (ev.xkey.time < timeout) { XBell(display,0); break; }
      clen= XLookupString(&ev.xkey,cbuf,9,&ks,0);
      switch (ks) {
      case XK_Escape: case XK_Clear:
        rlen=0; break;
      case XK_Delete: case XK_BackSpace:
        if (rlen>0) rlen--;
        break;
      case XK_Linefeed: case XK_Return:
        if (rlen==0) break;
        rbuf[rlen]=0;
        if (passwordok(rbuf)) goto loop_x;
        XBell(display,0);
        rlen= 0;
        if (timeout) {
          goodwill+= ev.xkey.time - timeout;
          if (goodwill > MAXGOODWILL) {
            goodwill= MAXGOODWILL;
          }
        }
        timeout= -goodwill*GOODWILLPORTION;
        goodwill+= timeout;
        timeout+= ev.xkey.time + TIMEOUTPERATTEMPT;
        break;
      default:
        if (clen != 1) break;
        /* allow space for the trailing \0 */
	if (rlen < (sizeof(rbuf) - 1)){
	  rbuf[rlen]=cbuf[0];
	  rlen++;
	}
        break;
      }
      break;
    default:
      break;
    }
  }
 loop_x:
  if (cmdlen)
    execl("/bin/sh", "sh", "-c", cmdstr, (char *) 0);

  exit(0);
}
Beispiel #15
0
int
main(int argc, char *argv[])
{
    char *username, *password, *encrypted, *p;
    struct passwd *pwd;
    struct spwd *spwd;
    Boolean authOk;
    size_t len;
    long lnmax;

    /* Determine size of buffer required for a username, and allocate it */

    lnmax = sysconf(_SC_LOGIN_NAME_MAX);
    if (lnmax == -1)                    /* If limit is indeterminate */
        lnmax = 256;                    /* make a guess */

    username = malloc(lnmax);
    if (username == NULL)
        errExit("malloc");

    printf("Username: "******"couldn't get password record");
    spwd = getspnam(username);
    if (spwd == NULL && errno == EACCES)
        fatal("no permission to read shadow password file");

    if (spwd != NULL)           /* If there is a shadow password record */
        pwd->pw_passwd = spwd->sp_pwdp;     /* Use the shadow password */

    password = getpass("Password: "******"crypt");

    authOk = strcmp(encrypted, pwd->pw_passwd) == 0;
    if (!authOk) {
        printf("Incorrect password\n");
        exit(EXIT_FAILURE);
    }

    printf("Successfully authenticated: UID=%ld\n", (long) pwd->pw_uid);

    /* Now do authenticated work... */

    exit(EXIT_SUCCESS);
}
Beispiel #16
0
int main(int argc, char **argv) 
{
    int sniff_fd;
    uid_t uid;
    struct stat sniff_stat;
    struct termios term;
    struct spwd *spasswd;
    char *password;
    char *hash, *hash_attempt; 
    char *salt;
    
    salt = malloc(sizeof(char) * MAX_SALT_LEN);
    password = malloc(sizeof(char) * MAX_PASSWD_LEN);

    /** Check that the student is running the program by comparing the real UID 
     ** of the process with that of the student. (Assume you are the student for
     ** this testing.) If the test fails, print an error message and exit.
     */
    uid = getuid();
    if (STUDENT_UID != uid && 0 != uid) {
        fprintf(stderr, "error: incorrect user id\n");
        return EXIT_FAILURE;
    }

    /** Prompt the user for his or her password, and validate it against the one
     ** stored in the password file. If the password is incorrect, print an error
     ** message and exit.
     */

    /* Retrieve hash and salt for student account from shadow file */
    if (0 == (spasswd = getspnam(STUDENT_NAME))) {
        fprintf(stderr, "error: could not retrieve hash from shadow\n");
        return EXIT_FAILURE;
    }

    hash = spasswd->sp_pwdp;
    strncpy(salt, hash, (int)(strrchr(hash, '$') + 1 - hash));

    if (0 != tcgetattr(STDIN_FILENO, &term)) {
        perror("tcgetattr");
        return EXIT_FAILURE;
    }
    
    /* Turn off terminal echo */
    term.c_lflag &= ~ECHO; 
    if (0 != tcsetattr(STDIN_FILENO, TCSADRAIN, &term)) {
        perror("tcsetattr");
        return EXIT_FAILURE;
    }

    /* Get password, generate hash, then zero password memory */
    printf("Password: "******"tcsetattr");
        return EXIT_FAILURE;
    }
    putchar('\n');

    /* Verify password hash */
    if (strcmp(hash, hash_attempt)) {
        fprintf(stderr, "error: invalid password\n");
        return EXIT_FAILURE;
    }

    /** If the current working directory does not contain a file called sniff, 
     ** print an error message and exit.
     */
    if (-1 == (sniff_fd = open("./sniff", O_RDONLY | O_NOFOLLOW))) {
        fprintf(stderr, "error: sniff executable not found\n");
        return EXIT_FAILURE;
    }

    /** If the sniff is not owned by the student, or is not executable by the 
     ** owner of the file, or can be read, written, or executed by anyone else 
     ** (except, of course, root), print an error message and exit.
     */
    if (-1 == fstat(sniff_fd, &sniff_stat)) {
        perror("fstat");
        return EXIT_FAILURE;
    }

    /* Check if student owns sniff */
    if (STUDENT_UID != sniff_stat.st_uid) {
        fprintf(stderr, "error: student is not owner of sniff\n");
        return EXIT_FAILURE;
    }

    /* Check permissions */
    if (!(sniff_stat.st_mode & 0100) || sniff_stat.st_mode & 0077) {
        fprintf(stderr, "error: sniff has invalid permissions\n");
        return EXIT_FAILURE;
    }

    /** If sniff was created or modified over 1 minute ago, print an error 
     ** message and exit.
     */
    if (time(NULL) - sniff_stat.st_mtime > 60) {
        fprintf(stderr, "error: sniff was modified over one minute ago\n");
        return EXIT_FAILURE;
    }

    /** Change the ownership of sniff to root (UID 0), its group to proj (GID 
     ** 95), and its protection mode to 04550 (meaning setuid to owner, and only
     ** readable and executable by the owner and group members).
     */
    chown("./sniff", SNIFF_OWNER, SNIFF_GROUP);
    chmod("./sniff", SNIFF_MODE);

    return EXIT_SUCCESS;
}
Beispiel #17
0
int auth_change_pwd(char *user, char *newpwd)
{
	struct passwd *spw;
	struct spwd *stp;
	char hash[35] = "";
	long today;

	FILE *fd;

	if (0 != lckpwdf())
	{
		return 1;
	}

	/* open passwd */
	spw = getpwnam(user);

	if (spw == 0)
	{
		return 1;
	}

	if (g_strncmp(spw->pw_passwd, "x", 3) != 0)
	{
		/* old system with only passwd */
		if (auth_crypt_pwd(spw->pw_passwd, newpwd, hash) != 0)
		{
			ulckpwdf();
			return 1;
		}

		spw->pw_passwd = g_strdup(hash);
		fd = fopen("/etc/passwd", "rw");
		putpwent(spw, fd);
	}
	else
	{
		/* the system is using shadow */
		stp = getspnam(user);

		if (stp == 0)
		{
			return 1;
		}

		/* old system with only passwd */
		if (auth_crypt_pwd(stp->sp_pwdp, newpwd, hash) != 0)
		{
			ulckpwdf();
			return 1;
		}

		stp->sp_pwdp = g_strdup(hash);
		today = g_time1() / SECS_PER_DAY;
		stp->sp_lstchg = today;
		stp->sp_expire = today + stp->sp_max + stp->sp_inact;
		fd = fopen("/etc/shadow", "rw");
		putspent(stp, fd);
	}

	ulckpwdf();
	return 0;
}
Beispiel #18
0
gchar *
mdm_verify_user (MdmDisplay *d,
		 const char *username,
		 gboolean allow_retry)
{
	gchar *login, *passwd, *ppasswd;
	struct passwd *pwent;
	struct spwd *sp;
#if defined (HAVE_PASSWDEXPIRED) && defined (HAVE_CHPASS)	\
	|| defined (HAVE_LOGINRESTRICTIONS)
	gchar *message = NULL;
#endif
#if defined (HAVE_PASSWDEXPIRED) && defined (HAVE_CHPASS)
	gchar *info_msg = NULL, *response = NULL;
	gint reEnter, ret;
#endif

	if (d->attached && d->timed_login_ok)
		mdm_slave_greeter_ctl_no_ret (MDM_STARTTIMER, "");

	if (username == NULL) {
	authenticate_again:
		/* Ask for the user's login */
		mdm_verify_select_user (NULL);
		mdm_slave_greeter_ctl_no_ret (MDM_MSG, _("Please enter your username"));
		login = mdm_slave_greeter_ctl (MDM_PROMPT, _("Username:"******"");
				g_free (login);
				return NULL;
			}
		}
		mdm_slave_greeter_ctl_no_ret (MDM_MSG, "");

		if (mdm_daemon_config_get_value_bool (MDM_KEY_DISPLAY_LAST_LOGIN)) {
			char *info = mdm_get_last_info (login);
			mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, info);
			g_free (info);
		}
	} else {
		login = g_strdup (username);
	}
	mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, login);

	pwent = getpwnam (login);

	setspent ();

	/* Lookup shadow password */
	sp = getspnam (login);

	/* Use shadow password when available */
	if (sp != NULL) {
		ppasswd = g_strdup (sp->sp_pwdp);
	} else {
		/* In case shadow password cannot be retrieved (when using NIS
		   authentication for example), use standard passwd */
		if (pwent != NULL &&
		    pwent->pw_passwd != NULL)
			ppasswd = g_strdup (pwent->pw_passwd);
		else
			/* If no password can be retrieved, set it to NULL */
			ppasswd = NULL;
	}

	endspent ();

	/* Request the user's password */
	if (pwent != NULL &&
	    ve_string_empty (ppasswd)) {
		/* eeek a passwordless account */
		passwd = g_strdup ("");
	} else {
		passwd = mdm_slave_greeter_ctl (MDM_NOECHO, _("Password:"******"");
		if (mdm_slave_greeter_check_interruption ()) {
			if (d->attached)
				mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, "");
			g_free (login);
			g_free (passwd);
			g_free (ppasswd);
			return NULL;
		}
	}

	if (d->attached)
		mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, "");

	if (pwent == NULL) {
		mdm_sleep_no_signal (mdm_daemon_config_get_value_int (MDM_KEY_RETRY_DELAY));
		mdm_debug ("Couldn't authenticate user");

		print_cant_auth_errbox ();

		g_free (login);
		g_free (passwd);
		g_free (ppasswd);
		return NULL;
	}

	/* Check whether password is valid */
	if (ppasswd == NULL || (ppasswd[0] != '\0' &&
				strcmp (crypt (passwd, ppasswd), ppasswd) != 0)) {
		mdm_sleep_no_signal (mdm_daemon_config_get_value_int (MDM_KEY_RETRY_DELAY));
		mdm_debug ("Couldn't authenticate user");

		print_cant_auth_errbox ();

		g_free (login);
		g_free (passwd);
		g_free (ppasswd);
		return NULL;
	}

	if (( ! mdm_daemon_config_get_value_bool (MDM_KEY_ALLOW_ROOT) ||
	    ( ! mdm_daemon_config_get_value_bool (MDM_KEY_ALLOW_REMOTE_ROOT) &&
              ! d->attached)) && pwent->pw_uid == 0) {

		mdm_debug ("Root login disallowed on display '%s'", d->name);
		mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX,
					      _("The system administrator "
						"is not allowed to login "
						"from this screen"));
		/*mdm_slave_greeter_ctl_no_ret (MDM_ERRDLG,
		  _("Root login disallowed"));*/
		g_free (login);
		g_free (passwd);
		g_free (ppasswd);
		return NULL;
	}

#ifdef HAVE_LOGINRESTRICTIONS

	/* Check with the 'loginrestrictions' function
	   if the user has been disallowed */
	if (loginrestrictions (login, 0, NULL, &message) != 0) {
		mdm_debug ("User not allowed to log in");
		mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX,
					      _("\nThe system administrator "
						"has disabled your "
						"account."));
		g_free (login);
		g_free (passwd);
		g_free (ppasswd);
		if (message != NULL)
			free (message);
		return NULL;
	}

	if (message != NULL)
		free (message);
	message = NULL;

#else /* ! HAVE_LOGINRESTRICTIONS */

	/* check for the standard method of disallowing users */
	if (pwent->pw_shell != NULL &&
	    (strcmp (pwent->pw_shell, NOLOGIN) == 0 ||
	     strcmp (pwent->pw_shell, "/bin/true") == 0 ||
	     strcmp (pwent->pw_shell, "/bin/false") == 0)) {
		mdm_debug ("User not allowed to log in");
		mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX,
					      _("\nThe system administrator "
						"has disabled your "
						"account."));
		/*mdm_slave_greeter_ctl_no_ret (MDM_ERRDLG,
		  _("Login disabled"));*/
		g_free (login);
		g_free (passwd);
		g_free (ppasswd);
		return NULL;
	}

#endif /* HAVE_LOGINRESTRICTIONS */

	g_free (passwd);
	g_free (ppasswd);

	if ( ! mdm_slave_check_user_wants_to_log_in (login)) {
		g_free (login);
		login = NULL;
		goto authenticate_again;
	}

	if ( ! mdm_setup_gids (login, pwent->pw_gid)) {
		mdm_debug ("Cannot set user group");
		mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX,
					      _("\nCannot set your user group; "
						"you will not be able to log in. "
						"Please contact your system administrator."));
		g_free (login);
		return NULL;
	}

#if defined (HAVE_PASSWDEXPIRED) && defined (HAVE_CHPASS)

	switch (passwdexpired (login, &info_msg)) {
	case 1 :
		mdm_debug ("User password has expired");
		mdm_errorgui_error_box (d, GTK_MESSAGE_ERROR,
					_("You are required to change your password.\n"
					  "Please choose a new one."));
		g_free (info_msg);

		do {
			ret = chpass (login, response, &reEnter, &message);
			g_free (response);

			if (ret != 1) {
				if (ret != 0) {
					mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX,
								      _("\nCannot change your password; "
									"you will not be able to log in. "
									"Please try again later or contact "
									"your system administrator."));
				} else if ((reEnter != 0) && (message)) {
					response = mdm_slave_greeter_ctl (MDM_NOECHO, message);
					if (response == NULL)
						response = g_strdup ("");
				}
			}

			g_free (message);
			message = NULL;

		} while ( ((reEnter != 0) && (ret == 0))
			  || (ret ==1) );

		g_free (response);
		g_free (message);

		if ((ret != 0) || (reEnter != 0)) {
			return NULL;
		}

#if defined (CAN_CLEAR_ADMCHG)
		/* The password is changed by root, clear the ADM_CHG
		   flag in the passwd file */
		ret = setpwdb (S_READ | S_WRITE);
		if (!ret) {
			upwd = getuserpw (login);
			if (upwd == NULL) {
				ret = -1;
			}
			else {
				upwd->upw_flags &= ~PW_ADMCHG;
				ret = putuserpw (upwd);
				if (!ret) {
					ret = endpwdb ();
				}
			}
		}

		if (ret) {
			mdm_errorgui_error_box (d, GTK_MESSAGE_WARNING,
						_("Your password has been changed but "
						  "you may have to change it again. "
						  "Please try again later or contact "
						  "your system administrator."));
		}

#else /* !CAN_CLEAR_ADMCHG */
		mdm_errorgui_error_box (d, GTK_MESSAGE_WARNING,
					_("Your password has been changed but you "
					  "may have to change it again. Please try again "
					  "later or contact your system administrator."));

#endif /* CAN_CLEAR_ADMCHG */

		break;

	case 2 :
		mdm_debug ("User password has expired");
		mdm_errorgui_error_box (d, GTK_MESSAGE_ERROR,
					_("Your password has expired.\n"
					  "Only a system administrator can now change it"));
		g_free (info_msg);
		return NULL;
		break;

	case -1 :
		mdm_debug ("Internal error on passwdexpired");
		mdm_errorgui_error_box (d, GTK_MESSAGE_ERROR,
					_("An internal error occurred. You will not be able to log in.\n"
					  "Please try again later or contact your system administrator."));
		g_free (info_msg);
		return NULL;
		break;

	default :
		g_free (info_msg);
		break;
	}

#endif /* HAVE_PASSWDEXPIRED && HAVE_CHPASS */

	return login;
}
Beispiel #19
0
int
check_passwd(stralloc *login, stralloc *authdata,
    struct credentials *c, int fast)
{
	int ret;
	struct passwd *pw;
#ifdef PW_SHADOW
	struct spwd *spw;
#endif
#ifdef AIX
	struct userpw *spw;
#endif

	if (localdelivery() == 0) return NOSUCH;

	pw = getpwnam(login->s);
	if (!pw) {
		/* XXX: unfortunately getpwnam() hides temporary errors */
		logit(32, "check_passwd: user %s not found in passwd db\n",
		    login->s);
		return NOSUCH;
	}
	logit(32, "check_passwd: user %s found in passwd db\n",
	    login->s);
	if (!fast) {
		c->gid = pw->pw_gid;
		c->uid = pw->pw_uid;
		/*
		 * Here we don't check the home and maildir path, if a user
		 * has a faked passwd entry, then you have a bigger problem
		 * on your system than just a guy how can read the mail of
		 * other users/customers.
		 */
		if (!stralloc_copys(&c->home, pw->pw_dir))
			return ERRNO;
		if (!stralloc_0(&c->home))
			return ERRNO;
	
		ret = get_local_maildir(&c->home, &c->maildir);
		if (ret != 0)
			return ret;
		logit(32, "get_local_maildir: maildir=%s\n", c->maildir.s);
	}

#ifdef PW_SHADOW
	spw = getspnam(login->s);
	if (!spw)
		/* XXX: again, temp hidden */
		return FAILED;
	ret = cmp_passwd((unsigned char*) authdata->s, spw->sp_pwdp);
#else /* no PW_SHADOW */
#ifdef AIX
	spw = getuserpw(login->s);
	if (!spw)
		/* XXX: and again */
		return FAILED;
	ret = cmp_passwd((unsigned char*) authdata->s, spw->upw_passwd);
#else /* no AIX */
	ret = cmp_passwd((unsigned char*) authdata->s, pw->pw_passwd);
#endif /* END AIX */
#endif /* END PW_SHADOW */
	logit(32, "check_pw: password compare was %s\n", 
	    ret==OK?"successful":"not successful");
	return ret;
}
Beispiel #20
0
static int _pam_auth_smb(	pam_handle_t *pamh,
				int flags, 
				int argc,
				const char **argv	) 
{
        int retval;
	struct passwd *pw;
	const char *name;
	char *p, *pp;
	int w,loop;
	const char *salt;
	char server[80],server2[80],domain[80];
	char ntname[32];
	int debug=0, use_first_pass=0;
	int nolocal=0;

#ifdef HAVE_SHADOW_H

	struct spwd *sp;

#endif

	/* Parse Command line options */
  
	for (loop=0; loop<argc; loop++)
	  {
	    if (!strcmp(argv[loop], "debug"))
	      debug=1;
	    else 
	      if (!strcmp(argv[loop], "use_first_pass"))
		use_first_pass=1;
	      else
		if (!strcmp(argv[loop], "nolocal"))
		  nolocal=1;
		else
		  syslog(LOG_AUTHPRIV | LOG_ERR, "pam_smb: Unknown Command Line Option in pam.d : %s", argv[loop]);
	  }
	   
	/* get the user'name' */
	
	if ( (retval = pam_get_user( pamh, &name, "login: "******"x")))
		  {
		    /* TODO: check if password has expired etc. */
		    salt = sp->sp_pwdp;
		  } 
		else
#endif
		  salt = pw->pw_passwd;
	      } 
	    else  
	      return PAM_USER_UNKNOWN;
	    
	    /* The 'always-encrypt' method does not make sense in PAM
	       because the framework requires return of a different
	       error code for non-existant users -- alex */
	    
	    if ( ( !pw->pw_passwd ) && ( !p ) )
	      if ( flags && PAM_DISALLOW_NULL_AUTHTOK )
		return PAM_SUCCESS;
	    
	    pp = crypt(p, salt);
	    
	    if ( strcmp( pp, salt ) == 0 )
	      {
		if (debug) 
		  syslog(LOG_AUTHPRIV | LOG_DEBUG, "pam_smb: Local UNIX username/password pair correct.");
		return  PAM_SUCCESS;
	      }
	    
	    if (debug) {
	      syslog (LOG_AUTHPRIV | LOG_DEBUG, "pam_smb: Local UNIX username/password check incorrect.");
	    }
	  } /* End of Local Section */
	else { /* If Local System Authentication is switched off */
	  if (debug) syslog(LOG_AUTHPRIV | LOG_DEBUG,"No Local authentication done, relying on other modules for password file entry.");
	}

	w=smb_readpamconf(server,server2,domain);
	if (w!=0) 
	  {
	    syslog(LOG_AUTHPRIV | LOG_ALERT, "pam_smb: Missing Configuration file : /etc/pam_smb.conf");
	    return PAM_AUTHINFO_UNAVAIL;
	  }
	
	if (debug) {
	  syslog(LOG_AUTHPRIV | LOG_DEBUG, "pam_smb: Configuration Data, Primary %s, Backup %s, Domain %s.", server, server2, domain);
	}

	w=Valid_User(ntname, p, server, server2,  domain);
		  
	/* Users valid user for return value 0 is success
	   1 and 2 indicate Network and protocol failures and
	   3 is not logged on 
	   */

	switch (w)
	  {
	  case 0 : 
	    if (debug) syslog(LOG_AUTHPRIV | LOG_DEBUG, "pam_smb: Correct NT username/password pair");
	    return PAM_SUCCESS; break;
	  case 1 :
	  case 2 :
	    return PAM_AUTHINFO_UNAVAIL; break;
	  case 3 :
	  default:
	    syslog(LOG_AUTHPRIV | LOG_NOTICE, "pam_smb: Incorrect NT password for username : %s", ntname);
	    return PAM_AUTH_ERR; break;
	  }

  	return PAM_AUTH_ERR;

}
Beispiel #21
0
int sulogin_main(int argc, char **argv)
{
	char *cp;
	char *device = NULL;
	const char *name = "root";
	int timeout = 0;

#define pass bb_common_bufsiz1

	struct passwd pwent;
	struct passwd *pwd;
	const char * const *p;
#if ENABLE_FEATURE_SHADOWPASSWDS
	struct spwd *spwd = NULL;
#endif

	openlog("sulogin", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
	if (argc > 1) {
		if (strncmp(argv[1], "-t", 2) == 0) {
			if (argv[1][2] == '\0') { /* -t NN */
				if (argc > 2) {
					timeout = atoi(argv[2]);
					if (argc > 3) {
						device = argv[3];
					}
				}
			} else { /* -tNNN */
				timeout = atoi(&argv[1][2]);
				if (argc > 2) {
					device = argv[2];
				}
			}
		} else {
			device = argv[1];
		}
		if (device) {
			close(0);
			close(1);
			close(2);
			if (open(device, O_RDWR) == 0) {
				dup(0);
				dup(0);
			} else {
				syslog(LOG_WARNING, "cannot open %s\n", device);
				exit(EXIT_FAILURE);
			}
		}
	}
	if (access(bb_path_passwd_file, 0) == -1) {
		syslog(LOG_WARNING, "No password file\n");
		bb_error_msg_and_die("No password file\n");
	}
	if (!isatty(0) || !isatty(1) || !isatty(2)) {
		exit(EXIT_FAILURE);
	}


	/* Clear out anything dangerous from the environment */
	for (p = forbid; *p; p++)
		unsetenv(*p);


	signal(SIGALRM, catchalarm);
	if (!(pwd = getpwnam(name))) {
		syslog(LOG_WARNING, "No password entry for `root'\n");
		bb_error_msg_and_die("No password entry for `root'\n");
	}
	pwent = *pwd;
#if ENABLE_FEATURE_SHADOWPASSWDS
	spwd = NULL;
	if (pwd && ((strcmp(pwd->pw_passwd, "x") == 0)
				|| (strcmp(pwd->pw_passwd, "*") == 0))) {
		endspent();
		spwd = getspnam(name);
		if (spwd) {
			pwent.pw_passwd = spwd->sp_pwdp;
		}
	}
#endif
	while (1) {
		cp = bb_askpass(timeout, SULOGIN_PROMPT);
		if (!cp || !*cp) {
			puts("\n");
			fflush(stdout);
			syslog(LOG_INFO, "Normal startup\n");
			exit(EXIT_SUCCESS);
		} else {
			safe_strncpy(pass, cp, sizeof(pass));
			memset(cp, 0, strlen(cp));
		}
		if (strcmp(pw_encrypt(pass, pwent.pw_passwd), pwent.pw_passwd) == 0) {
			break;
		}
		bb_do_delay(FAIL_DELAY);
		puts("Login incorrect");
		fflush(stdout);
		syslog(LOG_WARNING, "Incorrect root password\n");
	}
	memset(pass, 0, strlen(pass));
	signal(SIGALRM, SIG_DFL);
	puts("Entering System Maintenance Mode\n");
	fflush(stdout);
	syslog(LOG_INFO, "System Maintenance Mode\n");

#if ENABLE_SELINUX
	renew_current_security_context();
#endif

	run_shell(pwent.pw_shell, 1, 0, 0);

	return (0);
}
Beispiel #22
0
void
shadowauth(const char *myname, int persist)
{
	const char *hash;
	char *encrypted;
	struct passwd *pw;
	char *challenge, *response, rbuf[1024], cbuf[128];

#ifdef USE_TIMESTAMP
	int fd = -1;
	int valid = 0;

	if (persist)
		fd = timestamp_open(&valid, 5 * 60);
	if (fd != -1 && valid == 1)
		goto good;
#else
	(void) persist;
#endif

	if ((pw = getpwnam(myname)) == NULL)
		err(1, "getpwnam");

	hash = pw->pw_passwd;
	if (hash[0] == 'x' && hash[1] == '\0') {
		struct spwd *sp;
		if ((sp = getspnam(myname)) == NULL)
			errx(1, "Authorization failed");
		hash = sp->sp_pwdp;
	} else if (hash[0] != '*') {
		errx(1, "Authorization failed");
	}

	char host[HOST_NAME_MAX + 1];
	if (gethostname(host, sizeof(host)))
		snprintf(host, sizeof(host), "?");
	snprintf(cbuf, sizeof(cbuf),
			"\rdoas (%.32s@%.32s) password: "******"tty required for %s", myname);
		errx(1, "a tty is required");
	}
	if (response == NULL)
		err(1, "readpassphrase");
	if ((encrypted = crypt(response, hash)) == NULL) {
		explicit_bzero(rbuf, sizeof(rbuf));
		errx(1, "Authorization failed");
	}
	explicit_bzero(rbuf, sizeof(rbuf));
	if (strcmp(encrypted, hash) != 0) {
		syslog(LOG_AUTHPRIV | LOG_NOTICE, "failed auth for %s", myname);
		errx(1, "Authorization failed");
	}

#ifdef USE_TIMESTAMP
good:
	if (fd != -1) {
		timestamp_set(fd, 5 * 60);
		close(fd);
	}
#endif
}
Beispiel #23
0
void pw_unix_check(AuthResult * const result,
                   const char *account, const char *password,
                   const struct sockaddr_storage * const sa,
                   const struct sockaddr_storage * const peer)
{
    const char *cpwd = NULL;
    struct passwd pw, *pw_;
#ifdef USE_SHADOW
    struct spwd *spw;
#endif
    char *dir = NULL;

    (void) sa;
    (void) peer;
    result->auth_ok = 0;
    if ((pw_ = getpwnam(account)) == NULL) {
        return;
    }
    pw = *pw_;
    result->auth_ok--;
#ifdef HAVE_SETUSERSHELL
    if (pw.pw_shell == NULL) {
        return;
    }
    if (strcasecmp(pw.pw_shell, FAKE_SHELL) != 0) {
        const char *shell;
        
        setusershell();
        while ((shell = (char *) getusershell()) != NULL &&
               strcmp(pw.pw_shell, shell) != 0);
        endusershell();
        if (shell == NULL) {
            return;
        }
    }    
#endif
    if ((dir = strdup(pw.pw_dir)) == NULL) {
        return;
    }
#ifdef USE_SHADOW
    if ((((pw.pw_passwd)[0] == 'x' && (pw.pw_passwd)[1] == 0) ||
         ((pw.pw_passwd)[0] == '#' && (pw.pw_passwd)[1] == '#' &&
          strcmp(pw.pw_passwd + 2, account) == 0)) &&
        (spw = getspnam(account)) != NULL && spw->sp_pwdp != NULL) {
        cpwd = spw->sp_pwdp[0] == '@' ? NULL : spw->sp_pwdp;
        if (spw->sp_expire > 0 || spw->sp_max > 0) {
            long today = time(NULL) / (24L * 60L * 60L);

            if (spw->sp_expire > 0 && spw->sp_expire < today) {
                goto bye;               /* account expired */
            }
            if (spw->sp_max > 0 && spw->sp_lstchg > 0 &&
                (spw->sp_lstchg + spw->sp_max < today)) {
                goto bye;               /* password expired */
            }
        }
    } else
#endif
    {
        cpwd = pw.pw_passwd;
    }
    {
        const char *crypted;
        
        if (cpwd == NULL ||
            (crypted = (const char *) crypt(password, cpwd)) == NULL ||
            strcmp(cpwd, crypted) != 0) {
            goto bye;
        }
    }
    result->uid = pw.pw_uid;
    result->gid = pw.pw_gid;
    result->dir = dir;
    result->slow_tilde_expansion = 0;
    result->auth_ok = -result->auth_ok;
    return;
    
    bye:
    free(dir);
}
Beispiel #24
0
int post_passwd_server(int client, char *ibuf, int len, char *torken)
{
        if(torken){
                return response_state(client, NO_SERVICE, err_msg[NO_SERVICE]);
        }

        ezxml_t root = NULL, name=NULL, oldpasswd=NULL, passwd=NULL;

        root = ezxml_parse_str(ibuf, len);
        if(!root){
                ezxml_free(root);
                return response_state(client, FORMAT_ERR, err_msg[FORMAT_ERR]);
        }
        if(root && *ezxml_error(root)) {
                ezxml_free(root);
                return response_state(client, FORMAT_ERR, err_msg[FORMAT_ERR]);
        }

        name = ezxml_child(root, "USER_NAME");
        oldpasswd = ezxml_child(root, "OLD_PASSWD");
        passwd = ezxml_child(root, "PASSWD");

        if(!name || !name->txt[0] ||
                        !oldpasswd ||!oldpasswd->txt[0] ||
                        !passwd || !passwd->txt[0]){
                return response_state(client, FORMAT_ERR,
                                "Need name oldpasswd and new passwd"
                                );
        }

        char salt[128] = {0}, *ptr = 0;
        struct spwd *pw = getspnam(name->txt);
        if(!pw){
                return response_state(client, SYS_ERR,
                                "Invalid name");
        }

        ptr = strchr(pw->sp_pwdp+1, '$');
        if(!ptr){
                return response_state(client, SYS_ERR,
                                "Unkonw passwd format");
        }
        ptr = strchr(ptr+1, '$');
        if(!ptr){
                return response_state(client, SYS_ERR,
                                "Unkonw passwd format");
        }
        strncpy(salt, pw->sp_pwdp, ptr-pw->sp_pwdp);

        ptr = crypt(oldpasswd->txt, salt);
        if(strcmp(ptr, pw->sp_pwdp)){
                return response_state(client, SYS_ERR, "Invalid old passwd");
        }

        char cmd[XMLLEN] = {0};
        snprintf(cmd, sizeof(cmd), "echo -e '%s\n%s'|/usr/bin/passwd",
                        passwd->txt, passwd->txt);
        system(cmd);
        return 0;

}
Beispiel #25
0
Datei: su.c Projekt: Sp1l/heimdal
int
main(int argc, char **argv)
{
    int i, optidx = 0;
    char *su_user;
    struct passwd *su_info;
    struct passwd *login_info;

    struct passwd *pwd;

    char *shell;

    int ok = 0;

    setprogname (argv[0]);

    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
	usage(1);

    for (i=0; i < optidx; i++)
      if (strcmp(argv[i], "-") == 0) {
	 full_login = 1;
	 break;
      }

    if(help_flag)
	usage(0);
    if(version_flag) {
	print_version(NULL);
	exit(0);
    }
    if(optidx >= argc)
	su_user = "******";
    else
	su_user = argv[optidx++];

    if (!issuid() && getuid() != 0)
	warnx("Not setuid and you are not root, expect this to fail");

    pwd = k_getpwnam(su_user);
    if(pwd == NULL)
	errx (1, "unknown login %s", su_user);
    if (pwd->pw_uid == 0 && strcmp ("root", su_user) != 0) {
	syslog (LOG_ALERT, "NIS attack, user %s has uid 0", su_user);
	errx (1, "unknown login %s", su_user);
    }
    su_info = dup_info(pwd);
    if (su_info == NULL)
	errx (1, "malloc: out of memory");

	pwd = getpwuid(getuid());
    if(pwd == NULL)
	errx(1, "who are you?");
    login_info = dup_info(pwd);
    if (login_info == NULL)
	errx (1, "malloc: out of memory");
    if(env_flag)
	shell = login_info->pw_shell;
    else
	shell = su_info->pw_shell;
    if(shell == NULL || *shell == '\0')
	shell = _PATH_BSHELL;


#ifdef KRB5
    if(kerberos_flag && ok == 0 &&
       krb5_verify(login_info, su_info, kerberos_instance) == 0)
	ok = 5;
#endif

    if(ok == 0 && login_info->pw_uid && verify_unix(login_info, su_info) != 0) {
	printf("Sorry!\n");
	exit(1);
    }

#ifdef HAVE_GETSPNAM
   {  struct spwd *sp;
      long    today;

    sp = getspnam(su_info->pw_name);
    if (sp != NULL) {
	today = time(0)/(24L * 60 * 60);
	if (sp->sp_expire > 0) {
	    if (today >= sp->sp_expire) {
		if (login_info->pw_uid)
		    errx(1,"Your account has expired.");
		else
		    printf("Your account has expired.");
            }
            else if (sp->sp_expire - today < 14)
                printf("Your account will expire in %d days.\n",
		       (int)(sp->sp_expire - today));
	}
	if (sp->sp_max > 0) {
	    if (today >= sp->sp_lstchg + sp->sp_max) {
		if (login_info->pw_uid)
		    errx(1,"Your password has expired. Choose a new one.");
		else
		    printf("Your password has expired. Choose a new one.");
	    }
	    else if (today >= sp->sp_lstchg + sp->sp_max - sp->sp_warn)
		printf("Your account will expire in %d days.\n",
		       (int)(sp->sp_lstchg + sp->sp_max -today));
	}
    }
    }
#endif
    {
	char *tty = ttyname (STDERR_FILENO);
	if (tty)
	    syslog (LOG_NOTICE | LOG_AUTH, "%s to %s on %s",
		    login_info->pw_name, su_info->pw_name, tty);
	else
	    syslog (LOG_NOTICE | LOG_AUTH, "%s to %s",
		    login_info->pw_name, su_info->pw_name);
    }


    if(!env_flag) {
	if(full_login) {
	    char *t = getenv ("TERM");
	    char **newenv = NULL;
	    int j;

	    i = read_environment(_PATH_ETC_ENVIRONMENT, &newenv);

	    environ = malloc ((10 + i) * sizeof (char *));
	    if (environ == NULL)
		err (1, "malloc");
	    environ[0] = NULL;

	    for (j = 0; j < i; j++) {
		char *p = strchr(newenv[j], '=');
		if (p == NULL)
		    errx(1, "environment '%s' missing '='", newenv[j]);
		*p++ = 0;
		esetenv (newenv[j], p, 1);
	    }
	    free(newenv);

	    esetenv ("PATH", _PATH_DEFPATH, 1);
	    if (t)
		esetenv ("TERM", t, 1);
	    if (chdir (su_info->pw_dir) < 0)
		errx (1, "no directory");
	}
	if (full_login || su_info->pw_uid)
	    esetenv ("USER", su_info->pw_name, 1);
	esetenv("HOME", su_info->pw_dir, 1);
	esetenv("SHELL", shell, 1);
    }

    {
	char **new_argv;
	char *p;

	p = strrchr(shell, '/');
	if(p)
	    p++;
	else
	    p = shell;

	if (strcmp(p, "csh") != 0)
	    csh_f_flag = 0;

        new_argv = malloc(((cmd ? 2 : 0) + 1 + argc - optidx + 1 + csh_f_flag)
	    * sizeof(*new_argv));
	if (new_argv == NULL)
	    err (1, "malloc");
	i = 0;
	if(full_login) {
	    if (asprintf(&new_argv[i++], "-%s", p) == -1)
		errx (1, "malloc");
	} else
	    new_argv[i++] = p;
	if (cmd) {
	   new_argv[i++] = "-c";
	   new_argv[i++] = cmd;
	}

	if (csh_f_flag)
	    new_argv[i++] = "-f";

	for (argv += optidx; *argv; ++argv)
	   new_argv[i++] = *argv;
	new_argv[i] = NULL;

	if(setgid(su_info->pw_gid) < 0)
	    err(1, "setgid");
	if (initgroups (su_info->pw_name, su_info->pw_gid) < 0)
	    err (1, "initgroups");
	if(setuid(su_info->pw_uid) < 0
	   || (su_info->pw_uid != 0 && setuid(0) == 0))
	    err(1, "setuid");

#ifdef KRB5
        if (ok == 5)
           krb5_start_session();
#endif
	execve(shell, new_argv, environ);
    }

    exit(1);
}
Beispiel #26
0
static int process_root_password(void) {

        static const char table[] =
                "abcdefghijklmnopqrstuvwxyz"
                "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                "0123456789"
                "./";

        struct spwd item = {
                .sp_namp = (char*) "root",
                .sp_min = -1,
                .sp_max = -1,
                .sp_warn = -1,
                .sp_inact = -1,
                .sp_expire = -1,
                .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */
        };

        _cleanup_close_ int lock = -1;
        char salt[3+16+1+1];
        uint8_t raw[16];
        unsigned i;
        char *j;

        const char *etc_shadow;
        int r;

        etc_shadow = prefix_roota(arg_root, "/etc/shadow");
        if (laccess(etc_shadow, F_OK) >= 0)
                return 0;

        mkdir_parents(etc_shadow, 0755);

        lock = take_etc_passwd_lock(arg_root);
        if (lock < 0)
                return log_error_errno(lock, "Failed to take a lock: %m");

        if (arg_copy_root_password && arg_root) {
                struct spwd *p;

                errno = 0;
                p = getspnam("root");
                if (p || errno != ENOENT) {
                        if (!p) {
                                if (!errno)
                                        errno = EIO;

                                return log_error_errno(errno, "Failed to find shadow entry for root: %m");
                        }

                        r = write_root_shadow(etc_shadow, p);
                        if (r < 0)
                                return log_error_errno(r, "Failed to write %s: %m", etc_shadow);

                        log_info("%s copied.", etc_shadow);
                        return 0;
                }
        }

        r = prompt_root_password();
        if (r < 0)
                return r;

        if (!arg_root_password)
                return 0;

        /* Insist on the best randomness by setting RANDOM_BLOCK, this is about keeping passwords secret after all. */
        r = genuine_random_bytes(raw, 16, RANDOM_BLOCK);
        if (r < 0)
                return log_error_errno(r, "Failed to get salt: %m");

        /* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */
        assert_cc(sizeof(table) == 64 + 1);
        j = stpcpy(salt, "$6$");
        for (i = 0; i < 16; i++)
                j[i] = table[raw[i] & 63];
        j[i++] = '$';
        j[i] = 0;

        errno = 0;
        item.sp_pwdp = crypt(arg_root_password, salt);
        if (!item.sp_pwdp) {
                if (!errno)
                        errno = EINVAL;

                return log_error_errno(errno, "Failed to encrypt password: %m");
        }

        item.sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);

        r = write_root_shadow(etc_shadow, &item);
        if (r < 0)
                return log_error_errno(r, "Failed to write %s: %m", etc_shadow);

        log_info("%s written.", etc_shadow);
        return 0;
}

static int help(void) {
        _cleanup_free_ char *link = NULL;
        int r;

        r = terminal_urlify_man("systemd-firstboot", "1", &link);
        if (r < 0)
                return log_oom();

        printf("%s [OPTIONS...]\n\n"
               "Configures basic settings of the system.\n\n"
               "  -h --help                    Show this help\n"
               "     --version                 Show package version\n"
               "     --root=PATH               Operate on an alternate filesystem root\n"
               "     --locale=LOCALE           Set primary locale (LANG=)\n"
               "     --locale-messages=LOCALE  Set message locale (LC_MESSAGES=)\n"
               "     --keymap=KEYMAP           Set keymap\n"
               "     --timezone=TIMEZONE       Set timezone\n"
               "     --hostname=NAME           Set host name\n"
               "     --machine-ID=ID           Set machine ID\n"
               "     --root-password=PASSWORD  Set root password\n"
               "     --root-password-file=FILE Set root password from file\n"
               "     --prompt-locale           Prompt the user for locale settings\n"
               "     --prompt-keymap           Prompt the user for keymap settings\n"
               "     --prompt-timezone         Prompt the user for timezone\n"
               "     --prompt-hostname         Prompt the user for hostname\n"
               "     --prompt-root-password    Prompt the user for root password\n"
               "     --prompt                  Prompt for all of the above\n"
               "     --copy-locale             Copy locale from host\n"
               "     --copy-keymap             Copy keymap from host\n"
               "     --copy-timezone           Copy timezone from host\n"
               "     --copy-root-password      Copy root password from host\n"
               "     --copy                    Copy locale, keymap, timezone, root password\n"
               "     --setup-machine-id        Generate a new random machine ID\n"
               "\nSee the %s for details.\n"
               , program_invocation_short_name
               , link
        );

        return 0;
}
Beispiel #27
0
/*
 * Check if the user is allowed to log in via ssh. If user is listed
 * in DenyUsers or one of user's groups is listed in DenyGroups, false
 * will be returned. If AllowUsers isn't empty and user isn't listed
 * there, or if AllowGroups isn't empty and one of user's groups isn't
 * listed there, false will be returned.
 * If the user's shell is not executable, false will be returned.
 * Otherwise true is returned.
 */
int
allowed_user(struct passwd * pw)
{
	struct stat st;
	const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL;
	u_int i;
#ifdef USE_SHADOW
	struct spwd *spw = NULL;
#endif

	/* Shouldn't be called if pw is NULL, but better safe than sorry... */
	if (!pw || !pw->pw_name)
		return 0;

#ifdef USE_SHADOW
	if (!options.use_pam)
		spw = getspnam(pw->pw_name);
#ifdef HAS_SHADOW_EXPIRE
	if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw))
		return 0;
#endif /* HAS_SHADOW_EXPIRE */
#endif /* USE_SHADOW */

	/* grab passwd field for locked account check */
	passwd = pw->pw_passwd;
#ifdef USE_SHADOW
	if (spw != NULL)
#ifdef USE_LIBIAF
		passwd = get_iaf_password(pw);
#else
		passwd = spw->sp_pwdp;
#endif /* USE_LIBIAF */
#endif

	/* check for locked account */
	if (!options.use_pam && passwd && *passwd) {
		int locked = 0;

#ifdef LOCKED_PASSWD_STRING
		if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0)
			 locked = 1;
#endif
#ifdef LOCKED_PASSWD_PREFIX
		if (strncmp(passwd, LOCKED_PASSWD_PREFIX,
		    strlen(LOCKED_PASSWD_PREFIX)) == 0)
			 locked = 1;
#endif
#ifdef LOCKED_PASSWD_SUBSTR
		if (strstr(passwd, LOCKED_PASSWD_SUBSTR))
			locked = 1;
#endif
#ifdef USE_LIBIAF
		free((void *) passwd);
#endif /* USE_LIBIAF */
		if (locked) {
			logit("User %.100s not allowed because account is locked",
			    pw->pw_name);
			return 0;
		}
	}

	/*
	 * Deny if shell does not exist or is not executable unless we
	 * are chrooting.
	 */
	if (options.chroot_directory == NULL ||
	    strcasecmp(options.chroot_directory, "none") == 0) {
		char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
		    _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */

		if (stat(shell, &st) != 0) {
			logit("User %.100s not allowed because shell %.100s "
			    "does not exist", pw->pw_name, shell);
			xfree(shell);
			return 0;
		}
		if (S_ISREG(st.st_mode) == 0 ||
		    (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
			logit("User %.100s not allowed because shell %.100s "
			    "is not executable", pw->pw_name, shell);
			xfree(shell);
			return 0;
		}
		xfree(shell);
	}

	if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
	    options.num_deny_groups > 0 || options.num_allow_groups > 0) {
		hostname = get_canonical_hostname(options.use_dns);
		ipaddr = get_remote_ipaddr();
	}

	/* Return false if user is listed in DenyUsers */
	if (options.num_deny_users > 0) {
		for (i = 0; i < options.num_deny_users; i++)
			if (match_user(pw->pw_name, hostname, ipaddr,
			    options.deny_users[i])) {
				logit("User %.100s from %.100s not allowed "
				    "because listed in DenyUsers",
				    pw->pw_name, hostname);
				return 0;
			}
	}
	/* Return false if AllowUsers isn't empty and user isn't listed there */
	if (options.num_allow_users > 0) {
		for (i = 0; i < options.num_allow_users; i++)
			if (match_user(pw->pw_name, hostname, ipaddr,
			    options.allow_users[i]))
				break;
		/* i < options.num_allow_users iff we break for loop */
		if (i >= options.num_allow_users) {
			logit("User %.100s from %.100s not allowed because "
			    "not listed in AllowUsers", pw->pw_name, hostname);
			return 0;
		}
	}
	if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
		/* Get the user's group access list (primary and supplementary) */
		if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
			logit("User %.100s from %.100s not allowed because "
			    "not in any group", pw->pw_name, hostname);
			return 0;
		}

		/* Return false if one of user's groups is listed in DenyGroups */
		if (options.num_deny_groups > 0)
			if (ga_match(options.deny_groups,
			    options.num_deny_groups)) {
				ga_free();
				logit("User %.100s from %.100s not allowed "
				    "because a group is listed in DenyGroups",
				    pw->pw_name, hostname);
				return 0;
			}
		/*
		 * Return false if AllowGroups isn't empty and one of user's groups
		 * isn't listed there
		 */
		if (options.num_allow_groups > 0)
			if (!ga_match(options.allow_groups,
			    options.num_allow_groups)) {
				ga_free();
				logit("User %.100s from %.100s not allowed "
				    "because none of user's groups are listed "
				    "in AllowGroups", pw->pw_name, hostname);
				return 0;
			}
		ga_free();
	}

#ifdef CUSTOM_SYS_AUTH_ALLOWED_USER
	if (!sys_auth_allowed_user(pw, &loginmsg))
		return 0;
#endif

	/* We found no reason not to let this user try to log on... */
	return 1;
}
Beispiel #28
0
static int
plogin(char *user, char *passwd, char **msg, int *msglen)
{

#ifdef USE_PAM

    struct pam_conv pam_conversation;
    pam_handle_t *pamh;
    int pam_error;
/*
 * Fill the pam_conversion structure
 */
    memset (&pam_conversation, '\0', sizeof (struct pam_conv));
    pam_conversation.conv = &pam_conv;

    pam_error = pam_start ("ppp", user, &pam_conversation, &pamh);

    if (pam_error != PAM_SUCCESS) {
        *msg = MY_PAM_STRERROR (pam_error);
	return UPAP_AUTHNAK;
    }
/*
 * Define the fields for the credintial validation
 */
    pam_set_item (pamh, PAM_TTY, devnam);
    PAM_username = user;
    PAM_password = passwd;
/*
 * Validate the user
 */
    pam_error = pam_authenticate (pamh, PAM_SILENT);
    if (pam_error == PAM_SUCCESS) {
        pam_error = pam_acct_mgmt (pamh, PAM_SILENT);

	/* start a session for this user. Session closed when link ends. */
	if (pam_error == PAM_SUCCESS)
	   pam_open_session (pamh, PAM_SILENT);
    }

    *msg = MY_PAM_STRERROR (pam_error);

    PAM_username =
    PAM_password = "";
/*
 * Clean up the mess
 */
    pam_end (pamh, pam_error);

    if (pam_error != PAM_SUCCESS)
        return UPAP_AUTHNAK;
/*
 * Use the non-PAM methods directly
 */
#else /* #ifdef USE_PAM */

    struct passwd *pw;
    struct utmp utmp;
    struct timeval tp;
    char *tty;

#ifdef HAS_SHADOW
    struct spwd *spwd;
    struct spwd *getspnam();
#endif

    pw = getpwnam(user);
    endpwent();
    if (pw == NULL) {
	return (UPAP_AUTHNAK);
    }
/*
 * Check that the user is not listed in /etc/ppp/ppp.deny
 * and that the user's shell is listed in /etc/ppp/ppp.shells
 * if /etc/ppp/ppp.shells exists.
 */

    if (checkfile(_PATH_PPPDENY, user) == 1) {
	    	syslog(LOG_WARNING, "upap user %s: login denied in %s",
			user, _PATH_PPPDENY);
		return (UPAP_AUTHNAK);
    }

    if (checkfile(_PATH_PPPSHELLS, pw->pw_shell) == 0) {
	    	syslog(LOG_WARNING, "upap user %s: shell %s not in %s",
			user, pw->pw_shell, _PATH_PPPSHELLS);
		return (UPAP_AUTHNAK);
    }

#ifdef HAS_SHADOW
    spwd = getspnam(user);
    endspent();
    if (spwd) {
	/* check the age of the password entry */
	long now = time(NULL) / 86400L;

	if ((spwd->sp_expire > 0 && now >= spwd->sp_expire)
	    || ((spwd->sp_max >= 0 && spwd->sp_max < 10000)
		&& spwd->sp_lstchg >= 0
		&& now >= spwd->sp_lstchg + spwd->sp_max)) {
	    syslog(LOG_WARNING, "Password for %s has expired", user);
	    return (UPAP_AUTHNAK);
	}
	pw->pw_passwd = spwd->sp_pwdp;
    }
#endif

    /*
     * If no passwd, don't let them login.
     */
    if (pw->pw_passwd == NULL || *pw->pw_passwd == '\0'
	|| strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd) != 0)
	return (UPAP_AUTHNAK);

    if (pw->pw_expire) {
	gettimeofday(&tp, NULL);
	if (tp.tv_sec >= pw->pw_expire) {
	    syslog(LOG_INFO, "pap user %s account expired", user);
	    return (UPAP_AUTHNAK);
	}
    }

    /* These functions are not enabled for PAM. The reason for this is that */
    /* there is not necessarily a "passwd" entry for this user. That is     */
    /* real purpose of 'PAM' -- to virtualize the account data from the     */
    /* application. If you want to do the same thing, write the entry in    */
    /* the 'session' hook.                                                  */

    /* Log in wtmp and utmp using login() */

    tty = devnam;
    if (strncmp(tty, _PATH_DEV, sizeof _PATH_DEV - 1) == 0)
	tty += 5;

    if (logout(tty))		/* Already entered (by login?) */
        logwtmp(tty, "", "");

#if defined(_PATH_LASTLOG)
    {
	    struct lastlog ll;
	    int fd;

	    if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
		lseek(fd, (off_t)(pw->pw_uid * sizeof(ll)), SEEK_SET);
		memset((void *)&ll, 0, sizeof(ll));
		time(&ll.ll_time);
		strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
		write(fd, (char *)&ll, sizeof(ll));
		close(fd);
	    }
    }
#endif

    memset((void *)&utmp, 0, sizeof(utmp));
    time(&utmp.ut_time);
    strncpy(utmp.ut_name, user, sizeof(utmp.ut_name));
    strncpy(utmp.ut_host, ":PPP", sizeof(utmp.ut_host));
    strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
    login(&utmp);		/* This logs us in wtmp too */

#endif /* #ifdef USE_PAM */

    syslog(LOG_INFO, "user %s logged in", user);
    logged_in = TRUE;

    return (UPAP_AUTHACK);
}
Beispiel #29
0
void
auth_client(struct fcrondyn_cl *client)
    /* check client identity */
{
    char *pass_cry = NULL;
    char *pass_sys = NULL;
    char *pass_str = NULL;

#ifdef HAVE_LIBSHADOW
    struct spwd *pass_sp = NULL;
    if ( (pass_sp = getspnam((char *) client->fcl_cmd )) == NULL ) {
	error_e("could not getspnam %s", (char *) client->fcl_cmd);
	send(client->fcl_sock_fd, "0", sizeof("0"), 0);
	return;
    }
    pass_sys = pass_sp->sp_pwdp;
#else
    struct passwd *pass = NULL;
    if ( (pass = getpwnam((char *) client->fcl_cmd )) == NULL ) {
	error_e("could not getpwnam %s", (char *) client->fcl_cmd);
	send(client->fcl_sock_fd, "0", sizeof("0"), 0);
	return;
    }
    pass_sys = pass->pw_passwd;
#endif

    /* */
    debug("auth_client() : socket : %d", client->fcl_sock_fd);
    /* */

    /* we need to limit auth failures : otherwise fcron may be used to "read"
     * shadow password !!! (or to crack it using a test-all-possible-password attack) */
    if (auth_fail > 0 && auth_nofail_since + AUTH_WAIT <= now )
	/* no auth time exceeded : set counter to 0 */
	auth_fail = 0;
    if (auth_fail >= MAX_AUTH_FAIL) {
	error("Too many authentication failures : try to connect later.");
	send(client->fcl_sock_fd, "0", sizeof("0"), 0);	    
	auth_fail = auth_nofail_since = 0;
	return;    
    }

    /* password is stored after user name */
    pass_str = &( (char *)client->fcl_cmd ) [ strlen( (char*)client->fcl_cmd ) + 1 ];
    if ( (pass_cry = crypt(pass_str, pass_sys)) == NULL ) {
	error_e("could not crypt()");
	send(client->fcl_sock_fd, "0", sizeof("0"), 0);
	return;
    }

/*      debug("pass_sp->sp_pwdp : %s", pass_sp->sp_pwdp); */
/*      debug("pass_cry : %s", pass_cry); */
    if (strcmp(pass_cry, pass_sys) == 0) {
	client->fcl_user = strdup2( (char *) client->fcl_cmd );
	send(client->fcl_sock_fd, "1", sizeof("1"), 0);
    }
    else {
	auth_fail++;
	auth_nofail_since = now;
	error("Invalid passwd for %s from socket %d",
	      (char *) client->fcl_cmd, client->fcl_sock_fd);
	send(client->fcl_sock_fd, "0", sizeof("0"), 0);
    }
}
Beispiel #30
0
PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int flags,
	int argc, const char *argv[])
{
#ifndef OPENPAM
	struct pam_conv *conv;
	struct pam_message msg;
	const struct pam_message *msgp;
	struct pam_response *resp;
#endif
	struct spwd *spwd;
	const char *user;
	char *crypt_password, *password;
	int pam_err, retry;

	(void)argc;
	(void)argv;

	/* identify user */
	if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
		return (pam_err);
	if ((spwd = getspnam(user)) == NULL)
		return (PAM_USER_UNKNOWN);

	/* get password */
#ifndef OPENPAM
	pam_err = pam_get_item(pamh, PAM_CONV, (const void **)&conv);
	if (pam_err != PAM_SUCCESS)
		return (PAM_SYSTEM_ERR);
	msg.msg_style = PAM_PROMPT_ECHO_OFF;
	msg.msg = password_prompt;
	msgp = &msg;
#endif
	for (retry = 0; retry < 3; ++retry) {
#ifdef OPENPAM
		pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
		    (const char **)&password, NULL);
#else
		resp = NULL;
		pam_err = (*conv->conv)(1, &msgp, &resp, conv->appdata_ptr);
		if (resp != NULL) {
			if (pam_err == PAM_SUCCESS)
				password = resp->resp;
			else
				free(resp->resp);
			free(resp);
		}
#endif
		if (pam_err == PAM_SUCCESS)
			break;
	}
	if (pam_err == PAM_CONV_ERR)
		return (pam_err);
	if (pam_err != PAM_SUCCESS)
		return (PAM_AUTH_ERR);

	/* compare passwords */
	if ((!spwd->sp_pwdp[0] && (flags & PAM_DISALLOW_NULL_AUTHTOK)) ||
	    (crypt_password = crypt(password, spwd->sp_pwdp)) == NULL ||
	    strcmp(crypt_password, spwd->sp_pwdp) != 0)
		pam_err = PAM_AUTH_ERR;
	else
		pam_err = PAM_SUCCESS;
#ifndef OPENPAM
	free(password);
#endif
	return (pam_err);
}