2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. 2N/A#
include <
limits.h>
/* LOGNAME_MAX -- max Solaris user name */ 2N/A * files function pointer table, used by passwdutil_init to initialize 2N/A * the global Repository-Operations table "rops" 2N/A * this structure defines the buffer used to keep state between 2N/A * We should use sysconf, but there is no sysconf name for SHADOW 2N/A * so we use these from nss_dbdefs 2N/A * lock functions for files repository 2N/A * private_getpwnam_r() 2N/A * A private implementation of getpwnam_r which does *not* fall back to 2N/A * behaves like getpwnam_r(). 2N/A * private_getspnam_r() 2N/A * A private implementation of getspnam_r which does *not* fall back to 2N/A * Behaves like getspnam_r(). Since we use fgetspent_t(), all numeric 2N/A * fields that are undefined in /etc/shadow will be set to -1. 2N/A * files_getpwnam(name, items, rep, buf) 2N/A * we need for the items we need to update 2N/A * Some other repository might have different values 2N/A * so we ignore those. 2N/A * int files_user_to_authenticate(name, rep, auth_user, privileged) 2N/A * Determine which user needs to be authenticated. For files, the 2N/A * possible return values are: 2N/A * PWU_SUCCESS and (auth_user == NULL || auth_user = user) 2N/A /* check to see if target user is present in files */ 2N/A * Password history file format: 2N/A * user:crypw1: ... crypwn: such that n <= MAXHISTORY 2N/A * 3*LOGNAME_MAX just in case there are long user names. 2N/A * Traditionally Solaris LOGNAME_MAX (_POSIX_LOGIN_NAME_MAX) is 13, 2N/A * but some sites often user more. 2N/A * If LOGNAME_MAX ever becomes reasonable (128) and actually enforced, 2N/A * files_checkhistory - check if a user's new password is in the user's 2N/A * old password history. 2N/A * passwd = new clear text password. 2N/A * PWU_SUCCESS, passwd found in user's old password history. 2N/A * The caller should only be interested and fail if 2N/A * PWU_SUCCESS is returned. 2N/A * PWU_NOT_FOUND, passwd not in user's old password history. 2N/A * PWU_errors, PWU_ errors from other routines. 2N/A * This depends on the underlying files_getattr implementation 2N/A * treating user not found in backing store or no history as 2N/A debug(
"files_checkhistory: no history requested");
2N/A /* compare crypt_passwd to attr.data.val_s strings. */ 2N/A debug(
"files_checkhistory: user_pw=%s, history_pw=%s",
2N/A * files_getattr(name, items, rep) 2N/A * Get attributes specified in list 'items' 2N/A * Nothing special needs to be done for 2N/A debug(
"files_getattr: Get password history for %s ",
2N/A /* integer values */ 2N/A * see if attribute ATTR_MAX, with value != -1, is present in 2N/A * attribute-list "list". 2N/A * returns 1 if present, 0 otherwise. 2N/A * files_update(items, rep, buf) 2N/A * update the information in buf with the attributes specified in 2N/A * if sp_max==0 : disable passwd aging after updating the password 2N/A break;
/* We are able to handle this, but... */ 2N/A * Nothing special needs to be done for 2N/A * There is a special case only for files: if the 2N/A * password is to be deleted (-d to passwd), 2N/A * p->data.val_s will be NULL. 2N/A /* algorithm problem? */ 2N/A "passwdutil: crypt_gensalt %m");
2N/A /* append new password hash */ 2N/A /* Locked accounts stay locked on transition to NP */ 2N/A /* Turn aging off -> Reset min and warn too */ 2N/A * If minage has not been set with 2N/A * a command-line option, we set it 2N/A * If aging was turned off, we update lstchg. 2N/A * We take care not to update lstchg if the 2N/A * user has no password, otherwise the user 2N/A * might not be required to provide a password 2N/A * the next time [s]he logs-in. 2N/A * Also, if lstchg != -1 (i.e., not set in 2N/A /* __set_authtoken_attr() blocks this */ 2N/A * What should the new aging values look like? 2N/A * There are a number of different conditions 2N/A * a) aging is already configured: don't touch it 2N/A * b) disable_aging is set: disable aging 2N/A * c) aging is not configured: turn on default aging; 2N/A * b) and c) of course only if aging_needed and !aging_set. 2N/A * (i.e., password changed, and aging values not changed) 2N/A /* a) aging not yet configured */ 2N/A /* b) turn off aging */ 2N/A * files_update_shadow(char *name, struct spwd *spwd) 2N/A * update the shadow password file SHADOW to contain the spwd structure 2N/A * "spwd" for user "name" 2N/A /* Mode of the shadow file should be 400 or 000 */ 2N/A /* copy mode from current shadow file (0400 or 0000) */ 2N/A * we can't specify filemodes to fopen(), and we SHOULD NOT 2N/A * set umask in multi-thread safe libraries, so we use 2N/A * a combination of open() and fdopen() 2N/A * copy old shadow to temporary file while replacing the entry 2N/A * that matches "name". 2N/A * Something went wrong (ENOSPC for example). Don't 2N/A * use the resulting temporary file! 2N/A * Rename stmp to shadow: 2N/A /* see files_update_shadow() for open()+fdopen() rationale */ 2N/A * copy old password entries to temporary file while replacing 2N/A * the entry that matches "name" 2N/A /* Rename temp to passwd */ 2N/A * files_putpwnam(name, oldpw, rep, buf) 2N/A * store the password attributes contained in "buf" in /etc/passwd and 2N/A * NOTE: This is all covered under the repository lock held for updating 2N/A * passwd(4) and shadow(4). 2N/A FILE *
dst;
/* temp history database being updated */ 2N/A debug(
"files_update_history(%s) no history, unlinking",
name);
2N/A /* get ready to copy */ 2N/A /* Copy and update if found. Add if not found. */ 2N/A /* get username field */ 2N/A /* found user, update */ 2N/A debug(
"files_update_history: update user\n" 2N/A /* get old crypted password history */ 2N/A /* copy other users to updated file */ 2N/A /* user not found, add to history file */ 2N/A debug(
"files_update_history: add line\n" 2N/A /* If something messed up in file system, lose the update */ 2N/A debug(
"files_update_history: update file close failed %d",
2N/A * rename history to ohistory, 2N/A * rename tmp to history, 2N/A /* old history won't go away, lose the update */ 2N/A debug(
"files_update_history: update file rename failed %d",