passwd.c revision 49335bdececa5fc091b6c63763f9176524390b5e
080575042aba2197b425ebfd52061dea061a9aa1xy * CDDL HEADER START
080575042aba2197b425ebfd52061dea061a9aa1xy * The contents of this file are subject to the terms of the
080575042aba2197b425ebfd52061dea061a9aa1xy * Common Development and Distribution License, Version 1.0 only
080575042aba2197b425ebfd52061dea061a9aa1xy * (the "License"). You may not use this file except in compliance
080575042aba2197b425ebfd52061dea061a9aa1xy * with the License.
080575042aba2197b425ebfd52061dea061a9aa1xy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
080575042aba2197b425ebfd52061dea061a9aa1xy * See the License for the specific language governing permissions
080575042aba2197b425ebfd52061dea061a9aa1xy * and limitations under the License.
080575042aba2197b425ebfd52061dea061a9aa1xy * When distributing Covered Code, include this CDDL HEADER in each
080575042aba2197b425ebfd52061dea061a9aa1xy * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
080575042aba2197b425ebfd52061dea061a9aa1xy * If applicable, add the following below this CDDL HEADER, with the
080575042aba2197b425ebfd52061dea061a9aa1xy * fields enclosed by brackets "[]" replaced with your own identifying
080575042aba2197b425ebfd52061dea061a9aa1xy * information: Portions Copyright [yyyy] [name of copyright owner]
080575042aba2197b425ebfd52061dea061a9aa1xy * CDDL HEADER END
080575042aba2197b425ebfd52061dea061a9aa1xy * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
080575042aba2197b425ebfd52061dea061a9aa1xy * Use is subject to license terms.
080575042aba2197b425ebfd52061dea061a9aa1xy/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
080575042aba2197b425ebfd52061dea061a9aa1xy/* All Rights Reserved */
080575042aba2197b425ebfd52061dea061a9aa1xy/* Copyright (c) 1987, 1988 Microsoft Corporation */
080575042aba2197b425ebfd52061dea061a9aa1xy/* All Rights Reserved */
25f2d433de915875c8393f0b0dc14aa155997ad0xy#pragma ident "%Z%%M% %I% %E% SMI"
080575042aba2197b425ebfd52061dea061a9aa1xy * passwd is a program whose sole purpose is to manage
080575042aba2197b425ebfd52061dea061a9aa1xy * the password file, map, or table. It allows system administrator
080575042aba2197b425ebfd52061dea061a9aa1xy * to add, change and display password attributes.
080575042aba2197b425ebfd52061dea061a9aa1xy * Non privileged user can change password or display
25f2d433de915875c8393f0b0dc14aa155997ad0xy * password attributes which corresponds to their login name.
080575042aba2197b425ebfd52061dea061a9aa1xy * flags indicate password attributes to be modified
25f2d433de915875c8393f0b0dc14aa155997ad0xy#define MFLAG 0x004 /* set max field -- # of days passwd is valid */
080575042aba2197b425ebfd52061dea061a9aa1xy#define NFLAG 0x008 /* set min field -- # of days between */
080575042aba2197b425ebfd52061dea061a9aa1xy /* password changes */
080575042aba2197b425ebfd52061dea061a9aa1xy#define AFLAG 0x040 /* display password attributes for all users */
080575042aba2197b425ebfd52061dea061a9aa1xy#define SAFLAG (SFLAG|AFLAG) /* display password attributes for all users */
080575042aba2197b425ebfd52061dea061a9aa1xy#define AGEFLAG (LFLAG | FFLAG | MFLAG | NFLAG | WFLAG | XFLAG | UFLAG)
25f2d433de915875c8393f0b0dc14aa155997ad0xy#define MUTEXFLAG (DFLAG | LFLAG | XFLAG | UFLAG | SAFLAG)
080575042aba2197b425ebfd52061dea061a9aa1xy * exit code
080575042aba2197b425ebfd52061dea061a9aa1xy * define error messages
25f2d433de915875c8393f0b0dc14aa155997ad0xy#define MSG_FE "Unexpected failure. Password file/table unchanged."
080575042aba2197b425ebfd52061dea061a9aa1xy#define MSG_FF "Unexpected failure. Password file/table missing."
25f2d433de915875c8393f0b0dc14aa155997ad0xy#define MSG_FB "Password file/table busy. Try again later."
080575042aba2197b425ebfd52061dea061a9aa1xy#define MSG_UNACCEPT "%s is unacceptable as a new shell\n"
25f2d433de915875c8393f0b0dc14aa155997ad0xy#define MSG_UNAVAIL "warning: %s is unavailable on this machine\n"
080575042aba2197b425ebfd52061dea061a9aa1xy#define MSG_MAXLEN "Maximum number of characters allowed is %d."
25f2d433de915875c8393f0b0dc14aa155997ad0xy#define MSG_CONTROL "Control characters are not allowed.\n"
080575042aba2197b425ebfd52061dea061a9aa1xy#define MSG_GECOS_UNCHANGED "Finger information unchanged.\n"
25f2d433de915875c8393f0b0dc14aa155997ad0xy#define MSG_DIR_UNCHANGED "Homedir information unchanged.\n"
080575042aba2197b425ebfd52061dea061a9aa1xy#define MSG_INPUTHDR "Default values are printed inside of '[]'.\n" \
080575042aba2197b425ebfd52061dea061a9aa1xy "To accept the default, type <return>.\n" \
080575042aba2197b425ebfd52061dea061a9aa1xy "To have a blank entry, type the word 'none'.\n"
25f2d433de915875c8393f0b0dc14aa155997ad0xy#define MSG_AUTHTOK_EXP "Your password has been expired for too long.\n" \
25f2d433de915875c8393f0b0dc14aa155997ad0xy "Please contact the system administrator.\n"
080575042aba2197b425ebfd52061dea061a9aa1xy#define MSG_CUR_PASS_UNAME "Enter %s's existing login password: "
080575042aba2197b425ebfd52061dea061a9aa1xy#define MSG_SUCCESS "%s: password information changed for %s\n"
25f2d433de915875c8393f0b0dc14aa155997ad0xy * return code from ckarg() routine
080575042aba2197b425ebfd52061dea061a9aa1xy * defind password file name
25f2d433de915875c8393f0b0dc14aa155997ad0xy/* Number of characters in that make up an encrypted password (for now) */
080575042aba2197b425ebfd52061dea061a9aa1xy#define dprintf1(w, x)
25f2d433de915875c8393f0b0dc14aa155997ad0xyextern int optind;
25f2d433de915875c8393f0b0dc14aa155997ad0xystatic char *prognamep;
25f2d433de915875c8393f0b0dc14aa155997ad0xy struct pam_response **, void *);
25f2d433de915875c8393f0b0dc14aa155997ad0xystatic char *usrname; /* user whose attribute we update */
25f2d433de915875c8393f0b0dc14aa155997ad0xystatic adt_event_data_t *event = NULL; /* event to be generated */
25f2d433de915875c8393f0b0dc14aa155997ad0xystatic pwu_repository_t __REPFILES = { "files", NULL, 0 };
25f2d433de915875c8393f0b0dc14aa155997ad0xy * Function Declarations
25f2d433de915875c8393f0b0dc14aa155997ad0xyextern void setusershell(void);
25f2d433de915875c8393f0b0dc14aa155997ad0xyextern char *getusershell(void);
25f2d433de915875c8393f0b0dc14aa155997ad0xyextern void endusershell(void);
25f2d433de915875c8393f0b0dc14aa155997ad0xystatic void rusage(void);
080575042aba2197b425ebfd52061dea061a9aa1xystatic int ckuid(void);
080575042aba2197b425ebfd52061dea061a9aa1xystatic int ckarg(int argc, char **argv, attrlist **attributes);
080575042aba2197b425ebfd52061dea061a9aa1xystatic int get_namelist(pwu_repository_t, char ***, int *);
25f2d433de915875c8393f0b0dc14aa155997ad0xystatic int get_namelist_files(char ***, int *);
25f2d433de915875c8393f0b0dc14aa155997ad0xystatic int get_namelist_nisplus(char ***, int *);
25f2d433de915875c8393f0b0dc14aa155997ad0xystatic int get_attr(char *, pwu_repository_t *, attrlist **);
25f2d433de915875c8393f0b0dc14aa155997ad0xystatic char *userinput(char *, pwu_repository_t *, attrtype);
25f2d433de915875c8393f0b0dc14aa155997ad0xystatic char *getresponse(char *);
25f2d433de915875c8393f0b0dc14aa155997ad0xy * The main routine will call ckarg() to parse the command line
25f2d433de915875c8393f0b0dc14aa155997ad0xy * arguments and call the appropriate functions to perform the
25f2d433de915875c8393f0b0dc14aa155997ad0xy * tasks specified by the arguments. It allows system
25f2d433de915875c8393f0b0dc14aa155997ad0xy * administrator to add, change and display password attributes.
25f2d433de915875c8393f0b0dc14aa155997ad0xy * Non privileged user can change password or display
25f2d433de915875c8393f0b0dc14aa155997ad0xy * password attributes which corresponds to their login name.
25f2d433de915875c8393f0b0dc14aa155997ad0xy /* initialization for variables, set locale and textdomain */
25f2d433de915875c8393f0b0dc14aa155997ad0xy#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
25f2d433de915875c8393f0b0dc14aa155997ad0xy#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
080575042aba2197b425ebfd52061dea061a9aa1xy * ckarg() parses the arguments. In case of an error,
080575042aba2197b425ebfd52061dea061a9aa1xy * it sets the retval and returns FAIL (-1).
25f2d433de915875c8393f0b0dc14aa155997ad0xy } else if (flag == 0) {
080575042aba2197b425ebfd52061dea061a9aa1xy * If flag is zero, change passwd.
080575042aba2197b425ebfd52061dea061a9aa1xy * Otherwise, it will display or
080575042aba2197b425ebfd52061dea061a9aa1xy * modify password aging attributes
080575042aba2197b425ebfd52061dea061a9aa1xy if (pam_start("passwd", usrname, &pam_conv, &pamh) != PAM_SUCCESS)
080575042aba2197b425ebfd52061dea061a9aa1xy if (pam_set_item(pamh, PAM_REPOSITORY, (void *)&auth_rep)
080575042aba2197b425ebfd52061dea061a9aa1xy if (flag == SAFLAG) { /* display password attributes for all users */
080575042aba2197b425ebfd52061dea061a9aa1xy if (num_user == 0) {
080575042aba2197b425ebfd52061dea061a9aa1xy } else if (flag == SFLAG) { /* display password attributes by user */
080575042aba2197b425ebfd52061dea061a9aa1xy /* NOT REACHED */
080575042aba2197b425ebfd52061dea061a9aa1xy /* system error */
080575042aba2197b425ebfd52061dea061a9aa1xy /* Set up for Audit */
25f2d433de915875c8393f0b0dc14aa155997ad0xy if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
080575042aba2197b425ebfd52061dea061a9aa1xy /* save target user */
080575042aba2197b425ebfd52061dea061a9aa1xy /* Don't check account expiration when invoked by root */
080575042aba2197b425ebfd52061dea061a9aa1xy /* valid error when changing passwords */
080575042aba2197b425ebfd52061dea061a9aa1xy /* Ok to change password */
080575042aba2197b425ebfd52061dea061a9aa1xy /* bypass password strength checks */
080575042aba2197b425ebfd52061dea061a9aa1xy while (pam_retval == PAM_AUTHTOK_ERR && tries <= DEF_ATTEMPTS) {
080575042aba2197b425ebfd52061dea061a9aa1xy /* NOT REACHED */
25f2d433de915875c8393f0b0dc14aa155997ad0xy } else { /* changing attributes */
080575042aba2197b425ebfd52061dea061a9aa1xy switch (flag) {
080575042aba2197b425ebfd52061dea061a9aa1xy switch (retval) {
080575042aba2197b425ebfd52061dea061a9aa1xy if ((updated_reps & i) == 0)
080575042aba2197b425ebfd52061dea061a9aa1xy /* NOTREACHED */
080575042aba2197b425ebfd52061dea061a9aa1xy return (0);
080575042aba2197b425ebfd52061dea061a9aa1xy * Get a line of input from the user.
4914a7d0d1ee59f8cc21b19bfd7979cb65681eacyy * If the line is empty, or the input equals 'oldval', NULL is returned.
080575042aba2197b425ebfd52061dea061a9aa1xy * therwise, a malloced string containing the input (minus the trailing
080575042aba2197b425ebfd52061dea061a9aa1xy * newline) is returned.
080575042aba2197b425ebfd52061dea061a9aa1xy * char *userinput(item)
080575042aba2197b425ebfd52061dea061a9aa1xy * user conversation function. The old value of attribute "item" is
080575042aba2197b425ebfd52061dea061a9aa1xy * displayed while the user is asked to provide a new value.
4914a7d0d1ee59f8cc21b19bfd7979cb65681eacyy * returns a malloc()-ed string if the user actualy provided input
4914a7d0d1ee59f8cc21b19bfd7979cb65681eacyy * or NULL if the user simply hit return or the input equals the old
080575042aba2197b425ebfd52061dea061a9aa1xy * value (not changed).
4914a7d0d1ee59f8cc21b19bfd7979cb65681eacyyuserinput(char *name, pwu_repository_t *rep, attrtype type)
4914a7d0d1ee59f8cc21b19bfd7979cb65681eacyy if (__get_authtoken_attr(name, rep, &oldattr) != PWU_SUCCESS)
080575042aba2197b425ebfd52061dea061a9aa1xy /* No current shell: set DEFSHL as default choice */
080575042aba2197b425ebfd52061dea061a9aa1xy /* User must currently have a valid shell */
4914a7d0d1ee59f8cc21b19bfd7979cb65681eacyy /* Make sure new shell is listed */
080575042aba2197b425ebfd52061dea061a9aa1xy /* Allow user to give shell without path */
080575042aba2197b425ebfd52061dea061a9aa1xy /* take shell name including path */
080575042aba2197b425ebfd52061dea061a9aa1xy /* NOT REACHED */
4914a7d0d1ee59f8cc21b19bfd7979cb65681eacyy * if type == SHELL, we have returned by now. Only GECOS and
080575042aba2197b425ebfd52061dea061a9aa1xy * HOMEDIR get to this point.
080575042aba2197b425ebfd52061dea061a9aa1xy * PRE: oldval points to malloced string with Old Value
080575042aba2197b425ebfd52061dea061a9aa1xy * INV: oldval remains unchanged
4914a7d0d1ee59f8cc21b19bfd7979cb65681eacyy * POST:response points to valid string or NULL.
080575042aba2197b425ebfd52061dea061a9aa1xy for (;;) {
080575042aba2197b425ebfd52061dea061a9aa1xy /* No-change or empty string are OK */
080575042aba2197b425ebfd52061dea061a9aa1xy /* Check for illegal characters */
080575042aba2197b425ebfd52061dea061a9aa1xy /* don't allow control characters */
25f2d433de915875c8393f0b0dc14aa155997ad0xy break; /* response is a valid string */
080575042aba2197b425ebfd52061dea061a9aa1xy * We only get here if the input was invalid.
25f2d433de915875c8393f0b0dc14aa155997ad0xy * In that case, we again ask the user for input.
25f2d433de915875c8393f0b0dc14aa155997ad0xy * ckarg():
25f2d433de915875c8393f0b0dc14aa155997ad0xy * This function parses and verifies the
25f2d433de915875c8393f0b0dc14aa155997ad0xy * arguments. It takes three parameters:
080575042aba2197b425ebfd52061dea061a9aa1xy * argc => # of arguments
080575042aba2197b425ebfd52061dea061a9aa1xy * argv => pointer to an argument
25f2d433de915875c8393f0b0dc14aa155997ad0xy * attrlist => pointer to list of password attributes
080575042aba2197b425ebfd52061dea061a9aa1xy extern char *optarg;
080575042aba2197b425ebfd52061dea061a9aa1xy while ((opt = getopt(argc, argv, "r:aldefghsux:n:w:D:N")) != EOF) {
080575042aba2197b425ebfd52061dea061a9aa1xy switch (opt) {
080575042aba2197b425ebfd52061dea061a9aa1xy /* repository: this option should be specified first */
080575042aba2197b425ebfd52061dea061a9aa1xy "Repository is already defined or specified.\n"));
080575042aba2197b425ebfd52061dea061a9aa1xy /* if no repository the default for -d is files */
080575042aba2197b425ebfd52061dea061a9aa1xy * Delete the password - only privileged processes
080575042aba2197b425ebfd52061dea061a9aa1xy * can execute this for FILES
080575042aba2197b425ebfd52061dea061a9aa1xy "-d only applies to files repository\n"));
080575042aba2197b425ebfd52061dea061a9aa1xy /* if no repository the default for -N is files */
080575042aba2197b425ebfd52061dea061a9aa1xy "-N only applies to files or nisplus repository\n"));
080575042aba2197b425ebfd52061dea061a9aa1xy * Only privileged processes can execute this
080575042aba2197b425ebfd52061dea061a9aa1xy * for FILES
080575042aba2197b425ebfd52061dea061a9aa1xy /* if no repository the default for -l is files */
080575042aba2197b425ebfd52061dea061a9aa1xy "-l only applies to files or nisplus repository\n"));
080575042aba2197b425ebfd52061dea061a9aa1xy * Only privileged processes can execute this
080575042aba2197b425ebfd52061dea061a9aa1xy * for FILES
25f2d433de915875c8393f0b0dc14aa155997ad0xy /* if no repository the default for -u is files */
25f2d433de915875c8393f0b0dc14aa155997ad0xy "-u only applies to files or nisplus repository\n"));
25f2d433de915875c8393f0b0dc14aa155997ad0xy * Only privileged processes can execute this
25f2d433de915875c8393f0b0dc14aa155997ad0xy * for FILES
080575042aba2197b425ebfd52061dea061a9aa1xy /* if no repository the default for -x is files */
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
return (FAIL);
rusage();
return (FAIL);
rusage();
return (FAIL);
return (flag);
rusage();
return (FAIL);
rusage();
return (FAIL);
rusage();
return (FAIL);
return (FAIL);
return (flag);
ckuid(void)
if (uid != 0) {
return (SUCCESS);
int res;
return (PWU_SUCCESS);
username);
char *status;
char *passwd;
long lstchg;
while (attributes) {
case ATTR_PASSWD:
case ATTR_LSTCHG:
case ATTR_MIN:
case ATTR_MAX:
case ATTR_WARN:
if (status)
if (lstchg == 0) {
while (attributes) {
int max_user;
int nuser;
char **nl;
nuser = 0;
errno = 0;
return (NOPERM);
max_user++;
return (FMERR);
return (FMERR);
nuser++;
return (SUCCESS);
* search just the nisplus sp file, so we want to bypass normal nsswitch.conf
extern int str2spwd(const char *, int, void *, char *, int);
_np_setspent(void)
_np_endspent(void)
static struct spwd *
char *nam;
&arg);
static struct spwd *
_np_getspent(void)
nss_XbyY_buf_t *b;
int nuser = 0;
char **nl;
struct spwd *p;
return (FMERR);
(void) _np_setspent();
_np_endspent();
return (FMERR);
_np_endspent();
return (FMERR);
(void) _np_endspent();
return (SUCCESS);
rusage();
return (BADSYN);
if (pamh)
switch (retcode) {
case SUCCESS:
case NOPERM:
case BADOPT:
case FMERR:
case FATAL:
case FBUSY:
case BADSYN:
case BADAGE:
case NOMEM:
pam_retval) != 0) {
struct pam_message *m;
struct pam_response *r;
char *temp;
if (num_msg <= 0)
return (PAM_CONV_ERR);
sizeof (struct pam_response));
return (PAM_BUF_ERR);
k = num_msg;
m = *msg;
r = *response;
switch (m->msg_style) {
case PAM_PROMPT_ECHO_OFF:
r = *response;
for (i = 0; i < num_msg; i++, r++) {
if (r->resp)
return (PAM_BUF_ERR);
case PAM_PROMPT_ECHO_ON:
r = *response;
for (i = 0; i < num_msg; i++, r++) {
if (r->resp)
return (PAM_BUF_ERR);
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
return (PAM_SUCCESS);
attrlist **w;
switch (type) {
case ATTR_MIN:
case ATTR_WARN:
case ATTR_MAX:
attrlist **w;
while (*w != NULL) {
exp = *w;
*w = (*w)->next;
max = *w;
*w = (*w)->next;
w = &(*w)->next;
if (max) {
*w = max;
if (exp) {
*w = exp;
*w = NULL;
rusage(void)