Initial import of the CDE 2.1.30 sources from the Open Group.

This commit is contained in:
Peter Howkins
2012-03-10 18:21:40 +00:00
commit 83b6996daa
18978 changed files with 3945623 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
/* $XConsortium: Imakefile /main/4 1996/04/21 19:13:04 drk $
*
* (c) Copyright 1996 Digital Equipment Corporation.
* (c) Copyright 1996 Hewlett-Packard Company.
* (c) Copyright 1996 International Business Machines Corp.
* (c) Copyright 1995,1996 Sun Microsystems, Inc.
* (c) Copyright 1996 Novell, Inc.
* (c) Copyright 1996 FUJITSU LIMITED.
* (c) Copyright 1996 Hitachi.
*/
#define DoNormalLib NormalLibPam
#define DoSharedLib SharedLibPam
#define DoDebugLib DebugLibPam
#define DoProfileLib ProfileLibPam
#define LibName pam_unix
#define SoRev SOPAMREV
#define LibHeaders NO
#include <Threads.tmpl>
SRCS = unix_acct_mgmt.c \
unix_authenticate.c \
unix_chauthtok.c \
unix_close_session.c \
unix_get_authtokattr.c \
unix_open_session.c \
unix_set_authtokattr.c \
npd_clnt.c \
unix_setcred.c \
unix_update_authtok.c \
unix_update_authtok_file.c \
unix_update_authtok_nis.c \
unix_update_authtok_nisplus.c \
switch_utils.c \
unix_utils.c \
yppasswdxdr.c
OBJS = unix_acct_mgmt.o \
unix_authenticate.o \
unix_chauthtok.o \
unix_close_session.o \
unix_get_authtokattr.o \
unix_open_session.o \
unix_set_authtokattr.o \
npd_clnt.o \
unix_setcred.o \
unix_update_authtok.o \
unix_update_authtok_file.o \
unix_update_authtok_nis.o \
unix_update_authtok_nisplus.o \
switch_utils.o \
unix_utils.o \
yppasswdxdr.o
#ifdef SharedPamUnixReqs
REQUIREDLIBS = SharedPamUnixReqs
#endif
#ifdef PamUnixDefines
DEFINES = PamUnixDefines
#endif
#include <Library.tmpl>
DependTarget()

View File

@@ -0,0 +1,48 @@
/****************************************************************************
* Export list for libpam_unix.
* This list *must* be updated whenever a change is made to the libpam_unix API.
*
* The syntax for the symbol declarations in this list is as follows:
* public sym => Public C symbol, i.e., publicised API
* private sym => Private C symbol, i.e., unpublicised API
* internal sym => Internal C symbol, i.e., not part of API
* publicC++ sym => Public C++ symbol, i.e., publicised API
* privateC++ sym => Private C++ symbol, i.e., unpublicised API
* internalC++ sym => Internal C++ symbol, i.e., not part of API
*
* $TOG: libpam_unix.elist /main/1 1999/09/08 15:59:55 mgreess $
*****************************************************************************/
public pam_sm_authenticate
public pam_sm_setcred
public pam_sm_acct_mgmt
public pam_sm_open_session
public pam_sm_close_session
public pam_sm_chauthtok
internal get_ns
internal __set_authtoken_attr
internal defcntl
internal defopen
internal ck_perm
internal gethomedir
internal str2spwd
internal xdr_yppasswd
internal getspnam_from
internal update_authtok_file
internal setup_attr
internal getfingerinfo
internal free_setattr
internal defread
internal repository_to_string
internal _priv_lock
internal getpwnam_from
internal update_authtok_nis
internal attr_find
internal getloginshell
internal xdr_passwd
internal attr_match
internal __update_authtok
internal free_passwd_structs
internal __get_authtoken_attr

View File

@@ -0,0 +1,414 @@
/* $TOG: npd_clnt.c /main/5 1999/10/15 17:23:53 mgreess $ */
/*
* npd_clnt.c
* Contains all the client-side routines to communicate
* with the NIS+ passwd update deamon.
*
* Copyright (c) 1992-5 Sun Microsystems Inc
* All Rights Reserved.
*/
#ident "@(#)npd_clnt.c 1.11 95/09/19 SMI"
#ifdef PAM_NISPLUS
#include <syslog.h>
#include <string.h>
#include <shadow.h>
#include <rpc/rpc.h>
#include <rpc/xdr.h>
#include <rpc/des_crypt.h>
#include <mp.h>
#include <rpc/key_prot.h>
#include <rpcsvc/nis.h>
#include <rpcsvc/nispasswd.h>
#include <memory.h>
#include <sys/time.h>
#define _NPD_PASSMAXLEN 16
extern int pow(); /* from libmp.so (undocumented) */
extern int _mp_move(); /* from libmp.so (undocumented) */
extern int sdiv(); /* from libmp.so (undocumented) */
extern bool_t __npd_ecb_crypt();
extern bool_t __npd_cbc_crypt();
extern void *calloc();
extern void free();
/*
* given the domain return the client handle to the rpc.nispasswdd
* that I need to contact and the master_servers' publickey.
* returns TRUE on success and FALSE on failure.
*/
bool_t
npd_makeclnthandle(domain, clnt, srv_pubkey, keysize)
char *domain;
CLIENT **clnt; /* returned */
char *srv_pubkey; /* buf to hold the pubkey; returned */
int keysize; /* size of buffer */
{
nis_server **srvs; /* servers that serve 'domain' */
nis_server *master_srv;
char buf[NIS_MAXNAMELEN];
CLIENT *tmpclnt = NULL;
if (domain == NULL || *domain == '\0')
domain = nis_local_directory();
/* strlen("org_dir.") + null + "." = 10 */
if ((strlen(domain) + 10) > (size_t) NIS_MAXNAMELEN)
return (FALSE);
(void) sprintf(buf, "org_dir.%s", domain);
if (buf[strlen(buf) - 1] != '.')
(void) strcat(buf, ".");
srvs = nis_getservlist(buf);
if (srvs == NULL) {
/* can't find any of the servers that serve this domain */
/* something is very wrong ! */
syslog(LOG_ERR,
"can't get a list of servers for %s domain",
domain);
return (FALSE);
}
master_srv = srvs[0]; /* the first one is always the master */
/*
* copy the publickey -- should be safe to assume there is one,
* BUT just in case lets check first !
*/
switch (master_srv->key_type) {
case NIS_PK_DH:
if (keysize < master_srv->pkey.n_len) {
syslog(LOG_ERR,
"buf is %d bytes only, need %d bytes for the key",
keysize, master_srv->pkey.n_len);
(void) nis_freeservlist(srvs);
return (FALSE);
}
(void) strcpy(srv_pubkey, master_srv->pkey.n_bytes);
break;
case NIS_PK_NONE:
default:
/* server does not have a D-H key-pair */
syslog(LOG_ERR, "no publickey for %s", master_srv->name);
(void) nis_freeservlist(srvs);
return (FALSE);
}
/*
* now that we have the universal addr for the master server,
* lets create the client handle to rpc.nispasswdd.
* always use VC and attempt to create an authenticated handle.
* nis_make_rpchandle() will attempt to use auth_des first,
* if user does not have D-H keys, then it will try auth_sys.
* sendsz and recvsz are 0 ==> choose defaults.
*/
tmpclnt = nis_make_rpchandle(master_srv, 0, NISPASSWD_PROG,
NISPASSWD_VERS, ZMH_VC+ZMH_AUTH, 0, 0);
/* done with server list */
(void) nis_freeservlist(srvs);
if (tmpclnt == NULL) {
/*
* error syslog'd by nis_make_rpchandle()
*/
return (FALSE);
}
*clnt = tmpclnt;
return (TRUE);
}
/*
* generate a common DES key with the publickey I give and
* my secret key -- used by the client-side because the secret
* key is not cached with keyserv.
* returns TRUE on success and FALSE on failure.
*/
bool_t
__get_cmnkey(public, secret, deskey)
char *public;
char *secret;
des_block *deskey;
{
MINT *pub;
MINT *sec;
MINT *cmn;
MINT *tmp;
short reg;
short base = (1 << 8);
int i;
char *k;
pub = xtom(public);
sec = xtom(secret);
if ((pub == NULL) || (sec == NULL))
return (FALSE);
cmn = itom(0);
(void) pow(pub, sec, xtom(HEXMODULUS), cmn);
/*
* Choose middle 64 bits of the common key to use as our des
* key, possibly overwriting the lower order bits by setting
* parity.
*/
tmp = itom(0);
(void) _mp_move(cmn, tmp);
for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
(void) sdiv(tmp, base, tmp, &reg);
}
k = deskey->c;
for (i = 0; i < 8; i++) {
(void) sdiv(tmp, base, tmp, &reg);
*k++ = reg;
}
des_setparity((char *)deskey);
mfree(tmp);
mfree(sec);
mfree(pub);
mfree(cmn);
return (TRUE);
}
/* Default timeout can be changed using clnt_control() */
static struct timeval TIMEOUT = { 55, 0 };
/*
* initiate the passwd update request session by sending
* username, domainname, the generated public key and
* the callers' old passwd encrypted with the common DES key.
* if it succeeds, decrypt the identifier and randval sent in
* the response; otherwise return an appropriate error code.
*/
nispasswd_status
nispasswd_auth(user, domain, oldpass, u_pubkey, deskey, clnt,
ident, randval, err)
char *user; /* user name */
char *domain; /* domain */
char *oldpass; /* clear old password */
unsigned char *u_pubkey; /* users' public key */
des_block *deskey; /* the common DES key */
CLIENT *clnt; /* client handle to rpc.nispasswdd */
unsigned long *ident; /* ID, returned on first attempt */
unsigned long *randval; /* R, returned on first attempt */
int *err; /* error code, returned */
{
npd_request req_arg;
nispasswd_authresult res;
des_block ivec;
unsigned char xpass[_NPD_PASSMAXLEN];
des_block cryptbuf;
int cryptstat;
int i;
char *keystr = "DES";
if ((user == NULL || *user == '\0') ||
(domain == NULL || *domain == '\0') ||
(oldpass == NULL || *oldpass == '\0') ||
(u_pubkey == NULL || *u_pubkey == '\0') ||
(deskey == (des_block *) NULL) ||
(clnt == (CLIENT *) NULL)) {
*err = NPD_INVALIDARGS;
return (NPD_FAILED);
}
(void) memset((char *)&req_arg, 0, sizeof (req_arg));
(void) memset((char *)&res, 0, sizeof (res));
/* encrypt the passwd with the common des key */
if (strlen(oldpass) > (size_t) _NPD_PASSMAXLEN) {
*err = NPD_BUFTOOSMALL;
return (NPD_FAILED);
}
(void) strcpy((char *)xpass, oldpass);
for (i = strlen(oldpass); i < _NPD_PASSMAXLEN; i++)
xpass[i] = '\0';
ivec.key.high = ivec.key.low = 0;
cryptstat = cbc_crypt((char *) deskey, (char *) xpass,
_NPD_PASSMAXLEN, DES_ENCRYPT | DES_HW,
(char *) &ivec);
if (DES_FAILED(cryptstat)) {
*err = NPD_ENCRYPTFAIL;
return (NPD_FAILED);
}
req_arg.username = user;
req_arg.domain = domain;
req_arg.key_type = keystr;
req_arg.user_pub_key.user_pub_key_len =
strlen((char *)u_pubkey) + 1;
req_arg.user_pub_key.user_pub_key_val = u_pubkey;
req_arg.npd_authpass.npd_authpass_len = _NPD_PASSMAXLEN;
req_arg.npd_authpass.npd_authpass_val = xpass;
req_arg.ident = *ident; /* on re-tries ident is non-zero */
if (clnt_call(clnt, NISPASSWD_AUTHENTICATE,
(xdrproc_t) xdr_npd_request, (caddr_t) &req_arg,
(xdrproc_t) xdr_nispasswd_authresult, (caddr_t) &res,
TIMEOUT) != RPC_SUCCESS) {
/* following msg is printed on stderr */
(void) clnt_perror(clnt, "call to rpc.nispasswdd failed");
*err = NPD_SRVNOTRESP;
return (NPD_FAILED);
}
switch (res.status) {
case NPD_SUCCESS:
case NPD_TRYAGAIN:
/*
* decrypt the ident & randval
*/
cryptbuf.key.high =
ntohl(res.nispasswd_authresult_u.npd_verf.npd_xid);
cryptbuf.key.low =
ntohl(res.nispasswd_authresult_u.npd_verf.npd_xrandval);
if (! __npd_ecb_crypt(ident, randval, &cryptbuf,
sizeof (des_block), DES_DECRYPT, deskey)) {
*err = NPD_DECRYPTFAIL;
return (NPD_FAILED);
}
return (res.status);
case NPD_FAILED:
*err = res.nispasswd_authresult_u.npd_err;
return (NPD_FAILED);
default:
/*
* should never reach this case !
*/
*err = NPD_SYSTEMERR;
return (NPD_FAILED);
}
/* NOTREACHED */
}
/*
* authenticated the caller, now send the identifier; and the
* new password and the random value encrypted with the common
* DES key. Send any other changed password information in the
* clear.
*/
int
nispasswd_pass(clnt, ident, randval, deskey, newpass, gecos, shell, err, errlst)
CLIENT *clnt; /* client handle to rpc.nispasswdd */
unsigned long ident; /* ID */
unsigned long randval; /* R */
des_block *deskey; /* common DES key */
char *newpass; /* clear new password */
char *gecos; /* gecos */
char *shell; /* shell */
int *err; /* error code, returned */
nispasswd_error **errlst; /* error list on partial success, returned */
{
npd_update send_arg;
nispasswd_updresult result;
npd_newpass cryptbuf;
unsigned long tmp_xrval;
nispasswd_error *errl = NULL, *p;
if ((clnt == (CLIENT *) NULL) ||
(deskey == (des_block *) NULL) ||
(newpass == NULL || *newpass == '\0')) {
*err = NPD_INVALIDARGS;
return (NPD_FAILED);
}
(void) memset((char *)&send_arg, 0, sizeof (send_arg));
(void) memset((char *)&result, 0, sizeof (result));
send_arg.ident = ident;
if (! __npd_cbc_crypt(&randval, newpass, strlen(newpass),
&cryptbuf, _NPD_PASSMAXLEN, DES_ENCRYPT, deskey)) {
*err = NPD_ENCRYPTFAIL;
return (NPD_FAILED);
}
tmp_xrval = cryptbuf.npd_xrandval;
cryptbuf.npd_xrandval = htonl(tmp_xrval);
send_arg.xnewpass = cryptbuf;
/* gecos */
send_arg.pass_info.pw_gecos = gecos;
/* shell */
send_arg.pass_info.pw_shell = shell;
if (clnt_call(clnt, NISPASSWD_UPDATE,
(xdrproc_t) xdr_npd_update, (caddr_t) &send_arg,
(xdrproc_t) xdr_nispasswd_updresult, (caddr_t) &result,
TIMEOUT) != RPC_SUCCESS) {
/* printed to stderr */
(void) clnt_perror(clnt, "call to rpc.nispasswdd failed");
*err = NPD_SRVNOTRESP;
return (NPD_FAILED);
}
switch (result.status) {
case NPD_SUCCESS:
return (NPD_SUCCESS);
case NPD_PARTIALSUCCESS:
/* need to assign field/err code */
errl = &result.nispasswd_updresult_u.reason;
if (errl == (struct nispasswd_error *) NULL) {
*err = NPD_SYSTEMERR;
return (NPD_FAILED);
}
*errlst = (nispasswd_error *)
calloc(1, sizeof (nispasswd_error));
if (*errlst == (struct nispasswd_error *) NULL) {
*err = NPD_SYSTEMERR;
return (NPD_FAILED);
}
for (p = *errlst; errl != NULL; errl = errl->next) {
p->npd_field = errl->npd_field;
p->npd_code = errl->npd_code;
if (errl->next != NULL) {
p->next = (nispasswd_error *)
calloc(1, sizeof (nispasswd_error));
p = p->next;
} else
p->next = (nispasswd_error *) NULL;
}
return (NPD_PARTIALSUCCESS);
case NPD_FAILED:
*err = result.nispasswd_updresult_u.npd_err;
return (NPD_FAILED);
default:
/*
* should never reach this case !
*/
*err = NPD_SYSTEMERR;
return (NPD_FAILED);
}
}
void
__npd_free_errlist(list)
nispasswd_error *list;
{
nispasswd_error *p;
if (list == NULL)
return;
for (; list != NULL; list = p) {
p = list->next;
free(list);
}
list = NULL;
}
#else
#if defined(sun)
/* Quiet warnings */
static int dummy;
#endif /* sun */
#endif /* PAM_NISPLUS */

View File

@@ -0,0 +1,213 @@
$ $XConsortium: pam_unix.msg /main/2 1996/07/24 19:04:15 drk $
$ *************************************<+>*************************************
$ *****************************************************************************
$ **
$ ** File: pam_unix.msg
$ **
$ ** Project: pam
$ **
$ ** Description:
$ ** -----------
$ ** This file is the source for the pam_unix message catalog.
$ **
$ ** It contains messages for the pam_unix service module (set 1).
$ **
$ ** Also contains messages for pam_dial (set 2) and pam_test (set 3) modules.
$ **
$ *****************************************************************************
$ **
$ ** (c) Copyright 1996 Sun Microsystems, Inc.
$ ** All Rights reserved
$ **
$ *****************************************************************************
$ *************************************<+>*************************************
$ *****************************************************************************
$
$ ***** NOTE FOR MESSAGE CATALOG TRANSLATORS *****
$
$ There may be three types of messages in this file:
$
$ 1. Messages that appear in dialogs or are displayed to the user.
$
$ These messages are the default and they should ALL BE LOCALIZED.
$ Note that these messages do NOT have any identification (see the
$ comments for type 2 and 3 below).
$
$ 2. Messages that only appear in the error log file.
$
$ The localization of these messages is OPTIONAL. These messages are
$ identified by the following:
$
$ MESSAGES xx-yy IN SET zz WILL ONLY APPEAR IN THE DT ERRORLOG FILE
$
$ 3. Messages that should not be localized.
$
$ These messages are identified by the following:
$
$ DO NOT TRANSLATE or CHANGE or LOCALIZE MESSAGES xx-yy from set zz
$
$ ***** END (NOTE FOR MESSAGE CATALOG TRANSLATORS) *****
$
$ ******************************************************************************
$ unix module messages
$set 1
$ switch_utils.c
$ Msg 1 thru 8 print on consecutive lines.
$ Keep intentation for "passwd:" in messages 2 thru 7
1 Supported configurations for passwd management are as follows:
2 passwd: files
3 passwd: files nis
4 passwd: files nisplus
5 passwd: compat
6 passwd: compat AND
7 passwd_compat: nisplus
8 Please check your /etc/nsswitch.conf file
9 Can't find name service for passwd
10 You may not use nisplus repository
11 Your specified repository is not defined in the nsswitch file!
$ unix_acct_mgmt.c
20 Your password has been expired for too long.
21 Please contact the system administrator
22 Your password will expire within 24 hours.
23 Your password will expire in %d day.
24 Your password will expire in %d days.
$ unix_authenticate.c
30 UNIX Password:
31 Password:
$ unix_get_authtokattr.c
40 You must specify repository when displaying passwd attributes
$ leave "%s" unchanged
41 %s: System error: repository out of range
42 Unable to retrieve username.
$ leave "%s" unchanged
43 %s: Unexpected failure. Password database unchanged.
$ unix_setcred.c
$ translate 50-51 as a single sentence
50 Removing root credentials would break the rpc services that
51 use secure rpc on this host!
52 Root may use keylogout -f to do this (at your own risk)!
53 Could not unset your secret key.
54 Maybe the keyserver is down?
55 Warning: NFS credentials not destroyed
56 Password does not decrypt secret key for %s.
57 Could not set secret key for %s. The key server may be down.
$ unix_update_authtok.c
60 %s%s: %s does not exist
61 %s%s: user must have NIS+ credential
62 Enter login(NIS) password:
63 Enter login(NIS+) password:
64 Enter login password:
65 %s%s: Sorry.
66 %s%s: Sorry, wrong passwd
67 This password differs from your secure RPC password.
68 Please enter your old Secure RPC password:
69 This password does not decrypt your secure RPC credentials. Try again:
70 Please enter your old Secure RPC password:
71 %s%s: Sorry: less than %ld days since the last change.
72 %s%s: You may not change this password.
73 %s%s: can't create process
74 New password:
75 Re-enter new password:
76 %s%s: Too many tries; try again later
77 %s%s: They don't match; try again.
78 %s%s: Too many failures - try later.
79 %s%s: Password too short - must be at least 6 characters.
80 %s%s: Password cannot be circular shift of logonid.
81 %s%s: The first %d characters of the password
82 must contain at least two alphabetic characters and at least
83 one numeric or special character.
84 %s%s: Passwords must differ by at least 3 positions
85 nispasswd: user must have LOCAL credential
86 %s: invalid LOCAL credential
$ unix_update_authtok_file.c
90 %s%s: Password database busy. Try again later.
91 %s%s: Unexpected failure. Password database unchanged.
92 %s%s: Unexpected failure. Password database missing.
93 %s%s: passwd successfully changed for %s
94 %s: No local passwd record
$ unix_update_authtok_nis.c
100 %s%s: couldn't change passwd/attributes
101 %s%s: Couldn't change passwd/attributes for %s
102 NIS(YP) passwd/attributes changed on %s
103 System error: no NIS passwd record for %s
104 %s: System error%s: shell is set illegally
105 System error%s: homedir is set illegally.
106 System error: gecos is set illegally.
107 %s: secret key reencrypted for %s on %s
$ unix_update_authtok_nisplus.c
108 NIS+ password information changed for %s
109 NIS+ credential information changed for %s
110 Unable to reencrypt NIS+ credentials for %s;
111 %s%s: Password information update failed
112 NIS+ password information changed for %s
113 The NIS+ credential information for %s will not be changed.
114 User %s must do the following to update his/her
115 credential information:
116 Use NEW passwd for login and OLD passwd for keylogin.
$ translate 117-118 as a single sentance.
117 Use \"chkey -p\" to reencrypt the credentials with the
118 new login passwd.
119 The user must keylogin explicitly after their next login.
120 WARNING: Could not reencrypt NIS+ credentials for %s;
121 login and keylogin passwords differ.
122 Use NEW passwd for login and OLD passwd for keylogin.
123 You must keylogin explicitly after your next login.
124 %s%s: couldn't change password for %s.
125 Reason: failed to update the cred table with reencrypted credentials.
126 Please notify your System Administrator.
127 NIS+ Password incorrect: try again
128 NIS+ password information update failed while talking to NIS+ passwd daemon
129 GECOS information was not updated: check NIS+ permissions.
130 SHELL information was not updated: check NIS+ permissions.
131 NIS+ Credential information was not updated.
132 No NIS+ record
133 NIS+ password information update failed (update_attr)
$ unix_utils.c
140 %s%s: Permission denied
141 %s%s: Can't change local passwd file\n
142 %s%s: System error: repository out of range
143 Cannot change from restricted shell %s
144 Old shell: %s
145 New shell:
146 Login shell unchanged.
147 %s is unacceptable as a new shell
148 warning: %s is unavailable on this machine
149 Default values are printed inside of '[]'.
150 To accept the default, type <return>.
151 To have a blank entry, type the word 'none'.
152 Name [%s]:
153 Finger information unchanged.
154 Home Directory [%s]:
155 Homedir information unchanged.
156 ':' is not allowed.
157 Maximum number of characters allowed is %d.
158 Control characters are not allowed.
$ dialup password module messages
$set 2
1 Dialup Password:
$ dialup password module messages
$set 3
1 TEST Password:
2 Password:

View File

@@ -0,0 +1,684 @@
/* $XConsortium: switch_utils.c /main/5 1996/05/09 04:32:20 drk $ */
/*
* Copyright (c) 1992-1995, by Sun Microsystems, Inc.
* All rights reserved.
*/
#ident "@(#)switch_utils.c 1.31 96/02/02 SMI"
#include "unix_headers.h"
/*
* XXX
* This file relies on the fact that you are using NSS_SWITCH.
* If PAM_NIS or PAM_NISPLUS is defined, then the
* include files for nss_switch are included.
* Otherwise, the repository is assumed to be FILES,
* and NSS_SWITCH is not used.
*/
static void pr_config();
/*
* The following is similar to getpwnam() except that it specifies
* where to get the information. This is modeled after getpwnam_r().
*/
#ifdef PAM_NIS
static void
nss_nis_passwd(p)
nss_db_params_t *p;
{
p->name = NSS_DBNAM_PASSWD;
p->flags |= NSS_USE_DEFAULT_CONFIG;
p->default_config = "nis";
}
static void
nss_nis_shadow(p)
nss_db_params_t *p;
{
p->name = NSS_DBNAM_SHADOW;
p->config_name = NSS_DBNAM_PASSWD; /* Use config for "passwd" */
p->flags |= NSS_USE_DEFAULT_CONFIG;
p->default_config = "nis";
}
#endif /* PAM_NIS */
#ifdef PAM_NISPLUS
static void
nss_nisplus_passwd(p)
nss_db_params_t *p;
{
p->name = NSS_DBNAM_PASSWD;
p->flags |= NSS_USE_DEFAULT_CONFIG;
p->default_config = "nisplus";
}
static void
nss_nisplus_shadow(p)
nss_db_params_t *p;
{
p->name = NSS_DBNAM_SHADOW;
p->config_name = NSS_DBNAM_PASSWD; /* Use config for "passwd" */
p->flags |= NSS_USE_DEFAULT_CONFIG;
p->default_config = "nisplus";
}
#endif /* PAM_NISPLUS */
static char *
gettok(nextpp)
char **nextpp;
{
char *p = *nextpp;
char *q = p;
char c;
if (p == 0) {
return (0);
}
while ((c = *q) != '\0' && c != ':') {
q++;
}
if (c == '\0') {
*nextpp = 0;
} else {
*q++ = '\0';
*nextpp = q;
}
return (p);
}
#if (PAM_NIS || PAM_NISPLUS)
/*
* Return values: 0 = success, 1 = parse error, 2 = erange ...
* The structure pointer passed in is a structure in the caller's space
* wherein the field pointers would be set to areas in the buffer if
* need be. instring and buffer should be separate areas.
*/
static int
str2passwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
{
struct passwd *passwd = (struct passwd *)ent;
char *p, *next;
int black_magic; /* "+" or "-" entry */
if (lenstr + 1 > buflen) {
return (NSS_STR_PARSE_ERANGE);
}
/*
* We copy the input string into the output buffer and
* operate on it in place.
*/
(void) memcpy(buffer, instr, lenstr);
buffer[lenstr] = '\0';
next = buffer;
passwd->pw_name = p = gettok(&next); /* username */
if (*p == '\0') {
/* Empty username; not allowed */
return (NSS_STR_PARSE_PARSE);
}
black_magic = (*p == '+' || *p == '-');
if (black_magic) {
passwd->pw_uid = UID_NOBODY;
passwd->pw_gid = GID_NOBODY;
/*
* pwconv tests pw_passwd and pw_age == NULL
*/
passwd->pw_passwd = "";
passwd->pw_age = "";
/*
* the rest of the passwd entry is "optional"
*/
passwd->pw_comment = "";
passwd->pw_gecos = "";
passwd->pw_dir = "";
passwd->pw_shell = "";
}
passwd->pw_passwd = p = gettok(&next); /* password */
if (p == 0) {
if (black_magic)
return (NSS_STR_PARSE_SUCCESS);
else
return (NSS_STR_PARSE_PARSE);
}
for (; *p != '\0'; p++) { /* age */
if (*p == ',') {
*p++ = '\0';
break;
}
}
passwd->pw_age = p;
p = next; /* uid */
if (p == 0 || *p == '\0') {
if (black_magic)
return (NSS_STR_PARSE_SUCCESS);
else
return (NSS_STR_PARSE_PARSE);
}
if (!black_magic) {
passwd->pw_uid = strtol(p, &next, 10);
if (next == p) {
/* uid field should be nonempty */
return (NSS_STR_PARSE_PARSE);
}
/*
* The old code (in 2.0 thru 2.5) would check
* for the uid being negative, or being greater
* than 60001 (the rfs limit). If it met either of
* these conditions, the uid was translated to 60001.
*
* Now we just check for negative uids; anything else
* is administrative policy
*/
if (passwd->pw_uid < 0)
passwd->pw_uid = UID_NOBODY;
}
if (*next++ != ':') {
if (black_magic)
p = gettok(&next);
else
return (NSS_STR_PARSE_PARSE);
}
p = next; /* gid */
if (p == 0 || *p == '\0') {
if (black_magic)
return (NSS_STR_PARSE_SUCCESS);
else
return (NSS_STR_PARSE_PARSE);
}
if (!black_magic) {
passwd->pw_gid = strtol(p, &next, 10);
if (next == p) {
/* gid field should be nonempty */
return (NSS_STR_PARSE_PARSE);
}
/*
* gid should be non-negative; anything else
* is administrative policy.
*/
if (passwd->pw_gid < 0)
passwd->pw_gid = GID_NOBODY;
}
if (*next++ != ':') {
if (black_magic)
p = gettok(&next);
else
return (NSS_STR_PARSE_PARSE);
}
passwd->pw_gecos = passwd->pw_comment = p = gettok(&next);
if (p == 0) {
if (black_magic)
return (NSS_STR_PARSE_SUCCESS);
else
return (NSS_STR_PARSE_PARSE);
}
passwd->pw_dir = p = gettok(&next);
if (p == 0) {
if (black_magic)
return (NSS_STR_PARSE_SUCCESS);
else
return (NSS_STR_PARSE_PARSE);
}
passwd->pw_shell = p = gettok(&next);
if (p == 0) {
if (black_magic)
return (NSS_STR_PARSE_SUCCESS);
else
return (NSS_STR_PARSE_PARSE);
}
/* Better not be any more fields... */
if (next == 0) {
/* Successfully parsed and stored */
return (NSS_STR_PARSE_SUCCESS);
}
return (NSS_STR_PARSE_PARSE);
}
typedef const char *constp;
static bool_t /* 1 means success and more input, 0 means error or no more */
getfield(nextp, limit, uns, valp)
constp *nextp;
constp limit;
int uns;
void *valp;
{
constp p = *nextp;
char *endfield;
char numbuf[12]; /* Holds -2^31 and trailing \0 */
int len;
if (p == 0 || p >= limit) {
return (0);
}
if (*p == ':') {
p++;
*nextp = p;
return (p < limit);
}
if ((len = limit - p) > sizeof (numbuf) - 1) {
len = sizeof (numbuf) - 1;
}
/*
* We want to use strtol() and we have a readonly non-zero-terminated
* string, so first we copy and terminate the interesting bit.
* Ugh. (It's convenient to terminate with a colon rather than \0).
*/
if ((endfield = memccpy(numbuf, p, ':', len)) == 0) {
if (len != limit - p) {
/* Error -- field is too big to be a legit number */
return (0);
}
numbuf[len] = ':';
p = limit;
} else {
p += (endfield - numbuf);
}
if (uns) {
*((unsigned long *)valp) = strtoul(numbuf, &endfield, 10);
} else {
*((long *)valp) = strtol(numbuf, &endfield, 10);
}
if (*endfield != ':') {
/* Error -- expected <integer><colon>, got something else */
return (0);
}
*nextp = p;
return (p < limit);
}
/*
* str2spwd() -- convert a string to a shadow passwd entry. The parser is
* more liberal than the passwd or group parsers; since it's legitimate
* for almost all the fields here to be blank, the parser lets one omit
* any number of blank fields at the end of the entry. The acceptable
* forms for '+' and '-' entries are the same as those for normal entries.
* === Is this likely to do more harm than good?
*
* Return values: 0 = success, 1 = parse error, 2 = erange ...
* The structure pointer passed in is a structure in the caller's space
* wherein the field pointers would be set to areas in the buffer if
* need be. instring and buffer should be separate areas.
*/
int
str2spwd(instr, lenstr, ent, buffer, buflen)
const char *instr;
int lenstr;
void *ent; /* really (struct spwd *) */
char *buffer;
int buflen;
{
struct spwd *shadow = (struct spwd *)ent;
const char *p = instr, *limit;
char *bufp;
int lencopy, black_magic;
limit = p + lenstr;
if ((p = memchr(instr, ':', lenstr)) == 0 ||
++p >= limit ||
(p = memchr(p, ':', limit - p)) == 0) {
lencopy = lenstr;
p = 0;
} else {
lencopy = p - instr;
p++;
}
if (lencopy + 1 > buflen) {
return (NSS_STR_PARSE_ERANGE);
}
(void) memcpy(buffer, instr, lencopy);
buffer[lencopy] = 0;
black_magic = (*instr == '+' || *instr == '-');
shadow->sp_namp = bufp = buffer;
shadow->sp_pwdp = 0;
shadow->sp_lstchg = -1;
shadow->sp_min = -1;
shadow->sp_max = -1;
shadow->sp_warn = -1;
shadow->sp_inact = -1;
shadow->sp_expire = -1;
shadow->sp_flag = 0;
if ((bufp = strchr(bufp, ':')) == 0) {
if (black_magic)
return (NSS_STR_PARSE_SUCCESS);
else
return (NSS_STR_PARSE_PARSE);
}
*bufp++ = '\0';
shadow->sp_pwdp = bufp;
if (instr == 0) {
if ((bufp = strchr(bufp, ':')) == 0) {
if (black_magic)
return (NSS_STR_PARSE_SUCCESS);
else
return (NSS_STR_PARSE_PARSE);
}
*bufp++ = '\0';
p = bufp;
} /* else p was set when we copied name and passwd into the buffer */
if (!getfield(&p, limit, 0, &shadow->sp_lstchg))
return (NSS_STR_PARSE_SUCCESS);
if (!getfield(&p, limit, 0, &shadow->sp_min))
return (NSS_STR_PARSE_SUCCESS);
if (!getfield(&p, limit, 0, &shadow->sp_max))
return (NSS_STR_PARSE_SUCCESS);
if (!getfield(&p, limit, 0, &shadow->sp_warn))
return (NSS_STR_PARSE_SUCCESS);
if (!getfield(&p, limit, 0, &shadow->sp_inact))
return (NSS_STR_PARSE_SUCCESS);
if (!getfield(&p, limit, 0, &shadow->sp_expire))
return (NSS_STR_PARSE_SUCCESS);
if (!getfield(&p, limit, 1, &shadow->sp_flag))
return (NSS_STR_PARSE_SUCCESS);
if (p != limit) {
/* Syntax error -- garbage at end of line */
return (NSS_STR_PARSE_PARSE);
}
return (NSS_STR_PARSE_SUCCESS);
}
static nss_XbyY_buf_t *buffer;
static DEFINE_NSS_DB_ROOT(db_root);
#define GETBUF() \
NSS_XbyY_ALLOC(&buffer, sizeof (struct passwd), NSS_BUFLEN_PASSWD)
struct passwd *
getpwnam_from(name, rep)
const char *name;
int rep;
{
nss_XbyY_buf_t *b = GETBUF();
nss_XbyY_args_t arg;
if (b == 0)
return (0);
NSS_XbyY_INIT(&arg, b->result, b->buffer, b->buflen, str2passwd);
arg.key.name = name;
switch (rep) {
#ifdef PAM_NISPLUS
case PAM_REP_NISPLUS:
nss_search(&db_root, nss_nisplus_passwd, NSS_DBOP_PASSWD_BYNAME,
&arg);
break;
#endif
#ifdef PAM_NIS
case PAM_REP_NIS:
nss_search(&db_root, nss_nis_passwd, NSS_DBOP_PASSWD_BYNAME,
&arg);
break;
#endif
default:
return (NULL);
}
return (struct passwd *) NSS_XbyY_FINI(&arg);
}
static nss_XbyY_buf_t *spbuf;
static DEFINE_NSS_DB_ROOT(spdb_root);
#define GETSPBUF() \
NSS_XbyY_ALLOC(&spbuf, sizeof (struct spwd), NSS_BUFLEN_SHADOW)
struct spwd *
getspnam_from(name, rep)
const char *name;
int rep;
{
nss_XbyY_buf_t *b = GETSPBUF();
nss_XbyY_args_t arg;
if (b == 0)
return (0);
NSS_XbyY_INIT(&arg, b->result, b->buffer, b->buflen, str2spwd);
arg.key.name = name;
switch (rep) {
#ifdef PAM_NISPLUS
case PAM_REP_NISPLUS:
nss_search(&spdb_root, nss_nisplus_shadow,
NSS_DBOP_SHADOW_BYNAME, &arg);
break;
#endif
#ifdef PAM_NIS
case PAM_REP_NIS:
nss_search(&spdb_root, nss_nis_shadow,
NSS_DBOP_SHADOW_BYNAME, &arg);
break;
#endif
default:
return (NULL);
}
return (struct spwd *) NSS_XbyY_FINI(&arg);
}
#endif /* (PAM_NIS || PAM_NISPLUS) */
static void
pr_config(pamh)
pam_handle_t *pamh;
{
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
sprintf(messages[0], PAM_MSG(pamh, 1,
"Supported configurations for passwd management are as follows:"));
sprintf(messages[1], PAM_MSG(pamh, 2, " passwd: files"));
sprintf(messages[2], PAM_MSG(pamh, 3, " passwd: files nis"));
sprintf(messages[3], PAM_MSG(pamh, 4, " passwd: files nisplus"));
sprintf(messages[4], PAM_MSG(pamh, 5, " passwd: compat"));
sprintf(messages[5], PAM_MSG(pamh, 6, " passwd: compat AND"));
sprintf(messages[6], PAM_MSG(pamh, 7, " passwd_compat: nisplus"));
sprintf(messages[7],
PAM_MSG(pamh, 8, "Please check your /etc/nsswitch.conf file"));
/* display the above 8 messages */
(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 8, messages, NULL);
}
/*
* get name services (or repositories) of passwd.
* o_rep: the specified respository in command line. If no repository is
* specified in the command line, o_rep is equal to PAM_REP_DEFAULT.
* return value: new repositories
* 1. In the case of PAM_REP_DEFAULT, new repositories are from nsswitch
* file (as long as it represents a valid and supported configuration).
* 2. In the case of specified repository, it should be present as one
* of the valid services (or repositories) in nsswitch file.
* A warning is printed if this happens. Operation is continued.
*/
int
get_ns(pamh, o_rep, debug, nowarn)
pam_handle_t *pamh;
int o_rep;
int debug;
int nowarn;
{
#if (PAM_NIS || PAM_NISPLUS)
struct __nsw_switchconfig *conf = NULL;
struct __nsw_switchconfig *confcomp = NULL;
enum __nsw_parse_err pserr;
struct __nsw_lookup *lkp;
struct __nsw_lookup *lkp2;
int rep = 0;
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
/* yppasswd/nispasswd doesn't care about nsswitch file */
if (IS_OPWCMD(o_rep))
return (o_rep);
conf = __nsw_getconfig("passwd", &pserr);
if (conf == NULL) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 9,
"Can't find name service for passwd"));
__pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
if (IS_NISPLUS(o_rep)) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 10,
"You may not use nisplus repository"));
__pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
return (-1);
} else if (o_rep != PAM_REP_DEFAULT) {
/*
* The user specified a repository:
* Allow the user to try to change the passwd
* even though the specified repository is
* not listed in nsswitch.conf
*/
return (o_rep);
} else {
/*
* The user did not specify a repository:
* Allow the user to try to change the passwd
* in the default repositories (files and nis)
* even though we can not find the name service
* switch entry.
*/
rep = PAM_REP_FILES | PAM_REP_NIS;
return (rep); /* default */
}
}
if (debug)
syslog(LOG_DEBUG, "number of services is %d",
conf->num_lookups);
lkp = conf->lookups;
/*
* XXX: Currently we do now support more than 2 services
*/
if (conf->num_lookups > 2) {
pr_config(pamh);
return (-1);
} else if (conf->num_lookups == 1) {
/* files or compat */
if (strcmp(lkp->service_name, "files") == 0) {
rep |= PAM_REP_FILES;
if (o_rep == PAM_REP_NIS || o_rep == PAM_REP_NISPLUS) {
if (!nowarn) {
sprintf(messages[0],
PAM_MSG(pamh, 11,
"Your specified repository is not defined in the nsswitch file!"));
__pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
return (o_rep);
}
return (rep);
} else if (strcmp(lkp->service_name, "compat") == 0) {
/* get passwd_compat */
confcomp = __nsw_getconfig("passwd_compat", &pserr);
if (confcomp == NULL) {
rep = PAM_REP_FILES | PAM_REP_NIS;
if (o_rep == PAM_REP_NISPLUS) {
if (!nowarn) {
sprintf(messages[0],
PAM_MSG(pamh, 11,
"Your specified repository is not defined in the nsswitch file!"));
__pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
return (o_rep);
} else if (o_rep != PAM_REP_DEFAULT)
return (o_rep);
else
return (rep);
} else {
/* check the service: nisplus? */
if (strcmp(confcomp->lookups->service_name,
"nisplus") == 0) {
rep = PAM_REP_FILES | PAM_REP_NISPLUS;
if (o_rep == PAM_REP_NIS) {
if (!nowarn) {
sprintf(messages[0],
PAM_MSG(pamh, 11,
"Your specified repository is not defined in the nsswitch file!"));
__pam_display_msg(pamh,
PAM_ERROR_MSG,
1, messages, NULL);
}
return (o_rep);
} else if (o_rep != PAM_REP_DEFAULT)
return (o_rep);
else
return (rep);
} else {
/* passwd_compat must be nisplus?? */
return (-1);
}
}
} else {
pr_config(pamh);
return (-1);
}
} else { /* two services */
lkp = conf->lookups;
lkp2 = lkp->next;
if (strcmp(lkp->service_name, "files") == 0) {
/* files nis, or files nisplus */
rep |= PAM_REP_FILES;
/* continue */
} else {
pr_config(pamh);
return (-1);
}
if (strcmp(lkp2->service_name, "nis") == 0) {
rep |= PAM_REP_NIS;
if (o_rep == PAM_REP_NISPLUS) {
if (!nowarn) {
sprintf(messages[0],
PAM_MSG(pamh, 11,
"Your specified repository is not defined in the nsswitch file!"));
__pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
return (o_rep);
} else if (o_rep != PAM_REP_DEFAULT)
return (o_rep);
else
return (rep);
} else if (strcmp(lkp2->service_name, "nisplus") == 0) {
rep |= PAM_REP_NISPLUS;
if (o_rep == PAM_REP_NIS) {
if (!nowarn) {
sprintf(messages[0],
PAM_MSG(pamh, 11,
"Your specified repository is not defined in the nsswitch file!"));
__pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
return (o_rep);
} else if (o_rep != PAM_REP_DEFAULT)
return (o_rep);
else
return (rep);
} else {
pr_config(pamh);
return (-1);
}
}
#else
return (PAM_REP_FILES);
#endif /* (PAM_NIS || PAM_NISPLUS) */
}

View File

@@ -0,0 +1,313 @@
/* $XConsortium: unix_acct_mgmt.c /main/5 1996/05/09 04:32:39 drk $ */
/*
* Copyright (c) 1992-1995, by Sun Microsystems, Inc.
* All rights reserved.
*/
#ident "@(#)unix_acct_mgmt.c 1.35 95/12/08 SMI"
#include "unix_headers.h"
static void
unix_cleanup(
pam_handle_t *pamh,
void *data,
int pam_status)
{
free((unix_authtok_data *)data);
}
/*
* check_for_login_inactivity - Check for login inactivity
*
*/
static int
check_for_login_inactivity(
struct passwd pwd,
struct spwd shpwd)
{
int fdl;
struct lastlog ll;
int retval;
long long offset;
offset = (long long) pwd.pw_uid * (long long) sizeof (struct lastlog);
if ((fdl = open(LASTLOG, O_RDWR|O_CREAT, 0444)) >= 0) {
/*
* Read the last login (ll) time
*/
if (llseek(fdl, offset, SEEK_SET) != offset) {
/*
* XXX uid too large for database
*/
return (0);
}
retval = read(fdl, (char *)&ll, sizeof (ll));
/* Check for login inactivity */
if ((shpwd.sp_inact > 0) && (retval == sizeof (ll)) &&
ll.ll_time) {
if (((ll.ll_time / DAY) + shpwd.sp_inact) < DAY_NOW) {
/*
* Account inactive for too long
*/
(void) close(fdl);
return (1);
}
}
(void) close(fdl);
}
return (0);
}
/*
* new_password_check()
*
* check to see if the user needs to change their password
*/
static int
new_password_check(pwd, shpwd, flags)
struct passwd *pwd;
struct spwd *shpwd;
int flags;
{
int now = DAY_NOW;
/*
* We want to make sure that we change the password only if
* passwords are required for the system, the user does not
* have a password, AND the user's NULL password can be changed
* according to its password aging information
*/
if ((flags & PAM_DISALLOW_NULL_AUTHTOK) != 0) {
if (shpwd->sp_pwdp[0] == '\0') {
if ((pwd->pw_uid != 0) &&
((shpwd->sp_max == -1) ||
(shpwd->sp_lstchg > now) ||
((now >= shpwd->sp_lstchg + shpwd->sp_min) &&
(shpwd->sp_max >= shpwd->sp_min)))) {
return (PAM_NEW_AUTHTOK_REQD);
}
}
}
return (PAM_SUCCESS);
}
/*
* perform_passwd_aging_check
* - Check for password exipration.
*/
static int
perform_passwd_aging_check(
pam_handle_t *pamh,
struct spwd shpwd,
int flags)
{
int now = DAY_NOW;
int Idleweeks = -1;
char *ptr;
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
if (defopen(LOGINADMIN) == 0) {
if ((ptr = defread("IDLEWEEKS=")) != NULL)
Idleweeks = atoi(ptr);
(void) defopen(NULL);
}
if ((shpwd.sp_lstchg == 0) ||
((shpwd.sp_max >= 0) &&
(now > (shpwd.sp_lstchg + shpwd.sp_max)) &&
(shpwd.sp_max >= shpwd.sp_min))) {
if ((Idleweeks == 0) ||
((Idleweeks > 0) &&
(now > (shpwd.sp_lstchg + (7 * Idleweeks))))) {
if (!(flags & PAM_SILENT)) {
strcpy(messages[0], PAM_MSG(pamh, 20,
"Your password has been expired for too long."));
strcpy(messages[1], PAM_MSG(pamh, 21,
"Please contact the system administrator"));
__pam_display_msg(pamh, PAM_ERROR_MSG,
2, messages, NULL);
}
return (PAM_AUTHTOK_EXPIRED);
} else {
return (PAM_NEW_AUTHTOK_REQD);
}
}
return (PAM_SUCCESS);
}
/*
* warn_user_passwd_will_expire - warn the user when the password will
* expire.
*/
static void
warn_user_passwd_will_expire(
pam_handle_t *pamh,
struct spwd shpwd)
{
int now = DAY_NOW;
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
int days;
if ((shpwd.sp_warn > 0) && (shpwd.sp_max > 0) &&
(now + shpwd.sp_warn) >= (shpwd.sp_lstchg + shpwd.sp_max)) {
days = (shpwd.sp_lstchg + shpwd.sp_max) - now;
if (days <= 0)
sprintf(messages[0], PAM_MSG(pamh, 22,
"Your password will expire within 24 hours."));
else if (days == 1)
sprintf(messages[0], PAM_MSG(pamh, 23,
"Your password will expire in %d day."), days);
else
sprintf(messages[0], PAM_MSG(pamh, 24,
"Your password will expire in %d days."), days);
__pam_display_msg(pamh, PAM_TEXT_INFO, 1, messages, NULL);
}
}
/*
* pam_sm_acct_mgmt - main account managment routine.
* Returns: module error or specific error on failure
*/
int
pam_sm_acct_mgmt(
pam_handle_t *pamh,
int flags,
int argc,
const char **argv)
{
struct spwd shpwd;
struct passwd pwd;
char pwd_buf[1024];
char shpwd_buf[1024];
int error = PAM_ACCT_EXPIRED;
char *user;
int i;
int debug = 0;
int nowarn = 0;
uid_t orig_uid;
unix_authtok_data *status;
for (i = 0; i < argc; i++) {
if (strcasecmp(argv[i], "debug") == 0)
debug = 1;
else if (strcasecmp(argv[i], "nowarn") == 0) {
nowarn = 1;
flags = flags | PAM_SILENT;
} else {
syslog(LOG_ERR,
"UNIX pam_sm_acct_mgmt: illegal option %s",
argv[i]);
}
}
if ((error = pam_get_item(pamh, PAM_USER, (void **)&user))
!= PAM_SUCCESS)
goto out;
if (user == NULL) {
error = PAM_USER_UNKNOWN;
goto out;
}
/*
* Get the password and shadow password entries
*/
if (getpwnam_r(user, &pwd, pwd_buf, sizeof (pwd_buf)) == NULL ||
getspnam_r(user, &shpwd, shpwd_buf, sizeof (shpwd_buf)) == NULL) {
error = PAM_USER_UNKNOWN;
goto out;
}
if (shpwd.sp_pwdp != NULL && strcmp(shpwd.sp_pwdp, "*NP*") == 0) {
orig_uid = geteuid();
seteuid(pwd.pw_uid);
memset(pwd_buf, 0, sizeof (pwd_buf));
memset(shpwd_buf, 0, sizeof (shpwd_buf));
if (getpwnam_r(user, &pwd, pwd_buf, sizeof (pwd_buf)) == NULL ||
getspnam_r(user, &shpwd, shpwd_buf, sizeof (shpwd_buf))
== NULL) {
error = PAM_USER_UNKNOWN;
seteuid(orig_uid);
goto out;
}
seteuid(orig_uid);
}
/*
* Check for account expiration
*/
if (shpwd.sp_expire > 0 &&
shpwd.sp_expire < DAY_NOW) {
error = PAM_ACCT_EXPIRED;
goto out;
}
/*
* Check for excessive login account inactivity
*/
if (check_for_login_inactivity(pwd, shpwd)) {
error = PAM_PERM_DENIED;
goto out;
}
/*
* Check to see if the user needs to change their password
*/
if (error = new_password_check(&pwd, &shpwd, flags)) {
goto out;
}
/*
* Check to make sure password aging information is okay
*/
if ((error = perform_passwd_aging_check(pamh, shpwd, flags))
!= PAM_SUCCESS) {
goto out;
}
/*
* Finally, warn the user if their password is about to expire.
*/
if (!(flags & PAM_SILENT)) {
warn_user_passwd_will_expire(pamh, shpwd);
}
/*
* All done, return Success
*/
error = PAM_SUCCESS;
out:
memset(shpwd_buf, 0, sizeof (shpwd_buf));
/* store the password aging status in the pam handle */
if (pam_get_data(pamh, UNIX_AUTHTOK_DATA, (void **)&status)
!= PAM_SUCCESS) {
if ((status = (unix_authtok_data *)calloc
(1, sizeof (unix_authtok_data))) == NULL) {
return (PAM_BUF_ERR);
}
}
status->age_status = error;
if (pam_set_data(pamh, UNIX_AUTHTOK_DATA, status, unix_cleanup)
!= PAM_SUCCESS) {
free(status);
return (PAM_SERVICE_ERR);
}
return (error);
}

View File

@@ -0,0 +1,355 @@
/* $XConsortium: unix_authenticate.c /main/5 1996/05/09 04:32:58 drk $ */
/*
* Copyright (c) 1992-1995, by Sun Microsystems, Inc.
* All rights reserved.
*/
#ident "@(#)unix_authenticate.c 1.58 96/02/09 SMI"
#include "unix_headers.h"
#ifdef PAM_SECURE_RPC
static void
unix_cleanup(
pam_handle_t *pamh,
void *data,
int pam_status)
{
free((unix_auth_data *)data);
}
#endif
static int attempt_authentication(char *, char *, char *, uid_t, int, int);
/*
* pam_sm_authenticate - Authenticate user
*/
int
pam_sm_authenticate(
pam_handle_t *pamh,
int flags,
int argc,
const char **argv)
{
struct spwd shpwd; /* Shadow password structure */
struct passwd pwd; /* password structure */
char shpwd_buf[1024];
char pwd_buf[1024];
char *password = NULL;
char *dummy_passwd = "no:password";
int err = PAM_SUCCESS;
int retcode;
int debug = 0;
int try_first_pass = 0;
int use_first_pass = 0;
int i;
uid_t uid;
char *service, *user;
#ifdef PAM_SECURE_RPC
unix_auth_data *status;
char netname[MAXNETNAMELEN+1];
int estkey_stat;
#endif
for (i = 0; i < argc; i++) {
if (strcasecmp(argv[i], "debug") == 0)
debug = 1;
else if (strcasecmp(argv[i], "nowarn") == 0)
flags = flags | PAM_SILENT;
else if (strcmp(argv[i], "try_first_pass") == 0)
try_first_pass = 1;
else if (strcmp(argv[i], "use_first_pass") == 0)
use_first_pass = 1;
else {
syslog(LOG_ERR, "illegal option %s", argv[i]);
}
}
if ((err = pam_get_item(pamh, PAM_SERVICE, (void **)&service))
!= PAM_SUCCESS ||
(err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
return (err);
if (debug)
syslog(LOG_DEBUG,
"unix pam_sm_authenticate(%s %s), flags = %x ",
service, (user)?user:"no-user", flags);
if (!user) {
return (PAM_USER_UNKNOWN);
}
/*
* Get the password and shadow password entry
*/
memset(pwd_buf, 0, sizeof (pwd_buf));
memset(shpwd_buf, 0, sizeof (shpwd_buf));
if (getpwnam_r(user, &pwd, pwd_buf, sizeof (pwd_buf)) == NULL ||
getspnam_r(user, &shpwd, shpwd_buf, sizeof (shpwd_buf)) == NULL) {
err = PAM_USER_UNKNOWN;
/*
* Mask unknown users.
* Set up a dummy password.
*/
shpwd.sp_pwdp = dummy_passwd;
}
/*
* Is a password check required?
*/
/* Is there anything there to check? */
if ((shpwd.sp_pwdp == 0) || (*shpwd.sp_pwdp == '\0')) {
/*
* The /etc/default/login file will specify if passwords
* are required. If not, then simply return SUCCESS.
* Otherwise, flag the error, but still prompt the user
* for a password to mask the failure.
*/
if ((flags & PAM_DISALLOW_NULL_AUTHTOK) == 0)
goto out;
err = PAM_SERVICE_ERR;
goto prompt;
}
if ((err = __pam_get_authtok(pamh, PAM_HANDLE, PAM_AUTHTOK,
PASSWORD_LEN, NULL, &password)) != PAM_SUCCESS)
goto out;
if (try_first_pass) {
/*
* Try to login using the password from the first
* scheme, e.g. DCE password. If anything goes wrong,
* then simply prompt users for password.
*/
retcode = attempt_authentication(user, password,
shpwd.sp_pwdp, pwd.pw_uid,
flags, debug);
if (err != PAM_USER_UNKNOWN)
err = retcode;
if (err == PAM_SUCCESS)
goto post_prompt;
else
goto prompt;
} else if (use_first_pass) {
/*
* Try to login using the password from the first
* scheme, e.g. DCE password. If anything goes wrong,
* quit, and return the error;
*/
retcode = attempt_authentication(user, password,
shpwd.sp_pwdp, pwd.pw_uid,
flags, debug);
if (err != PAM_USER_UNKNOWN)
err = retcode;
if (err == PAM_SUCCESS)
goto post_prompt;
else
goto out;
}
prompt:
/*
* Get the password from the user
*/
if ((password != NULL && password[0] != '\0') || try_first_pass) {
if (password) {
memset(password, 0, strlen(password));
free(password);
password = NULL;
}
if ((retcode = __pam_get_authtok(pamh, PAM_PROMPT,
PAM_AUTHTOK, PASSWORD_LEN,
PAM_MSG(pamh, 30, "UNIX Password: "),
&password)) != PAM_SUCCESS) {
if (err != PAM_USER_UNKNOWN)
err = retcode;
goto out;
}
} else {
if (password) {
memset(password, 0, strlen(password));
free(password);
password = NULL;
}
if ((retcode = __pam_get_authtok(pamh, PAM_PROMPT,
PAM_AUTHTOK, PASSWORD_LEN,
PAM_MSG(pamh, 31, "Password: "),
&password)) != PAM_SUCCESS) {
if (err != PAM_USER_UNKNOWN)
err = retcode;
goto out;
}
}
retcode = attempt_authentication(user, password,
shpwd.sp_pwdp, pwd.pw_uid, flags, debug);
if (err != PAM_USER_UNKNOWN)
err = retcode;
if (err != PAM_SUCCESS)
goto out;
post_prompt:
#ifdef PAM_SECURE_RPC
/*
* Do a keylogin if the password is
* not null and its not a root login.
* This code used to be in pam_setcred().
*/
uid = pwd.pw_uid;
if (password != NULL &&
password[0] != '\0' &&
uid != 0) {
/*
* we always ask to reestablish the private key with
* keyserv to solve the problem that the keys may have
* changed and a re-keylogin not done
*/
estkey_stat = establish_key(uid, password, 1, netname);
/*
* Store the return value as module specific data
* to be printed out later in pam_setcred().
*/
if (pam_get_data(pamh, UNIX_AUTH_DATA, (void**)&status)
!= PAM_SUCCESS) {
if ((status = (unix_auth_data *)calloc
(1, sizeof (unix_auth_data)))
== NULL) {
err = PAM_BUF_ERR;
goto out;
}
}
status->key_status = estkey_stat;
strcpy(status->netname, netname);
if (pam_set_data(pamh, UNIX_AUTH_DATA, status, unix_cleanup)
!= PAM_SUCCESS) {
err = PAM_SERVICE_ERR;
goto out;
}
}
#endif /* PAM_SECURE_RPC */
out:
if (password) {
memset(password, 0, strlen(password));
free(password);
}
return (err);
}
static int
attempt_authentication(char *user, char *password, char *enc_passwd,
uid_t uid, int flags, int debug)
{
struct passwd pwd;
struct spwd shpwd;
char shpwd_buf[1024];
char pwd_buf[1024];
int estkey_stat;
uid_t orig_uid;
int err = 0;
if (password == NULL || password[0] == '\0') {
if (debug)
syslog(LOG_DEBUG,
"unix_auth: NULL passwd in attempt_authenticate()");
return (PAM_AUTH_ERR);
} else {
/*
* Yes, there is some string in the sp_pwdp field.
* We have one of the following two situations:
* 1) the sp_pwdp string is actually the encrypted
* user's password,
* or 2) the sp_pwdp string is "*NP*", which means we
* didn't actually have permission to read the
* password field in the name service.
*
* In either case, we must obtain the password from the
* user. In situation 2, we can't actually tell yet
* whether the unix password is present or not. We must
* get the password from the user, just to establish
* the user's secure RPC credentials. Then, having
* established the user's Secure RPC credentials, we
* need to re-obtain the shpwd structure. At that point,
* if the unix password is present there, we check it
* against that too.
*/
if (strcmp(enc_passwd, "*NP*") == 0) {
#ifdef PAM_SECURE_RPC
estkey_stat = establish_key(uid,
password, 1, NULL);
if (estkey_stat != ESTKEY_SUCCESS) {
/* Failed to establish secret key. */
switch (estkey_stat) {
case ESTKEY_BADPASSWD:
err = PAM_AUTH_ERR;
break;
case ESTKEY_NOCREDENTIALS:
/*
* user requires credentials to
* read passwd field but doesn't
* have any should syslog() a
* message for admin
*/
syslog(LOG_ALERT,
"User %s needs Secure RPC \
credentials to login.", user);
err = PAM_SERVICE_ERR;
break;
default:
err = PAM_SERVICE_ERR;
}
return (err);
}
orig_uid = geteuid();
seteuid(uid);
memset(pwd_buf, 0, sizeof (pwd_buf));
memset(shpwd_buf, 0, sizeof (shpwd_buf));
if (getpwnam_r(user, &pwd, pwd_buf,
sizeof (pwd_buf)) == NULL ||
getspnam_r(user, &shpwd, shpwd_buf,
sizeof (shpwd_buf)) == NULL) {
seteuid(orig_uid);
return (PAM_USER_UNKNOWN);
}
seteuid(orig_uid);
if ((shpwd.sp_pwdp != 0) &&
(strcmp(shpwd.sp_pwdp, "*NP*") == 0)) {
syslog(LOG_ALERT,
"Permissions on the password database may be too restrictive");
return (PAM_AUTH_ERR);
}
enc_passwd = shpwd.sp_pwdp;
#else
return (PAM_AUTH_ERR);
#endif /* PAM_SECURE_RPC */
}
if ((enc_passwd == 0) ||
(*enc_passwd == '\0')) {
if (flags & PAM_DISALLOW_NULL_AUTHTOK)
return (PAM_AUTH_ERR);
/* return success if passwords are not required */
return (PAM_SUCCESS);
}
if (strcmp(crypt(password, enc_passwd),
enc_passwd) != 0) {
return (PAM_AUTH_ERR);
}
/* success! */
return (PAM_SUCCESS);
}
}

View File

@@ -0,0 +1,89 @@
/* $XConsortium: unix_chauthtok.c /main/5 1996/05/09 04:33:18 drk $ */
/*
* Copyright (c) 1992-1995, by Sun Microsystems, Inc.
* All rights reserved.
*/
#ident "@(#)unix_chauthtok.c 1.83 95/12/12 SMI"
#include "unix_headers.h"
/*
* pam_sm_chauthtok():
* To change authentication token.
*
* This function handles all requests from the "passwd" command
* to change a user's password in all repositories specified
* in nsswitch.conf.
*/
int
pam_sm_chauthtok(
pam_handle_t *pamh,
int flags,
int argc,
const char **argv)
{
int i;
int debug = 0; /* debug option from pam.conf */
int authtok_aged = 0; /* flag to check if password expired */
unix_authtok_data *status; /* status in pam handle stating if */
/* password aged */
/*
* Only check for debug here - parse remaining options
* in __update_authtok();
*/
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "debug") == 0)
debug = 1;
}
if (flags & PAM_PRELIM_CHECK) {
/* do not do any prelim check at this time */
if (debug)
syslog(LOG_DEBUG,
"unix pam_sm_chauthtok(): prelim check");
return (PAM_SUCCESS);
}
/* make sure PAM framework is telling us to update passwords */
if (!(flags & PAM_UPDATE_AUTHTOK)) {
syslog(LOG_ERR, "unix pam_sm_chauthtok: bad flags: %d", flags);
return (PAM_SYSTEM_ERR);
}
if (flags & PAM_CHANGE_EXPIRED_AUTHTOK) {
if (pam_get_data(pamh, UNIX_AUTHTOK_DATA, (void **)&status)
== PAM_SUCCESS) {
switch (status->age_status) {
case PAM_NEW_AUTHTOK_REQD:
if (debug)
syslog(LOG_DEBUG,
"pam_sm_chauthtok: UNIX password aged");
authtok_aged = 1;
break;
default:
/* UNIX authtok did not expire */
if (debug)
syslog(LOG_DEBUG,
"pam_sm_chauthtok: UNIX password young");
authtok_aged = 0;
break;
}
}
if (!authtok_aged)
return (PAM_IGNORE);
}
/*
* This function calls __update_authtok() to change passwords.
* By passing PAM_REP_DEFAULT, the repository will be determined
* by looking in nsswitch.conf.
*
* To obtain the domain name (passed as NULL), __update_authtok()
* will call: nis_local_directory();
*/
return (__update_authtok(pamh, flags, PAM_REP_DEFAULT, NULL,
argc, argv));
}

View File

@@ -0,0 +1,34 @@
/* $XConsortium: unix_close_session.c /main/5 1996/05/09 04:33:38 drk $ */
/*
* Copyright (c) 1992-1995, by Sun Microsystems, Inc.
* All rights reserved.
*/
#ident "@(#)unix_close_session.c 1.26 95/12/12 SMI"
#include "unix_headers.h"
/*
* pam_sm_close_session - Terminate a PAM authenticated session
*/
int
pam_sm_close_session(
pam_handle_t *pamh,
int flags,
int argc,
const char **argv)
{
int i;
int debug = 0;
for (i = 0; i < argc; i++) {
if (strcasecmp(argv[i], "debug") == 0)
debug = 1;
else
syslog(LOG_ERR, "illegal option %s", argv[i]);
}
return (PAM_SUCCESS);
}

View File

@@ -0,0 +1,352 @@
/* $XConsortium: unix_get_authtokattr.c /main/8 1996/11/21 20:00:50 drk $ */
/*
* Copyright (c) 1992-1995, by Sun Microsystems, Inc.
* All rights reserved.
*/
#ident "@(#)unix_get_authtokattr.c 1.59 96/01/07 SMI"
#include "unix_headers.h"
#define XOS_USE_NO_LOCKING
#define X_INCLUDE_TIME_H
#include <X11/Xos_r.h>
#ifdef PAM_NISPLUS
static void _np_nss_initf_shadow(nss_db_params_t *);
static void _np_setspent();
static void _np_endspent();
static struct spwd * _np_getspent_r(struct spwd *, char *, int);
static struct spwd * _np_getspent();
#endif
/*
* __get_authtoken_attr():
* To get authentication token attribute values.
*
* This function calls ck_perm() first to check the caller's
* permission. If the check succeeds, it will read the
* attribute/value pairs from the shadow password entry of
* the user specified by the authentication handle "pamh"
* and store them into a character array and return.
*/
/*
* XXX: We use our own version of the shadow passwd getent routine.
* See below for details. Compatible with version 2 of the name service
* switch. In the future, the name service switch implementation may
* change and these functions and the Makefile may have to
* be modified.
*/
int
__get_authtoken_attr(
pam_handle_t *pamh,
char ***ga_getattr,
int repository,
const char *domain,
int argc,
const char **argv)
{
register int k;
char value[PAM_MAX_ATTR_SIZE];
int retcode;
long lstchg;
char *usrname;
char *prognamep;
char **get_attributes;
struct passwd *pwd;
struct spwd *shpwd;
int found = 0;
struct spwd *psp;
struct tm *tmp;
int privileged = 0;
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
int debug = 0;
int nowarn = 0;
int i;
void *passwd_res;
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "debug") == 0)
debug = 1;
else if (strcmp(argv[i], "nowarn") == 0)
nowarn = 1;
else
syslog(LOG_ERR, "illegal UNIX module option %s",
argv[i]);
}
if (debug)
syslog(LOG_DEBUG,
"__get_authtoken_attr(): repository=%s",
repository_to_string(repository));
if ((retcode = pam_get_item(pamh, PAM_SERVICE, (void **)&prognamep))
!= PAM_SUCCESS ||
(retcode = pam_get_item(pamh, PAM_USER, (void **)&usrname))
!= PAM_SUCCESS)
return (retcode);
if ((get_attributes = (char **)
calloc(PAM_MAX_NUM_ATTR, sizeof (char *))) == NULL)
return (PAM_BUF_ERR);
/* repository must be specified in the command line. */
if (repository == PAM_REP_DEFAULT) {
sprintf(messages[0], PAM_MSG(pamh, 40,
"You must specify repository when displaying passwd attributes"));
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
return (PAM_AUTHTOK_ERR);
}
if (!IS_FILES(repository) && !IS_NIS(repository) &&
!IS_NISPLUS(repository)) {
sprintf(messages[0], PAM_MSG(pamh, 41,
"%s: System error: repository out of range"), prognamep);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1,
messages, NULL);
return (PAM_SYSTEM_ERR);
}
#ifdef PAM_NISPLUS
if (usrname == NULL || *usrname == NULL) {
/* print nis+ table */
/*
* Cat the table using our private _np_getspent()
*/
if (!IS_NISPLUS(repository)) {
sprintf(messages[0], PAM_MSG(pamh, 42,
"Unable to retrieve username."));
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
return (PAM_AUTHTOK_RECOVERY_ERR);
}
(void) _np_setspent();
while ((psp = _np_getspent()) != NULL) {
found++;
sprintf(value, "%s ", psp->sp_namp);
if (psp->sp_pwdp == NULL) {
sprintf(messages[0],
"%s NP ", value);
} else if ((int)strlen(psp->sp_pwdp) < NUMCP) {
sprintf(messages[0],
"%s LK ", value);
} else {
sprintf(messages[0],
"%s PS ", value);
}
if (psp->sp_max != -1) {
_Xgtimeparams gmtime_buf;
strcpy(value, messages[0]);
if (psp->sp_lstchg) {
lstchg = psp->sp_lstchg * DAY;
tmp = _XGmtime(&lstchg, gmtime_buf);
sprintf(messages[0],
"%s %.2d/%.2d/%.2d ",
value,
(tmp->tm_mon + 1),
tmp->tm_mday, tmp->tm_year);
} else
sprintf(messages[0],
"%s 00/00/00 ",
value);
strcpy(value, messages[0]);
if ((psp->sp_min >= 0) && (psp->sp_warn > 0)) {
sprintf(messages[0],
"%s %d %d %d ",
value,
psp->sp_min, psp->sp_max,
psp->sp_warn);
} else if (psp->sp_min >= 0) {
sprintf(messages[0],
"%s %d %d ", value,
psp->sp_min, psp->sp_max);
} else if (psp->sp_warn > 0) {
sprintf(messages[0],
"%s %d %d ", value,
psp->sp_max, psp->sp_warn);
} else {
sprintf(messages[0],
"%s %d ",
value, psp->sp_max);
}
}
(void) __pam_display_msg(pamh, PAM_TEXT_INFO,
1, messages, NULL);
}
(void) _np_endspent();
/*
* If password table does not have any entries or is missing,
* return fatal error.
*/
if (found == 0) {
sprintf(messages[0],
PAM_MSG(pamh, 43,
"%s: Unexpected failure. Password database unchanged."),
prognamep);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
return (PAM_SYSTEM_ERR);
}
return (PAM_SUCCESS);
}
#endif /* PAM_NISPLUS */
retcode = ck_perm(pamh, repository,
(char *)domain, &pwd, &shpwd, &privileged,
(void **)&passwd_res, getuid(), debug, nowarn);
if (retcode != 0) {
return (retcode);
}
k = 0;
/* get attribute "AUTHTOK_STATUS" */
if (shpwd->sp_pwdp == NULL)
(void) strcpy(value, "NP ");
else if ((int)strlen(shpwd->sp_pwdp) < NUMCP)
(void) strcpy(value, "LK ");
else
(void) strcpy(value, "PS ");
setup_attr(get_attributes, k++, "AUTHTOK_STATUS=", value);
if (shpwd->sp_max != -1) {
/* get attribute "AUTHTOK_LASTCHANGE" */
if (shpwd->sp_lstchg) {
lstchg = shpwd->sp_lstchg * DAY;
sprintf(value, "%d", lstchg);
} else {
sprintf(value, "%d", shpwd->sp_lstchg);
}
setup_attr(get_attributes, k++,
"AUTHTOK_LASTCHANGE=", value);
/* get attribute "AUTHTOK_MINAGE" */
/* "AUTHTOK_MAXAGE", and "AUTHTOK_WARNDATE" */
if ((shpwd->sp_min >= 0) && (shpwd->sp_warn > 0)) {
sprintf(value, "%d", shpwd->sp_min);
setup_attr(get_attributes, k++,
"AUTHTOK_MINAGE=", value);
sprintf(value, "%d", shpwd->sp_max);
setup_attr(get_attributes, k++,
"AUTHTOK_MAXAGE=", value);
sprintf(value, "%d", shpwd->sp_warn);
setup_attr(get_attributes, k++,
"AUTHTOK_WARNDATE=", value);
} else {
if (shpwd->sp_min >= 0) {
sprintf(value, "%d", shpwd->sp_min);
setup_attr(get_attributes, k++,
"AUTHTOK_MINAGE=", value);
sprintf(value, "%d", shpwd->sp_max);
setup_attr(get_attributes, k++,
"AUTHTOK_MAXAGE=", value);
} else {
if (shpwd->sp_warn > 0) {
sprintf(value, "%d", shpwd->sp_max);
setup_attr(get_attributes, k++,
"AUTHTOK_MAXAGE=", value);
sprintf(value, "%d", shpwd->sp_warn);
setup_attr(get_attributes, k++,
"AUTHTOK_WARNDATE=", value);
} else {
sprintf(value, "%d", shpwd->sp_max);
setup_attr(get_attributes, k++,
"AUTHTOK_MAXAGE=", value);
}
}
}
}
/* terminate with NULL */
setup_attr(get_attributes, k, NULL, NULL);
*ga_getattr = &get_attributes[0];
free_passwd_structs(pwd, shpwd);
return (PAM_SUCCESS);
}
#ifdef PAM_NISPLUS
/*
* XXX Our private version of the switch frontend for getspent. We want to
* search just the nisplus sp file, so we want to bypass normal nsswitch.conf
* based processing. This implementation compatible with version 2 of the
* name service switch.
*/
#define NSS_NISPLUS_ONLY "nisplus"
int str2spwd(const char *, int, void *, char *, int);
static DEFINE_NSS_DB_ROOT(db_root);
static DEFINE_NSS_GETENT(context);
static void
_np_nss_initf_shadow(p)
nss_db_params_t *p;
{
p->name = NSS_DBNAM_SHADOW;
p->config_name = NSS_DBNAM_PASSWD; /* Use config for "passwd" */
p->default_config = NSS_NISPLUS_ONLY; /* Use nisplus only */
p->flags = NSS_USE_DEFAULT_CONFIG;
}
static void
_np_setspent()
{
nss_setent(&db_root, _np_nss_initf_shadow, &context);
}
static void
_np_endspent()
{
nss_endent(&db_root, _np_nss_initf_shadow, &context);
nss_delete(&db_root);
}
static struct spwd *
_np_getspent_r(result, buffer, buflen)
struct spwd *result;
char *buffer;
int buflen;
{
nss_XbyY_args_t arg;
char *nam;
/* In getXXent_r(), protect the unsuspecting caller from +/- entries */
do {
NSS_XbyY_INIT(&arg, result, buffer, buflen, str2spwd);
/* No key to fill in */
nss_getent(&db_root, _np_nss_initf_shadow, &context, &arg);
} while (arg.returnval != 0 &&
(nam = ((struct spwd *)arg.returnval)->sp_namp) != 0 &&
(*nam == '+' || *nam == '-'));
return (struct spwd *) NSS_XbyY_FINI(&arg);
}
static nss_XbyY_buf_t *buffer;
static struct spwd *
_np_getspent()
{
nss_XbyY_buf_t *b;
b = NSS_XbyY_ALLOC(&buffer, sizeof (struct spwd), NSS_BUFLEN_SHADOW);
return (b == 0 ? 0 : _np_getspent_r(b->result, b->buffer, b->buflen));
}
#endif /* PAM_NISPLUS */

View File

@@ -0,0 +1,206 @@
/* $XConsortium: unix_headers.h /main/5 1996/05/09 04:34:13 drk $ */
/*
* Copyright (c) 1992-1995, by Sun Microsystems, Inc.
* All rights reserved.
*/
#ifndef _UNIX_HEADERS_H
#define _UNIX_HEADERS_H
#pragma ident "@(#)unix_headers.h 1.61 96/02/02 SMI" /* PAM 2.6 */
#ifdef __cplusplus
extern "C" {
#endif
/*
*******************************************************************
*
* PROPRIETARY NOTICE(Combined)
*
* This source code is unpublished proprietary information
* constituting, or derived under license from AT&T's UNIX(r) System V.
* In addition, portions of such source code were derived from Berkeley
* 4.3 BSD under license from the Regents of the University of
* California.
*
*
*
* Copyright Notice
*
* Notice of copyright on this source code product does not indicate
* publication.
*
* (c) 1986, 1987, 1988, 1989, 1990, 1991, 1992 Sun Microsystems, Inc
* (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T.
* All rights reserved.
*******************************************************************
*/
/*
********************************************************************** *
* *
* Unix Scheme Header Files *
* *
********************************************************************** */
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include "../../libpam/pam_impl.h"
#include <syslog.h>
#include <pwd.h>
#include <shadow.h>
#include <lastlog.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <libintl.h>
#include <thread.h>
#include <synch.h>
#include <errno.h>
#include <time.h>
#include <sys/fcntl.h>
#include <string.h>
#include <crypt.h>
#ifdef PAM_NISPLUS
#include <rpcsvc/nis.h>
#include <rpcsvc/nispasswd.h>
#endif
#if (PAM_NIS || PAM_NISPLUS)
#include <rpcsvc/yppasswd.h>
#include <rpcsvc/ypclnt.h>
#include <nss_dbdefs.h>
#include <nsswitch.h>
#include <rpc/key_prot.h>
#include <rpc/rpc.h>
#include <nfs/nfs.h>
#include <nfs/nfssys.h>
#endif
/*
* Various useful files and string constants
*/
#define SHELL "/usr/bin/sh"
#define DEFSHELL "/bin/sh"
#define LASTLOG "/var/adm/lastlog"
#define PWADMIN "/etc/default/passwd"
#define LOGINADMIN "/etc/default/login"
#define PASSWD "/etc/passwd"
#define SHADOW "/etc/shadow"
#define UNIX_AUTH_DATA "SUNW-UNIX-AUTH-DATA"
#define UNIX_AUTHTOK_DATA "SUNW-UNIX-AUTHTOK-DATA"
#define UNIX_MSG "(Unix)"
#define NIS_MSG "(NIS)"
#define NISPLUS_MSG "(NIS+)"
#define PASSWORD_LEN 8
#define PAM_NISPLUS_PARTIAL_SUCCESS -1
/*
* PAM_MSG macro for return of internationalized text
*/
#define PAM_MSG(pamh, number, string)\
(char *) __pam_get_i18n_msg(pamh, "pam_unix", 1, number, string)
/*
* Returned status codes for establish_key () utility function
*/
#define ESTKEY_SUCCESS 0
#define ESTKEY_NOCREDENTIALS 1
#define ESTKEY_BADPASSWD 2
#define ESTKEY_CANTSETKEY 3
#define ESTKEY_ALREADY 4
/*
* Miscellaneous constants
*/
#define ROOTUID 0
#define MINWEEKS -1 /* minimum weeks before next password change */
#define MAXWEEKS -1 /* maximum weeks before password change */
#define WARNWEEKS -1 /* number weeks before password expires */
/* to warn the user */
#define MINLENGTH 6 /* minimum length for passwords */
#define MAXLENGTH 8 /* maximum length for passwords */
#define NUMCP 13 /* number of characters for valid password */
#define MAX_CHANCES 3 /* 3 chances to enter new passwd */
/*
* variables declarations
*/
mutex_t _priv_lock;
/*
* nis+ definition
*/
#define PKTABLE "cred.org_dir"
#define PKTABLELEN 12
#define PASSTABLE "passwd.org_dir"
#define PASSTABLELEN 14
#define PKMAP "publickey.byname"
/* define error messages */
#define NULLSTRING ""
/*
* Function Declarations
*/
extern int defopen();
extern char *defread();
extern int key_setnet();
/* from unix_utils.c */
extern int ck_perm(pam_handle_t *, int,
char *, struct passwd **, struct spwd **,
int *, void **, uid_t, int, int);
extern char *attr_match(register char *, register char *);
extern char *getloginshell(pam_handle_t *, char *, int, int);
extern char *gethomedir(pam_handle_t *, char *, int);
extern char *getfingerinfo(pam_handle_t *, char *, int);
extern char *repository_to_string(int);
extern void free_passwd_structs(struct passwd *, struct spwd *);
/* from switch_utils.c */
extern int str2spwd(const char *, int, void *, char *, int);
extern struct passwd *getpwnam_from(const char *, int);
extern struct spwd *getspnam_from(const char *, int);
extern int get_ns(pam_handle_t *, int, int, int);
/* from update_authtok_<repository> */
extern int update_authtok_file(pam_handle_t *, char *, char **,
struct passwd *, int, int);
#ifdef PAM_NIS
extern int update_authtok_nis(pam_handle_t *, char *, char **,
char *, char *,
struct passwd *, int, int);
#endif
#ifdef PAM_NISPLUS
extern int update_authtok_nisplus(pam_handle_t *, char *, char *,
char **, char *, char *,
char *, int, struct passwd *, char *,
int, nis_result *, nis_result *, int, int);
#endif
#ifdef PAM_SECURE_RPC
extern int establish_key(uid_t, char *, int, char *);
typedef struct _unix_auth_data_ {
int key_status;
char netname[MAXNETNAMELEN+1];
}unix_auth_data;
#endif
typedef struct _unix_authtok_data_ {
int age_status;
}unix_authtok_data;
#ifdef __cplusplus
}
#endif
#endif /* _UNIX_HEADERS_H */

View File

@@ -0,0 +1,82 @@
/* $XConsortium: unix_open_session.c /main/5 1996/05/09 04:34:32 drk $ */
/*
* Copyright (c) 1992-1995, by Sun Microsystems, Inc.
* All rights reserved.
*/
#ident "@(#)unix_open_session.c 1.32 95/12/08 SMI"
/*
* pam_sm_open_session - session management for individual users
*/
#include "unix_headers.h"
int
pam_sm_open_session(
pam_handle_t *pamh,
int flags,
int argc,
const char **argv)
{
int error;
char *ttyn, *rhost, *user;
int fdl;
struct lastlog newll;
struct passwd pwd;
char buffer[2048];
int i;
int debug = 0;
long long offset;
for (i = 0; i < argc; i++) {
if (strcasecmp(argv[i], "debug") == 0)
debug = 1;
else
syslog(LOG_ERR, "illegal option %s", argv[i]);
}
if ((error = pam_get_item(pamh, PAM_TTY, (void **)&ttyn))
!= PAM_SUCCESS ||
(error = pam_get_item(pamh, PAM_USER, (void **)&user))
!= PAM_SUCCESS ||
(error = pam_get_item(pamh, PAM_RHOST, (void **)&rhost))
!= PAM_SUCCESS) {
return (error);
}
if (getpwnam_r(user, &pwd, buffer, sizeof (buffer)) == NULL) {
return (PAM_USER_UNKNOWN);
}
if ((fdl = open(LASTLOG, O_RDWR|O_CREAT, 0444)) >= 0) {
/*
* The value of lastlog is read by the UNIX
* account management module
*/
offset = (long long) pwd.pw_uid *
(long long) sizeof (struct lastlog);
if (llseek(fdl, offset, SEEK_SET) != offset) {
/*
* XXX uid too large for database
*/
return (PAM_SUCCESS);
}
(void) time(&newll.ll_time);
strncpy(newll.ll_line,
(ttyn + sizeof ("/dev/")-1),
sizeof (newll.ll_line));
strncpy(newll.ll_host, rhost, sizeof (newll.ll_host));
(void) write(fdl, (char *)&newll, sizeof (newll));
(void) close(fdl);
}
return (PAM_SUCCESS);
}

View File

@@ -0,0 +1,112 @@
/* $XConsortium: unix_set_authtokattr.c /main/5 1996/05/09 04:34:50 drk $ */
/*
* Copyright (c) 1992-1995, by Sun Microsystems, Inc.
* All rights reserved.
*/
#ident "@(#)__set_authtoken_attr.c 1.33 95/09/11 SMI"
#include "unix_headers.h"
/*
* __set_authtoken_attr():
* To set authentication token attribute values.
*
* This function calls ck_perm() to check the caller's
* permission. If the check succeeds, It will
* call update_authentok_file() and passes attributes/value
* pairs pointed by "sa_setattr" to set the authentication
* token attribute values of the user specified by the
* authentication handle "pamh".
*/
int
__set_authtoken_attr(
pam_handle_t *pamh,
const char **sa_setattr,
int repository,
const char *domain,
int argc,
const char **argv)
{
register int i;
int retcode;
char *usrname;
char *prognamep;
struct passwd *pwd = NULL;
struct spwd *shpwd = NULL;
int privileged = 0;
int debug = 0;
int nowarn = 0;
void *passwd_res;
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "debug") == 0)
debug = 1;
else if (strcmp(argv[i], "nowarn") == 0)
nowarn = 1;
else
syslog(LOG_ERR, "illegal UNIX module option %s",
argv[i]);
}
if ((retcode = pam_get_item(pamh, PAM_SERVICE, (void **)&prognamep))
!= PAM_SUCCESS ||
(retcode = pam_get_item(pamh, PAM_USER, (void **)&usrname))
!= PAM_SUCCESS)
return (retcode);
if (debug)
syslog(LOG_DEBUG,
"__set_authtoken_attr(): repository %x, usrname %s",
repository, usrname);
retcode = ck_perm(pamh, repository,
(char *)domain, &pwd, &shpwd, &privileged,
(void **)&passwd_res, getuid(), debug, nowarn);
if (retcode != 0) {
return (retcode);
}
/*
* XXX: why do this???
* ignore all the signals
*/
for (i = 1; i < NSIG; i++)
(void) sigset(i, SIG_IGN);
/* update authentication token file */
/* make sure the user exists before we update the repository */
#ifdef PAM_NIS
if (IS_NIS(repository) && (pwd != NULL)) {
retcode = update_authtok_nis(pamh, "attr",
(char **)sa_setattr, NULL, NULL, pwd,
privileged, nowarn);
free_passwd_structs(pwd, shpwd);
return (retcode);
} else
#endif
#ifdef PAM_NISPLUS
if (IS_NISPLUS(repository) && (pwd != NULL)) {
/* nis+ needs clear versions of old and new passwds */
retcode = update_authtok_nisplus(pamh,
(char *)domain, "attr", (char **)sa_setattr,
NULL, NULL, NULL, IS_OPWCMD(repository) ? 1 : 0, pwd,
NULL, privileged, (nis_result *)passwd_res, NULL,
debug, nowarn);
free_passwd_structs(pwd, shpwd);
return (retcode);
} else
#endif
if (IS_FILES(repository) && (pwd != NULL)) {
retcode = update_authtok_file(pamh, "attr",
(char **)sa_setattr, pwd,
privileged, nowarn);
free_passwd_structs(pwd, shpwd);
return (retcode);
}
return (PAM_SUCCESS);
}

View File

@@ -0,0 +1,172 @@
/* $XConsortium: unix_setcred.c /main/5 1996/05/09 04:35:09 drk $ */
/*
* Copyright (c) 1992-1995, by Sun Microsystems, Inc.
* All rights reserved.
*/
#ident "@(#)unix_setcred.c 1.51 95/12/12 SMI"
#include "unix_headers.h"
/*
* pam_sm_setcred - Set the process credentials
*
* XXX: If this module succeeds when invoked with PAM_ESTABLISH_CREd,
* and a subsequent module in the stack fails, then there is no way
* to delete the user's Secure RPC credentials (keylogout). Currently
* there is no way for PAM to correct this problem.
*/
int
pam_sm_setcred(
pam_handle_t *pamh,
int flags,
int argc,
const char **argv)
{
int i;
int debug = 0;
int err = 0;
struct pam_conv *pam_convp;
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
#ifdef PAM_SECURE_RPC
unix_auth_data *status;
char secret[HEXKEYBYTES + 1];
struct nfs_revauth_args nra; /* revoking kernel NFS creds */
#endif
for (i = 0; i < argc; i++) {
if (strcasecmp(argv[i], "debug") == 0)
debug = 1;
else if (strcasecmp(argv[i], "nowarn") == 0)
flags = flags | PAM_SILENT;
}
/* make sure flags are valid */
if (flags &&
!(flags & PAM_ESTABLISH_CRED) &&
!(flags & PAM_REINITIALIZE_CRED) &&
!(flags & PAM_REFRESH_CRED) &&
!(flags & PAM_DELETE_CRED) &&
!(flags & PAM_SILENT)) {
syslog(LOG_ERR, "unix setcred: illegal flag %d", flags);
err = PAM_SYSTEM_ERR;
goto out;
}
if (pam_get_item(pamh, PAM_CONV, (void **) &pam_convp) !=
PAM_SUCCESS) {
if (debug) {
syslog(LOG_DEBUG,
"pam_sm_setcred(): unable to get conv structure");
}
err = PAM_SERVICE_ERR;
goto out;
}
if ((flags & PAM_REINITIALIZE_CRED) ||
(flags & PAM_REFRESH_CRED)) {
/* For unix, these flags are not applicable */
err = PAM_SUCCESS;
} else if (flags & PAM_DELETE_CRED) {
#ifdef PAM_SECURE_RPC
/* do a keylogout */
memset(secret, 0, sizeof (secret));
if (geteuid() == 0) {
if (!(flags & PAM_SILENT)) {
sprintf(messages[0], PAM_MSG(pamh, 50,
"removing root credentials would break the rpc services that"));
sprintf(messages[1], PAM_MSG(pamh, 51,
"use secure rpc on this host!"));
sprintf(messages[2], PAM_MSG(pamh, 52,
"root may use keylogout -f to do this (at your own risk)!"));
__pam_display_msg(pamh, PAM_ERROR_MSG,
3, messages, NULL);
}
err = PAM_PERM_DENIED;
goto out;
}
if (key_setsecret(secret) < 0) {
if (!(flags & PAM_SILENT)) {
sprintf(messages[0], PAM_MSG(pamh, 53,
"Could not unset your secret key."));
sprintf(messages[1], PAM_MSG(pamh, 54,
"Maybe the keyserver is down?"));
__pam_display_msg(pamh, PAM_ERROR_MSG,
2, messages, NULL);
}
err = PAM_AUTH_ERR;
goto out;
}
nra.authtype = AUTH_DES; /* only revoke DES creds */
nra.uid = getuid(); /* use the real uid */
if (_nfssys(NFS_REVAUTH, &nra) < 0) {
if (!(flags & PAM_SILENT)) {
sprintf(messages[0], PAM_MSG(pamh, 55,
"Warning: NFS credentials not destroyed"));
__pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
err = PAM_AUTH_ERR;
goto out;
}
#endif
err = PAM_SUCCESS;
} else {
#ifdef PAM_SECURE_RPC
/*
* Default case: PAM_ESTABLISH_CRED
* For unix, the keylogin was already done in
* unix_authenticate.c. Only print out the
* keylogin status here.
*/
if (!(flags & PAM_SILENT)) {
if (pam_get_data(pamh, UNIX_AUTH_DATA,
(void**)&status) == PAM_SUCCESS) {
switch (status->key_status) {
case ESTKEY_SUCCESS:
if (debug)
syslog(LOG_DEBUG,
"unix setcred successful");
case ESTKEY_ALREADY:
case ESTKEY_NOCREDENTIALS:
break;
case ESTKEY_BADPASSWD:
if (!(flags & PAM_SILENT)) {
sprintf(messages[0],
PAM_MSG(pamh, 56,
"Password does not decrypt secret key for %s."),
status->netname);
__pam_display_msg(
pamh,
PAM_ERROR_MSG, 1,
messages, NULL);
}
break;
case ESTKEY_CANTSETKEY:
if (!(flags & PAM_SILENT)) {
sprintf(messages[0],
PAM_MSG(pamh, 57,
"Could not set secret key for %s. The key server may be down."),
status->netname);
__pam_display_msg(
pamh,
PAM_ERROR_MSG, 1,
messages, NULL);
}
break;
}
} else {
if (debug)
syslog(LOG_DEBUG,
"pam_sm_setcred(): no module data");
}
}
#endif
err = PAM_SUCCESS;
}
out:
return (err);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,637 @@
/* $XConsortium: unix_update_authtok_file.c /main/5 1996/05/09 04:35:55 drk $ */
/*
* Copyright (c) 1992-1995, by Sun Microsystems, Inc.
* All rights reserved.
*/
#ident "@(#)unix_update_authtok_file.c 1.26 95/09/11 SMI"
#include "unix_headers.h"
static int update_spent(pam_handle_t *, char *, char **,
struct passwd *, struct spwd *, int *, int, int);
static int process_passwd(pam_handle_t *, char *, char *,
struct passwd *, int);
/*
* update_authtok_file():
* To update the authentication token file.
*
* This function is called by either __set_authtoken_attr() to
* update the token attributes or pam_chauthtok() to update the
* authentication token. The parameter "field" has to be specified
* as "attr" if the caller wants to update token attributes, and
* the attribute-value pairs to be set needs to be passed in by parameter
* "data". If the function is called to update authentication
* token itself, then "field" needs to be specified as "passwd"
* and the new authentication token has to be passed in by "data".
*/
int
update_authtok_file(pamh, field, data, unix_pwd, privileged, nowarn)
pam_handle_t *pamh;
char *field;
char *data[];
struct passwd *unix_pwd;
int privileged;
int nowarn;
{
char *prognamep;
char *usrname;
struct stat buf;
register int found = 0;
FILE *tsfp, *spfp;
struct spwd unix_sp;
char spbuf[1024];
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
int passwd_flag = 0; /* attrs in shadow or passwd file */
int retcode;
if ((retcode = pam_get_item(pamh, PAM_SERVICE, (void **)&prognamep))
!= PAM_SUCCESS ||
(retcode = pam_get_item(pamh, PAM_USER, (void **)&usrname))
!= PAM_SUCCESS)
return (retcode);
/*
* XXX:
* Assume effective UID already set to 0
* so we can update the passwd file.
*
* This will be the last update (after nis/nis+)
*/
errno = 0;
/* lock the password file */
if (lckpwdf() != 0) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 90,
"%s%s: Password database busy. Try again later."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
return (PAM_AUTHTOK_LOCK_BUSY);
}
/* Mode of the shadow file should be 400 or 000 */
if (stat(SHADOW, &buf) < 0) {
syslog(LOG_ERR, "%s: stat of shadow file failed",
prognamep);
(void) ulckpwdf();
return (PAM_AUTHTOK_ERR);
}
(void) umask(S_IAMB & ~(buf.st_mode & S_IRUSR));
if ((tsfp = fopen(SHADTEMP, "w")) == NULL) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
(void) ulckpwdf();
return (PAM_AUTHTOK_ERR);
}
/*
* copy passwd files to temps, replacing matching lines
* with new password attributes.
*/
if ((spfp = fopen(SHADOW, "r")) == NULL) {
fclose(tsfp);
goto err;
}
while (fgetspent_r(spfp, &unix_sp, spbuf, sizeof (spbuf)) != NULL) {
if (strcmp(unix_sp.sp_namp, usrname) == 0) {
found = 1;
retcode = update_spent(pamh, field, data,
unix_pwd, &unix_sp, &passwd_flag,
privileged, nowarn);
if (retcode != PAM_SUCCESS) {
fclose(tsfp);
fclose(spfp);
goto err;
}
if (passwd_flag) {
/* The attributes are in passwd file */
if ((retcode = process_passwd(pamh,
prognamep, usrname, unix_pwd,
nowarn)) != PAM_SUCCESS) {
fclose(tsfp);
fclose(spfp);
goto err;
}
}
}
if (putspent(&unix_sp, tsfp) != 0) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
fclose(tsfp);
fclose(spfp);
goto err;
}
memset(spbuf, 0, sizeof (spbuf));
} /* end of while */
if ((fclose(tsfp)) || (fclose(spfp))) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
goto err;
}
/* Check if user name exists */
if (found == 0) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
goto err;
}
/*
* Rename temp file back to appropriate passwd file.
*/
/* remove old shadow file */
if (unlink(OSHADOW) && access(OSHADOW, 0) == 0) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
goto err;
}
/* rename shadow file to old shadow file */
if (rename(SHADOW, OSHADOW) == -1) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
goto err;
}
/* rename temparory shadow file to shadow file */
if (rename(SHADTEMP, SHADOW) == -1) {
(void) unlink(SHADOW);
if (link(OSHADOW, SHADOW)) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 92,
"%s%s: Unexpected failure. Password database missing."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
goto err;
}
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
goto err;
}
(void) ulckpwdf();
memset(spbuf, 0, sizeof (spbuf));
if (strcmp(field, "passwd") == 0) {
sprintf(messages[0], PAM_MSG(pamh, 93,
"%s%s: passwd successfully changed for %s"),
prognamep, UNIX_MSG, usrname);
(void) __pam_display_msg(pamh, PAM_TEXT_INFO,
1, messages, NULL);
}
return (PAM_SUCCESS);
err:
unlink(SHADTEMP);
(void) ulckpwdf();
memset(spbuf, 0, sizeof (spbuf));
return (PAM_AUTHTOK_ERR);
}
/*
* update_spent():
* To update a shadow password file entry in the Unix
* authentication token file.
* This function is called by update_authtok_file() to
* update the token to token attributes.
* The parameter "field" indicates whenther token attributes or
* token itself will be changes, and the parameter "data" has
* the new values for the attributes or token.
*
*/
static int
update_spent(pamh, field, data, unix_pwd, unix_sp,
passwd_flag, privileged, nowarn)
pam_handle_t *pamh;
char *field;
char **data;
struct passwd *unix_pwd;
struct spwd *unix_sp;
int *passwd_flag;
int privileged;
int nowarn;
{
char *value;
char *char_p;
char *tmp_pwd_entry;
char **data_p = data;
int mindate;
int maxdate;
int warndate;
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
static char *lkstring = "*LK*"; /* lock string to lock */
/* user's password */
if (strcmp(field, "attr") == 0) {
while (*data != NULL) {
/* check attribute: AUTHTOK_DEL */
if ((value =
attr_match("AUTHTOK_DEL", *data))
!= NULL) {
if (strcmp(value, "1") == 0) {
/* delete password */
if (unix_sp->sp_pwdp)
memset(unix_sp->sp_pwdp, 0,
strlen(unix_sp->sp_pwdp));
/*
* set "AUTHTOK_EXT" will clear
* the sp_lstchg field. We do not
* want sp_lstchg field to be set
* if one execute passwd -d -f
* name or passwd -l -f name.
*/
if (attr_find("AUTHTOK_EXP",
data_p) == 0)
unix_sp->sp_lstchg = DAY_NOW;
}
data++;
continue;
}
/* check attribute: AUTHTOK_LK */
if ((value = attr_match("AUTHTOK_LK", *data))
!= NULL) {
if (strcmp(value, "1") == 0) {
memset(unix_sp->sp_pwdp, 0,
strlen(unix_sp->sp_pwdp));
/* lock password */
unix_sp->sp_pwdp = lkstring;
if (attr_find("AUTHTOK_EXP",
data_p) == 0)
unix_sp->sp_lstchg = DAY_NOW;
}
data++;
continue;
}
/* check attribute: AUTHTOK_EXP */
if ((value = attr_match("AUTHTOK_EXP", *data))
!= NULL) {
if (strcmp(value, "1") == 0) {
/* expire password */
unix_sp->sp_lstchg = (long) 0;
}
data++;
continue;
}
/* check attribute: AUTHTOK_MAXAGE */
if ((value = attr_match("AUTHTOK_MAXAGE", *data))
!= NULL) {
/* set max field */
maxdate = (int)strtol(value, &char_p, 10);
if ((attr_find("AUTHTOK_MINAGE", data_p) ==
0) && unix_sp->sp_min == -1)
unix_sp->sp_min = 0;
if (maxdate == -1) { /* turn off aging */
unix_sp->sp_min = -1;
unix_sp->sp_warn = -1;
} else if (unix_sp->sp_max == -1)
/*
* It was set to 0 before. That
* will force passwd change at the
* next login. There are several
* ways to force passwd change. I don't
* think turning on aging should imply
* that.
*/
unix_sp->sp_lstchg = DAY_NOW;
unix_sp->sp_max = maxdate;
data++;
continue;
}
/* check attribute: AUTHTOK_MINAGE */
if ((value = attr_match("AUTHTOK_MINAGE", *data))
!= NULL) {
/* set min field */
mindate = (int)strtol(value, &char_p, 10);
if ((attr_find("AUTHTOK_MAXAGE", data_p) ==
0) &&
unix_sp->sp_max == -1 && mindate != -1) {
return (PAM_AUTHTOK_DISABLE_AGING);
}
unix_sp->sp_min = mindate;
data++;
continue;
}
/* check attribute: AUTHTOK_WARNDATE */
if ((value =
attr_match
("AUTHTOK_WARNDATE", *data)) != NULL) {
/* set warn field */
warndate = (int)strtol(value, &char_p, 10);
if (unix_sp->sp_max == -1 && warndate != -1) {
return (PAM_AUTHTOK_DISABLE_AGING);
}
unix_sp->sp_warn = warndate;
data++;
continue;
}
/* new shell */
if ((value = attr_match("AUTHTOK_SHELL", *data))
!= NULL) {
if (unix_pwd == NULL) {
if (!nowarn) {
sprintf(messages[0],
PAM_MSG(pamh, 94,
"%s: No local passwd record"),
UNIX_MSG);
(void) __pam_display_msg(
pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
return (PAM_AUTHTOK_RECOVERY_ERR);
}
tmp_pwd_entry = unix_pwd->pw_shell;
unix_pwd->pw_shell =
getloginshell(pamh, unix_pwd->pw_shell,
privileged, nowarn);
if (tmp_pwd_entry)
free(tmp_pwd_entry);
/* if NULL, shell unchanged */
if (unix_pwd->pw_shell == NULL)
return (PAM_SUCCESS);
*passwd_flag = 1;
data++;
continue;
}
/* new homedir */
if ((value = attr_match("AUTHTOK_HOMEDIR", *data))
!= NULL) {
if (unix_pwd == NULL) {
if (!nowarn) {
sprintf(messages[0],
PAM_MSG(pamh, 94,
"%s: No local passwd record"),
UNIX_MSG);
(void) __pam_display_msg(
pamh, PAM_ERROR_MSG, 1,
messages, NULL);
}
return (PAM_AUTHTOK_RECOVERY_ERR);
}
tmp_pwd_entry = unix_pwd->pw_dir;
unix_pwd->pw_dir =
gethomedir(pamh, unix_pwd->pw_dir,
nowarn);
if (tmp_pwd_entry)
free(tmp_pwd_entry);
/* if NULL, homedir unchanged */
if (unix_pwd->pw_dir == NULL)
return (PAM_SUCCESS);
*passwd_flag = 1;
data++;
continue;
}
/* new gecos */
if ((value = attr_match("AUTHTOK_GECOS", *data))
!= NULL) {
if (unix_pwd == NULL) {
if (!nowarn) {
sprintf(messages[0],
PAM_MSG(pamh, 94,
"%s: No local passwd record"),
UNIX_MSG);
(void) __pam_display_msg(
pamh, PAM_ERROR_MSG, 1,
messages, NULL);
}
return (PAM_AUTHTOK_RECOVERY_ERR);
}
tmp_pwd_entry = unix_pwd->pw_gecos;
unix_pwd->pw_gecos =
getfingerinfo(pamh, unix_pwd->pw_gecos,
nowarn);
if (tmp_pwd_entry)
free(tmp_pwd_entry);
/* if NULL, gecos unchanged */
if (unix_pwd->pw_gecos == NULL)
return (PAM_SUCCESS);
*passwd_flag = 1;
data++;
continue;
}
}
} else {
if (strcmp(field, "passwd") == 0) { /* change password */
unix_sp->sp_pwdp = *data_p;
/* update the last change field */
unix_sp->sp_lstchg = DAY_NOW;
if (unix_sp->sp_max == 0) { /* turn off aging */
unix_sp->sp_max = -1;
unix_sp->sp_min = -1;
}
}
}
return (PAM_SUCCESS);
}
/*
* shell, homedir and gecos are in passwd file. The update is modeled
* after shadow file.
*/
static int
process_passwd(pamh, prognamep, usrname, unix_pwd, nowarn)
pam_handle_t *pamh;
char *prognamep;
char *usrname;
struct passwd *unix_pwd;
int nowarn;
{
FILE *tpfp; /* tmp passwd file pointer */
FILE *pwfp; /* passwd file pointer */
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
struct passwd *unix_p;
struct passwd unix_tmp;
int found;
char buf[4 * BUFSIZ];
struct stat stat_buf;
if (stat(PASSWD, &stat_buf) < 0) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
return (PAM_AUTHTOK_ERR);
}
(void) umask(S_IAMB & ~(stat_buf.st_mode & S_IRUSR));
if ((tpfp = fopen(PASSTEMP, "w")) == NULL) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
return (PAM_AUTHTOK_ERR);
}
if ((pwfp = fopen(PASSWD, "r")) == NULL) {
fclose(tpfp);
goto err;
}
while ((unix_p = fgetpwent_r(pwfp, &unix_tmp, buf, 4*BUFSIZ)) != NULL) {
if (strcmp(unix_p->pw_name, usrname) == 0) {
found = 1;
unix_p->pw_gecos = unix_pwd->pw_gecos;
unix_p->pw_dir = unix_pwd->pw_dir;
unix_p->pw_shell = unix_pwd->pw_shell;
}
if (putpwent(unix_p, tpfp) != 0) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
fclose(tpfp);
fclose(pwfp);
goto err;
}
memset(buf, 0, 4 * BUFSIZ);
} /* end of while */
if ((fclose(tpfp)) || (fclose(pwfp))) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
goto err;
}
/* Check if user name exists */
if (found == 0) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
goto err;
}
/*
* Rename temp file back to appropriate passwd file.
*/
/* remove old passwd file */
if (unlink(OPASSWD) && access(OPASSWD, 0) == 0) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: %s"),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
goto err;
}
/* rename password file to old password file */
if (rename(PASSWD, OPASSWD) == -1) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
goto err;
}
/* rename temporary password file to password file */
if (rename(PASSTEMP, PASSWD) == -1) {
(void) unlink(PASSWD);
if (link(OPASSWD, PASSWD)) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
goto err;
}
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 91,
"%s%s: Unexpected failure. Password database unchanged."),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
goto err;
}
(void) chmod(PASSWD, 0644);
return (PAM_SUCCESS);
err:
(void) unlink(PASSTEMP);
return (PAM_AUTHTOK_ERR);
}

View File

@@ -0,0 +1,326 @@
/* $XConsortium: unix_update_authtok_nis.c /main/5 1996/05/09 04:36:14 drk $ */
/*
* Copyright (c) 1992-1996, by Sun Microsystems, Inc.
* All rights reserved.
*/
#ident "@(#)unix_update_authtok_nis.c 1.43 96/02/02 SMI"
#include "unix_headers.h"
#ifdef PAM_NIS
static void reencrypt_secret(pam_handle_t *, char *, char *, char *,
int);
static int update_nisattr(pam_handle_t *, char *, char **,
struct passwd *, int, int);
int
update_authtok_nis(
pam_handle_t *pamh,
char *field,
char *data[], /* encrypted new passwd */
/* or new attribute info */
char *old, /* old passwd: clear */
char *new, /* new passwd: clear */
struct passwd *nis_pwd, /* password structure */
int privileged,
int nowarn) /* no compat mode: npd and yp server */
/* take the same protocol */
{
int ok;
enum clnt_stat ans;
char *domain;
char *master;
CLIENT *client;
struct timeval timeout;
char *prognamep;
char *usrname;
int retcode = PAM_SYSTEM_ERR;
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
struct yppasswd yppasswd;
/* initialize this */
yppasswd.oldpass = NULL;
if ((retcode = pam_get_item(pamh, PAM_SERVICE, (void **)&prognamep))
!= PAM_SUCCESS ||
(retcode = pam_get_item(pamh, PAM_USER, (void **)&usrname))
!= PAM_SUCCESS)
goto out;
if (strcmp(field, "passwd") == 0) {
/*
* ck_passwd() already checked the old passwd. It won't get here
* if the old passwd is not matched.
* We are just preparing the passwd update packet here.
*/
if ((yppasswd.oldpass = strdup(old)) == NULL) {
retcode = PAM_BUF_ERR;
goto out;
}
if (nis_pwd->pw_passwd) {
memset(nis_pwd->pw_passwd, 0,
strlen(nis_pwd->pw_passwd));
free(nis_pwd->pw_passwd);
}
nis_pwd->pw_passwd = *data; /* encrypted new passwd */
} else {
/*
* prompt for passwd: required for the options
* nis_pwd struct will be modified by update_nisattr().
* The encrypted passwd remains the same because we are not
* changing passwd here.
*/
retcode = __pam_get_authtok(pamh, PAM_PROMPT, 0, PASSWORD_LEN,
PAM_MSG(pamh, 62, "Enter login(NIS) password: "),
&(yppasswd.oldpass));
if (retcode != PAM_SUCCESS)
goto out;
if ((retcode = update_nisattr(pamh, field, data,
nis_pwd, privileged, nowarn)) != PAM_SUCCESS) {
if (retcode == -1) {
/* finger, shell, or gecos info unchanged */
retcode = PAM_SUCCESS;
}
goto out;
}
}
yppasswd.newpw = *nis_pwd;
if (yp_get_default_domain(&domain) != 0) {
syslog(LOG_ERR, "%s%s: can't get domain",
prognamep, NIS_MSG);
retcode = PAM_SYSTEM_ERR;
goto out;
}
if (yp_master(domain, "passwd.byname", &master) != 0) {
syslog(LOG_ERR, "%s%s: can't get master for passwd map",
prognamep, NIS_MSG);
retcode = PAM_SYSTEM_ERR;
goto out;
}
client = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp");
if (client == NULL) {
syslog(LOG_ERR,
"%s%s: couldn't create client to YP master",
prognamep, NIS_MSG);
retcode = PAM_SYSTEM_ERR;
goto out;
}
timeout.tv_usec = 0;
timeout.tv_sec = 55; /* npd uses 55 seconds */
ans = CLNT_CALL(client, YPPASSWDPROC_UPDATE, xdr_yppasswd,
(char *)&yppasswd, xdr_int, (char *)&ok, timeout);
(void) clnt_destroy(client);
if (ans != RPC_SUCCESS) {
sprintf(messages[0], PAM_MSG(pamh, 100,
"%s%s: couldn't change passwd/attributes"),
prognamep, NIS_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
retcode = PAM_PERM_DENIED;
goto out;
}
if (ok != 0) {
sprintf(messages[0], PAM_MSG(pamh, 101,
"%s%s: Couldn't change passwd/attributes for %s"),
prognamep, NIS_MSG, usrname);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
retcode = PAM_PERM_DENIED;
goto out;
}
sprintf(messages[0], PAM_MSG(pamh, 102,
"NIS(YP) passwd/attributes changed on %s"),
master);
(void) __pam_display_msg(pamh, PAM_TEXT_INFO,
1, messages, NULL);
reencrypt_secret(pamh, domain, old, new, nowarn);
retcode = PAM_SUCCESS;
out:
if (yppasswd.oldpass) {
memset(yppasswd.oldpass, 0, strlen(yppasswd.oldpass));
free(yppasswd.oldpass);
}
return (retcode);
}
static int
update_nisattr(pam_handle_t *pamh, char *field, char **data,
struct passwd *nis_pwd, int privileged, int nowarn)
{
char *username;
char *value;
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
if (nis_pwd == NULL) {
if (!nowarn) {
pam_get_item(pamh, PAM_USER, (void **)&username);
sprintf(messages[0], PAM_MSG(pamh, 103,
"System error: no NIS passwd record for %s"),
username);
(void) __pam_display_msg(pamh,
PAM_ERROR_MSG, 1, messages, NULL);
}
return (PAM_USER_UNKNOWN);
}
if (strcmp(field, "attr") == 0) {
while (*data != NULL) {
/* AUTHTOK_DEL: not applicable */
if ((value = attr_match("AUTHTOK_SHELL", *data))
!= NULL) {
if (strcmp(value, "1") != 0) {
if (!nowarn) {
sprintf(messages[0],
PAM_MSG(pamh, 104,
"%s: System error%s: shell is set illegally"),
value, NIS_MSG);
(void) __pam_display_msg(pamh,
PAM_ERROR_MSG, 1,
messages, NULL);
}
return (PAM_SYSTEM_ERR);
}
nis_pwd->pw_shell =
getloginshell(pamh, nis_pwd->pw_shell,
privileged, nowarn);
/* if NULL, shell unchanged */
if (nis_pwd->pw_shell == NULL)
return (-1);
data++;
continue;
}
if ((value = attr_match("AUTHTOK_HOMEDIR", *data))
!= NULL) {
/* home directory */
if (strcmp(value, "1") != 0) {
if (!nowarn) {
sprintf(messages[0],
PAM_MSG(pamh, 105,
"System error%s: homedir is set illegally."),
NIS_MSG);
(void) __pam_display_msg(
pamh,
PAM_ERROR_MSG, 1,
messages, NULL);
}
return (PAM_SYSTEM_ERR);
}
nis_pwd->pw_dir =
gethomedir(pamh, nis_pwd->pw_dir, nowarn);
/* if NULL, homedir unchanged */
if (nis_pwd->pw_dir == NULL)
return (-1);
data++;
continue;
}
if ((value = attr_match("AUTHTOK_GECOS", *data))
!= NULL) {
/* finger information */
if (strcmp(value, "1") != 0) {
if (!nowarn) {
sprintf(messages[0],
PAM_MSG(pamh, 106,
"System error: gecos is set illegally."));
(void) __pam_display_msg(
pamh,
PAM_ERROR_MSG, 1,
messages, NULL);
}
return (PAM_SYSTEM_ERR);
}
nis_pwd->pw_gecos =
getfingerinfo(pamh, nis_pwd->pw_gecos,
nowarn);
/* if NULL, gecos unchanged */
if (nis_pwd->pw_gecos == NULL)
return (-1);
data++;
continue;
}
} /* while */
return (PAM_SUCCESS);
}
return (PAM_AUTHTOK_ERR);
/* NOTREACHED */
}
/*
* If the user has a secret key, reencrypt it.
* Otherwise, be quiet.
*/
static void
reencrypt_secret(pam_handle_t *pamh, char *domain, char *oldpass,
char *newpass, int nowarn)
{
#ifdef PAM_SECURE_RPC
char who[MAXNETNAMELEN+1];
char secret[HEXKEYBYTES+1];
char public[HEXKEYBYTES+1];
char crypt[HEXKEYBYTES + KEYCHECKSUMSIZE + 1];
char pkent[sizeof (crypt) + sizeof (public) + 1];
char *master;
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
getnetname(who);
if (!getsecretkey(who, secret, oldpass)) {
/*
* Quiet: net is not running secure RPC
*/
return;
}
if (secret[0] == 0) {
/*
* Quiet: user has no secret key
*/
return;
}
if (getpublickey(who, public) == FALSE) {
return;
}
(void) memcpy(crypt, secret, HEXKEYBYTES);
(void) memcpy(crypt + HEXKEYBYTES, secret, KEYCHECKSUMSIZE);
crypt[HEXKEYBYTES + KEYCHECKSUMSIZE] = 0;
(void) xencrypt(crypt, newpass);
(void) sprintf(pkent, "%s:%s", public, crypt);
if (yp_update(domain, PKMAP, YPOP_STORE,
who, strlen(who), pkent, strlen(pkent)) != 0) {
return;
}
if (yp_master(domain, PKMAP, &master) != 0) {
master = "yp master"; /* should never happen */
}
sprintf(messages[0], PAM_MSG(pamh, 107,
"%s: secret key reencrypted for %s on %s"),
NIS_MSG, who, master);
__pam_display_msg(pamh, PAM_TEXT_INFO, 1, messages, NULL);
#else
return;
#endif /* PAM_SECURE_RPC */
}
#endif /* PAM_NIS */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,974 @@
/* $XConsortium: unix_utils.c /main/5 1996/05/09 04:36:55 drk $ */
/*
* Copyright (c) 1992-1995, by Sun Microsystems, Inc.
* All rights reserved.
*/
#ident "@(#)unix_utils.c 1.53 95/09/11 SMI"
#include "unix_headers.h"
static char *spskip();
static int special_case();
static int illegal_input();
static int copy_passwd_structs(struct passwd **, struct passwd *,
struct spwd **, struct spwd *);
void free_passwd_structs(struct passwd *, struct spwd *);
/* ******************************************************************** */
/* */
/* Utilities Functions */
/* */
/* ******************************************************************** */
#ifdef PAM_SECURE_RPC
/*
* Establish the Secure RPC secret key for the given uid using
* the given password to decrypt the secret key, and store it with
* the key service.
*
* If called with a nonzero 'reestablish' parameter, the key
* is obtained from the name service, decrypted, and stored
* even if the keyserver already has a key stored for the uid.
* If the 'reestablish' parameter is zero, the function will not
* try to reset the key. It will return immediately with
* ESTKEY_ALREADY.
*
* Returns one of the following codes:
* ESTKEY_ALREADY - reestablish flag was zero, and key was already set.
* ESTKEY_SUCCESS - successfully obtained, decrypted, and set the key
* ESTKEY_NOCREDENTIALS - the user has no credentials.
* ESTKEY_BADPASSWD - the password supplied didn't decrypt the key
* ESTKEY_CANTSETKEY - decrypted the key, but couldn't store key with
* the key service.
*
* If netnamebuf is a non-NULL pointer, the netname will be returned in
* netnamebuf, provided that the return status is not
* ESTKEY_NOCREDENTIALS or ESTKEY_ALREADY. If non-NULL, the
* netnamebuf pointer must point to a buffer of length at least
* MAXNETNAMELEN+1 characters.
*/
int
establish_key(uid, password, reestablish, netnamebuf)
uid_t uid;
char *password;
int reestablish;
char *netnamebuf;
{
char netname[MAXNETNAMELEN+1];
struct key_netstarg netst;
uid_t orig_uid;
orig_uid = geteuid();
if (seteuid(uid) == -1)
/* can't set uid */
return (ESTKEY_NOCREDENTIALS);
if (!reestablish && key_secretkey_is_set()) {
/* key is already established and we are not to reestablish */
(void) seteuid(orig_uid);
return (ESTKEY_ALREADY);
}
if (!getnetname(netname)) {
/* can't construct netname */
(void) seteuid(orig_uid);
return (ESTKEY_NOCREDENTIALS);
}
if (!getsecretkey(netname, (char *) &(netst.st_priv_key), password)) {
/* no secret key */
(void) seteuid(orig_uid);
return (ESTKEY_NOCREDENTIALS);
}
if (netnamebuf) {
/* return copy of netname in caller's buffer */
(void) strcpy(netnamebuf, netname);
}
if (netst.st_priv_key[0] == 0) {
/* password does not decrypt secret key */
(void) seteuid(orig_uid);
return (ESTKEY_BADPASSWD);
}
/* secret key successfully decrypted at this point */
/* store with key service */
if ((netst.st_netname = strdup(netname)) == NULL) {
(void) seteuid(orig_uid);
return (PAM_BUF_ERR);
}
(void) memset(netst.st_pub_key, 0, HEXKEYBYTES);
if (key_setnet(&netst) < 0) {
free(netst.st_netname);
(void) seteuid(orig_uid);
return (ESTKEY_CANTSETKEY);
}
free(netst.st_netname);
(void) seteuid(orig_uid);
return (ESTKEY_SUCCESS);
}
#endif /* PAM_SECURE_RPC */
/* ******************************************************************** */
/* */
/* Utilities Functions */
/* */
/* ******************************************************************** */
/*
* ck_perm():
* Check the permission of the user specified by "usrname".
*
* It returns PAM_PERM_DENIED if (1) the user has a NULL pasword or
* shadow password file entry, or (2) the caller is not root and
* its uid is not equivalent to the uid specified by the user's
* password file entry.
*/
int
ck_perm(pamh, repository, domain, pwd, shpwd, privileged, passwd_res, uid,
debug, nowarn)
pam_handle_t *pamh;
int repository;
char *domain;
struct passwd **pwd;
struct spwd **shpwd;
int *privileged;
void **passwd_res;
uid_t uid;
int debug;
int nowarn;
{
FILE *pwfp, *spfp;
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
struct passwd local_pwd, *local_pwdp;
struct spwd local_shpwd, *local_shpwdp;
char pwdbuf[1024], shpwdbuf[1024];
char *prognamep;
char *usrname;
int retcode = 0;
#ifdef PAM_NISPLUS
char buf[NIS_MAXNAMELEN+1];
nis_name local_principal;
nis_name pwd_domain;
#endif
if (debug)
syslog(LOG_DEBUG,
"ck_perm() called: repository=%s",
repository_to_string(repository));
if ((retcode = pam_get_item(pamh, PAM_SERVICE, (void **)&prognamep))
!= PAM_SUCCESS ||
(retcode = pam_get_item(pamh, PAM_USER, (void **)&usrname))
!= PAM_SUCCESS) {
*pwd = NULL; *shpwd = NULL;
return (retcode);
}
if (repository == PAM_REP_FILES) {
if (((pwfp = fopen(PASSWD, "r")) == NULL) ||
((spfp = fopen(SHADOW, "r")) == NULL)) {
*pwd = NULL; *shpwd = NULL;
syslog(LOG_ERR,
"ck_perm: can not open passwd/shadow file");
return (PAM_PERM_DENIED);
}
while ((local_pwdp = fgetpwent_r(pwfp, &local_pwd, pwdbuf,
sizeof (pwdbuf))) != NULL)
if (strcmp(local_pwd.pw_name, usrname) == 0)
break;
while ((local_shpwdp = fgetspent_r(spfp, &local_shpwd,
shpwdbuf, sizeof (shpwdbuf))) != NULL)
if (strcmp(local_shpwd.sp_namp, usrname) == 0)
break;
(void) fclose(pwfp);
(void) fclose(spfp);
if (local_pwdp == NULL || local_shpwdp == NULL) {
*pwd = NULL; *shpwd = NULL;
return (PAM_USER_UNKNOWN);
}
if (uid != 0 && uid != local_pwd.pw_uid) {
/*
* Change passwd for another person:
* Even if you are nis+ admin, you can't do anything
* locally. Don't bother to continue.
*/
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 140,
"%s%s: Permission denied"), prognamep,
UNIX_MSG);
sprintf(messages[1], PAM_MSG(pamh, 141,
"%s%s: Can't change local passwd file\n"),
prognamep, UNIX_MSG);
(void) __pam_display_msg(
pamh, PAM_ERROR_MSG, 2,
messages, NULL);
}
*pwd = NULL; *shpwd = NULL;
return (PAM_PERM_DENIED);
}
return (copy_passwd_structs(pwd, local_pwdp,
shpwd, local_shpwdp));
}
#ifdef PAM_NIS
if (repository == PAM_REP_NIS) {
/*
* Special case root: don't bother to get root from nis(yp).
*/
if (strcmp(usrname, "root") == 0) {
*pwd = NULL; *shpwd = NULL;
return (PAM_USER_UNKNOWN);
}
/* get pwd struct from yp */
local_pwdp = getpwnam_from(usrname, PAM_REP_NIS);
local_shpwdp = getspnam_from(usrname, PAM_REP_NIS);
if (local_pwdp == NULL || local_shpwdp == NULL)
return (PAM_USER_UNKNOWN);
if (uid != local_pwdp->pw_uid) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 140,
"%s%s: Permission denied"), prognamep,
NIS_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
*pwd = NULL; *shpwd = NULL;
return (PAM_PERM_DENIED);
}
return (copy_passwd_structs(pwd, local_pwdp,
shpwd, local_shpwdp));
}
#endif /* PAM_NIS */
#ifdef PAM_NISPLUS
if (repository == PAM_REP_NISPLUS) {
/*
* Special case root: don't bother to get root from nis+.
*/
if (strcmp(usrname, "root") == 0) {
*pwd = NULL; *shpwd = NULL;
return (PAM_USER_UNKNOWN);
}
if (debug)
syslog(LOG_DEBUG, "ck_perm(): NIS+ domain=%s", domain);
/*
* We need to use user id to
* make any nis+ request. But don't give up the super
* user power yet. It may be needed elsewhere.
*/
(void) setuid(0); /* keep real user id as root */
(void) seteuid(uid);
local_shpwdp = getspnam_from(usrname, PAM_REP_NISPLUS);
local_pwdp = getpwnam_from(usrname, PAM_REP_NISPLUS);
if (local_pwdp == NULL || local_shpwdp == NULL)
return (PAM_USER_UNKNOWN);
/*
* local_principal is internal, it is not meant to be free()ed
*/
local_principal = nis_local_principal();
if ((9 + strlen(usrname) + strlen(domain) + PASSTABLELEN) >
(size_t) NIS_MAXNAMELEN) {
sprintf(messages[0], PAM_MSG(pamh, 140,
"%s%s: Permission denied"), prognamep, NISPLUS_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
*pwd = NULL; *shpwd = NULL;
return (PAM_PERM_DENIED);
}
sprintf(buf, "[name=%s],%s.%s", usrname, PASSTABLE, domain);
if (buf[strlen(buf) - 1] != '.')
(void) strcat(buf, ".");
/*
* We must use an authenticated handle to get the cred
* table information for the user we want to modify the
* cred info for. If we can't even read that info, we
* definitely wouldn't have modify permission. Well..
*/
*passwd_res = (void *) nis_list(buf,
USE_DGRAM+FOLLOW_LINKS+FOLLOW_PATH+MASTER_ONLY,
NULL, NULL);
if (((nis_result *)(*passwd_res))->status != NIS_SUCCESS) {
sprintf(messages[0], PAM_MSG(pamh, 140,
"%s%s: Permission denied"), prognamep, NISPLUS_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
*pwd = NULL; *shpwd = NULL;
return (PAM_PERM_DENIED);
}
pwd_domain =
NIS_RES_OBJECT((nis_result *)(*passwd_res))->zo_domain;
if (strcmp(nis_leaf_of(pwd_domain), "org_dir") == 0) {
pwd_domain = nis_domain_of(
NIS_RES_OBJECT((nis_result *)(*passwd_res))->zo_domain);
}
*privileged = __nis_isadmin(local_principal, "passwd",
pwd_domain);
return (copy_passwd_structs(pwd, local_pwdp,
shpwd, local_shpwdp));
}
#endif /* PAM_NISPLUS */
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 142,
"%s%s: System error: repository out of range"),
prognamep, UNIX_MSG);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1,
messages, NULL);
}
*pwd = NULL; *shpwd = NULL;
return (PAM_PERM_DENIED);
}
/*
* attr_match():
*
* Check if the attribute name in string s1 is equivalent to
* that in string s2.
* s1 is either name, or name=value
* s2 is name=value
* if names match, return value of s2, else NULL
*/
char *
attr_match(s1, s2)
register char *s1, *s2;
{
while (*s1 == *s2++)
if (*s1++ == '=')
return (s2);
if (*s1 == '\0' && *(s2-1) == '=')
return (s2);
return (NULL);
}
/*
* attr_find():
*
* Check if the attribute name in string s1 is present in the
* attribute=value pairs array pointed by s2.
* s1 is name
* s2 is an array of name=value pairs
* if s1 match the name of any one of the name in the name=value pairs
* pointed by s2, then 1 is returned; else 0 is returned
*/
int
attr_find(s1, s2)
register char *s1, *s2[];
{
int i;
char *sa, *sb;
i = 0;
while (s2[i] != NULL) {
sa = s1;
sb = s2[i];
while (*sa++ == *sb++) {
if ((*sa == '\0') && (*sb == '='))
return (1); /* find */
}
i++;
}
return (0); /* not find */
}
/*
* free_setattr():
* free storage pointed by "setattr"
*/
void
free_setattr(setattr)
char * setattr[];
{
int i;
for (i = 0; setattr[i] != NULL; i++)
free(setattr[i]);
}
/*
* setup_attr():
* allocate memory and copy in attribute=value pair
* into the array of attribute=value pairs pointed to
* by "dest_attr"
*/
void
setup_attr(dest_attr, k, attr, value)
char *dest_attr[];
int k;
char attr[];
char value[];
{
if (attr != NULL) {
dest_attr[k] = (char *)calloc(PAM_MAX_ATTR_SIZE, sizeof (char));
(void) strncpy(dest_attr[k], attr, PAM_MAX_ATTR_SIZE);
(void) strncat(dest_attr[k], value, PAM_MAX_ATTR_SIZE);
} else
dest_attr[k] = NULL;
}
#ifdef PAM_NISPLUS
static char *
spskip(p)
register char *p;
{
while (*p && *p != ':' && *p != '\n')
++p;
if (*p == '\n')
*p = '\0';
else if (*p)
*p++ = '\0';
return (p);
}
void
nisplus_populate_age(enobj, sp)
struct nis_object *enobj;
struct spwd *sp;
{
char *oldage, *p, *end;
long x;
/*
* shadow (col 7)
*/
sp->sp_lstchg = -1;
sp->sp_min = -1;
sp->sp_max = -1;
sp->sp_warn = -1;
sp->sp_inact = -1;
sp->sp_expire = -1;
sp->sp_flag = 0;
if ((p = ENTRY_VAL(enobj, 7)) == NULL)
return;
oldage = strdup(p);
p = oldage;
x = strtol(p, &end, 10);
if (end != memchr(p, ':', strlen(p)))
return;
if (end != p)
sp->sp_lstchg = x;
p = spskip(p);
x = strtol(p, &end, 10);
if (end != memchr(p, ':', strlen(p)))
return;
if (end != p)
sp->sp_min = x;
p = spskip(p);
x = strtol(p, &end, 10);
if (end != memchr(p, ':', strlen(p)))
return;
if (end != p)
sp->sp_max = x;
p = spskip(p);
x = strtol(p, &end, 10);
if (end != memchr(p, ':', strlen(p)))
return;
if (end != p)
sp->sp_warn = x;
p = spskip(p);
x = strtol(p, &end, 10);
if (end != memchr(p, ':', strlen(p)))
return;
if (end != p)
sp->sp_inact = x;
p = spskip(p);
x = strtol(p, &end, 10);
if (end != memchr(p, ':', strlen(p)))
return;
if (end != p)
sp->sp_expire = x;
p = spskip(p);
x = strtol(p, &end, 10);
if ((end != memchr(p, ':', strlen(p))) &&
(end != memchr(p, '\n', strlen(p))))
return;
if (end != p)
sp->sp_flag = x;
free(oldage);
}
#endif /* PAM_NISPLUS */
/*
* getloginshell() displays old login shell and asks for new login shell.
* The new login shell is then returned to calling function.
*/
char *
getloginshell(pamh, oldshell, privileged, nowarn)
pam_handle_t *pamh;
char *oldshell;
int privileged;
int nowarn;
{
char newshell[PAM_MAX_MSG_SIZE];
char *cp, *valid, *getusershell();
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
struct pam_response *ret_resp = (struct pam_response *)0;
if (oldshell == 0 || *oldshell == '\0')
oldshell = DEFSHELL;
if (privileged == 0) {
mutex_lock(&_priv_lock);
setusershell();
for (valid = getusershell(); valid; valid = getusershell())
if (strcmp(oldshell, valid) == 0)
break;
mutex_unlock(&_priv_lock);
if (valid == NULL) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 143,
"Cannot change from restricted shell %s"),
oldshell);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
return (NULL);
}
}
sprintf(messages[0],
PAM_MSG(pamh, 144, "Old shell: %s"), oldshell);
(void) __pam_display_msg(pamh, PAM_TEXT_INFO, 1, messages, NULL);
sprintf(messages[0],
PAM_MSG(pamh, 145, "New shell: "));
(void) __pam_get_input(pamh, PAM_PROMPT_ECHO_ON,
1, messages, NULL, &ret_resp);
strncpy(newshell, ret_resp->resp, PAM_MAX_MSG_SIZE);
newshell[PAM_MAX_RESP_SIZE-1] = '\0';
__pam_free_resp(1, ret_resp);
cp = strchr(newshell, '\n');
if (cp)
*cp = '\0';
if (newshell[0] == '\0' || (strcmp(newshell, oldshell) == 0)) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 146,
"Login shell unchanged."));
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
return (NULL);
}
/*
* XXX:
* Keep in mind that, for whatever this validation is worth,
* a root on a machine can edit /etc/shells and get any shell
* accepted as a valid shell in the NIS+ table.
*/
mutex_lock(&_priv_lock);
setusershell();
if (!privileged) {
for (valid = getusershell(); valid; valid = getusershell()) {
/*
* Allow user to give shell w/o preceding pathname.
*/
if (newshell[0] == '/') {
cp = valid;
} else {
cp = strrchr(valid, '/');
if (cp == 0)
cp = valid;
else
cp++;
}
if (strcmp(newshell, cp) == 0) {
strncpy(newshell, valid, strlen(valid));
break;
}
}
}
mutex_unlock(&_priv_lock);
if (newshell == 0) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 147,
"%s is unacceptable as a new shell"),
newshell);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
__pam_free_resp(1, ret_resp);
return (NULL);
}
if (access(newshell, X_OK) < 0) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 148,
"warning: %s is unavailable on this machine"),
newshell);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
}
return (strdup(newshell));
}
/*
* Get name.
*/
char *
getfingerinfo(pamh, old_gecos, nowarn)
pam_handle_t *pamh;
char *old_gecos;
int nowarn;
{
char new_gecos[PAM_MAX_MSG_SIZE];
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
struct pam_response *ret_resp = (struct pam_response *)0;
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 149,
"Default values are printed inside of '[]'."));
sprintf(messages[1], PAM_MSG(pamh, 150,
"To accept the default, type <return>."));
sprintf(messages[2], PAM_MSG(pamh, 151,
"To have a blank entry, type the word 'none'."));
(void) __pam_display_msg(pamh, PAM_TEXT_INFO,
3, messages, NULL);
}
/*
* Get name.
*/
do {
sprintf(messages[0], " ");
(void) __pam_display_msg(pamh, PAM_TEXT_INFO, 1,
messages, NULL);
sprintf(messages[0], PAM_MSG(pamh, 152,
"Name [%s]: "), old_gecos);
(void) __pam_get_input(pamh, PAM_PROMPT_ECHO_ON,
1, messages, NULL, &ret_resp);
strncpy(new_gecos, ret_resp->resp, PAM_MAX_MSG_SIZE);
new_gecos[PAM_MAX_MSG_SIZE-1] = '\0';
__pam_free_resp(1, ret_resp);
if (special_case(new_gecos, old_gecos))
break;
} while (illegal_input(pamh, new_gecos, nowarn));
if (strcmp(new_gecos, old_gecos) == 0) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 153,
"Finger information unchanged."));
(void) __pam_display_msg(pamh, PAM_TEXT_INFO,
1, messages, NULL);
}
return (NULL);
}
return (strdup(new_gecos));
}
/*
* Get Home Dir.
*/
char *
gethomedir(pamh, olddir, nowarn)
pam_handle_t *pamh;
char *olddir;
int nowarn;
{
char newdir[PAM_MAX_MSG_SIZE];
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
struct pam_response *ret_resp = (struct pam_response *)0;
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 149,
"Default values are printed inside of '[]'."));
sprintf(messages[1], PAM_MSG(pamh, 150,
"To accept the default, type <return>."));
sprintf(messages[2], PAM_MSG(pamh, 151,
"To have a blank entry, type the word 'none'."));
(void) __pam_display_msg(pamh, PAM_TEXT_INFO,
3, messages, NULL);
}
do {
sprintf(messages[0], " ");
(void) __pam_display_msg(pamh, PAM_TEXT_INFO,
1, messages, NULL);
sprintf(messages[0], PAM_MSG(pamh, 154,
"Home Directory [%s]: "), olddir);
(void) __pam_get_input(pamh, PAM_PROMPT_ECHO_ON,
1, messages, NULL, &ret_resp);
strncpy(newdir, ret_resp->resp, PAM_MAX_MSG_SIZE);
newdir[PAM_MAX_MSG_SIZE-1] = '\0';
__pam_free_resp(1, ret_resp);
if (special_case(newdir, olddir))
break;
} while (illegal_input(pamh, newdir, nowarn));
if (strcmp(newdir, olddir) == 0) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 155,
"Homedir information unchanged."));
(void) __pam_display_msg(pamh, PAM_TEXT_INFO,
1, messages, NULL);
}
return (NULL);
}
return (strdup(newdir));
}
char *
repository_to_string(int repository)
{
/* if NISPLUS and FILES */
switch (repository) {
case (PAM_REP_FILES | PAM_REP_NISPLUS):
return ("files and nisplus");
case (PAM_REP_FILES | PAM_REP_NIS):
return ("files and nis");
case PAM_REP_NISPLUS:
return ("nisplus");
case PAM_REP_NIS:
return ("nis");
case PAM_REP_FILES:
return ("files");
case PAM_REP_DEFAULT:
return ("default");
default:
return ("bad repository");
}
}
/*
* Prints an error message if a ':' or a newline is found in the string.
* A message is also printed if the input string is too long.
* The password sources use :'s as seperators, and are not allowed in the "gcos"
* field. Newlines serve as delimiters between users in the password source,
* and so, those too, are checked for. (I don't think that it is possible to
* type them in, but better safe than sorry)
*
* Returns '1' if a colon or newline is found or the input line is too long.
*/
static int
illegal_input(pamh, input_str, nowarn)
pam_handle_t *pamh;
char *input_str;
int nowarn;
{
char *ptr;
int error_flag = 0;
int length = (int)strlen(input_str);
char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
if (strchr(input_str, ':')) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 156,
"':' is not allowed."));
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
error_flag = 1;
}
if (input_str[length-1] != '\n') {
/* the newline and the '\0' eat up two characters */
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 157,
"Maximum number of characters allowed is %d."),
PAM_MAX_MSG_SIZE-2);
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
error_flag = 1;
}
/*
* Delete newline by shortening string by 1.
*/
input_str[length-1] = '\0';
/*
* Don't allow control characters, etc in input string.
*/
for (ptr = input_str; *ptr != '\0'; ptr++) {
/* 040 is ascii char "space" */
if ((int) *ptr < 040) {
if (!nowarn) {
sprintf(messages[0], PAM_MSG(pamh, 158,
"Control characters are not allowed."));
(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
1, messages, NULL);
}
error_flag = 1;
break;
}
}
return (error_flag);
}
/*
* special_case returns true when either the default is accepted
* (str = '\n'), or when 'none' is typed. 'none' is accepted in
* either upper or lower case (or any combination). 'str' is modified
* in these two cases.
*/
static int
special_case(str, default_str)
char *str, *default_str;
{
static char word[] = "none\n";
char *ptr, *wordptr;
/*
* If the default is accepted, then change the old string do the
* default string.
*/
if (*str == '\n') {
(void) strcpy(str, default_str);
return (1);
}
/*
* Check to see if str is 'none'. (It is questionable if case
* insensitivity is worth the hair).
*/
wordptr = word - 1;
for (ptr = str; *ptr != '\0'; ++ptr) {
++wordptr;
if (*wordptr == '\0') /* then words are different sizes */
return (0);
if (*ptr == *wordptr)
continue;
if (isupper(*ptr) && (tolower(*ptr) == *wordptr))
continue;
/*
* At this point we have a mismatch, so we return
*/
return (0);
}
/*
* Make sure that words are the same length.
*/
if (*(wordptr+1) != '\0')
return (0);
/*
* Change 'str' to be the null string
*/
*str = '\0';
return (1);
}
static int
copy_passwd_structs(struct passwd **pwd, struct passwd *local_pwd,
struct spwd **shpwd, struct spwd *local_shpwd)
{
/* copy the passwd information */
if ((*pwd = (struct passwd *)
calloc(1, sizeof (struct passwd))) == NULL)
return (PAM_BUF_ERR);
if (local_pwd->pw_name) {
if (((*pwd)->pw_name = strdup(local_pwd->pw_name)) == NULL)
goto out;
}
if (local_pwd->pw_passwd) {
if (((*pwd)->pw_passwd = strdup(local_pwd->pw_passwd)) == NULL)
goto out;
}
(*pwd)->pw_uid = local_pwd->pw_uid;
(*pwd)->pw_gid = local_pwd->pw_gid;
if (local_pwd->pw_gecos) {
if (((*pwd)->pw_gecos = strdup(local_pwd->pw_gecos)) == NULL)
goto out;
}
if (local_pwd->pw_dir) {
if (((*pwd)->pw_dir = strdup(local_pwd->pw_dir)) == NULL)
goto out;
}
if (local_pwd->pw_shell) {
if (((*pwd)->pw_shell = strdup(local_pwd->pw_shell)) == NULL)
goto out;
}
/* copy the shadow passwd information */
if ((*shpwd = (struct spwd *)
calloc(1, sizeof (struct spwd))) == NULL)
goto out;
**shpwd = *local_shpwd;
if (local_shpwd->sp_namp) {
if (((*shpwd)->sp_namp = strdup(local_shpwd->sp_namp)) == NULL)
goto out;
}
if (local_shpwd->sp_pwdp) {
if (((*shpwd)->sp_pwdp = strdup(local_shpwd->sp_pwdp)) == NULL)
goto out;
}
return (PAM_SUCCESS);
out:
free_passwd_structs(*pwd, *shpwd);
return (PAM_BUF_ERR);
}
void
free_passwd_structs(struct passwd *pwd, struct spwd *shpwd)
{
if (pwd) {
if (pwd->pw_name)
free(pwd->pw_name);
if (pwd->pw_passwd) {
memset(pwd->pw_passwd, 0, strlen(pwd->pw_passwd));
free(pwd->pw_passwd);
}
if (pwd->pw_gecos)
free(pwd->pw_gecos);
if (pwd->pw_dir)
free(pwd->pw_dir);
if (pwd->pw_shell)
free(pwd->pw_shell);
free(pwd);
}
if (shpwd) {
if (shpwd->sp_namp)
free(shpwd->sp_namp);
if (shpwd->sp_pwdp) {
memset(shpwd->sp_pwdp, 0, strlen(shpwd->sp_pwdp));
free(shpwd->sp_pwdp);
}
free(shpwd);
}
}

View File

@@ -0,0 +1,68 @@
/* $XConsortium: yppasswdxdr.c /main/2 1996/05/08 13:46:51 drk $
*
* (c) Copyright 1996 Digital Equipment Corporation.
* (c) Copyright 1996 Hewlett-Packard Company.
* (c) Copyright 1996 International Business Machines Corp.
* (c) Copyright 1995,1996 Sun Microsystems, Inc.
* (c) Copyright 1996 Novell, Inc.
* (c) Copyright 1996 FUJITSU LIMITED.
* (c) Copyright 1996 Hitachi.
*/
/*******************************************************************************
** yppasswd utilies
*******************************************************************************/
#if (PAM_NIS || PAM_NISPLUS)
#include "unix_headers.h"
bool_t
xdr_passwd(xdrs, pw)
XDR *xdrs;
struct passwd *pw;
{
if (!xdr_wrapstring(xdrs, &pw->pw_name)) {
return (FALSE);
}
if (!xdr_wrapstring(xdrs, &pw->pw_passwd)) {
return (FALSE);
}
if (!xdr_uid_t(xdrs, &pw->pw_uid)) {
return (FALSE);
}
if (!xdr_gid_t(xdrs, (&pw->pw_gid))){
return (FALSE);
}
if (!xdr_wrapstring(xdrs, &pw->pw_gecos)) {
return (FALSE);
}
if (!xdr_wrapstring(xdrs, &pw->pw_dir)) {
return (FALSE);
}
if (!xdr_wrapstring(xdrs, &pw->pw_shell)) {
return (FALSE);
}
return (TRUE);
}
bool_t
xdr_yppasswd(xdrs, yppw)
XDR *xdrs;
struct yppasswd *yppw;
{
if (!xdr_wrapstring(xdrs, &yppw->oldpass)) {
return (FALSE);
}
if (!xdr_passwd(xdrs, &yppw->newpw)) {
return (FALSE);
}
return (TRUE);
}
#else
/* Some compilers complain about empty compilation modules. */
static int dummy;
#endif /* PAM_NIS or PAM_NISPLUS */