diff options
author | Steve Langasek <steve.langasek@ubuntu.com> | 2019-01-03 12:47:05 -0800 |
---|---|---|
committer | Steve Langasek <steve.langasek@ubuntu.com> | 2019-01-03 12:47:05 -0800 |
commit | 4c51da22e068907adb7857d50f5109a467c94d7c (patch) | |
tree | becf5fbae5dfcbe8896355f59042dc8eaefa7f37 /Linux-PAM/modules | |
parent | efd31890b5ed496a5a00c08a262da240e66a4ddc (diff) | |
parent | ab9e8ba11f464fc083fc65a0bc695d60ebc86f3e (diff) | |
download | pam-4c51da22e068907adb7857d50f5109a467c94d7c.tar.gz pam-4c51da22e068907adb7857d50f5109a467c94d7c.tar.bz2 pam-4c51da22e068907adb7857d50f5109a467c94d7c.zip |
New upstream version 0.79
Diffstat (limited to 'Linux-PAM/modules')
137 files changed, 4924 insertions, 1401 deletions
diff --git a/Linux-PAM/modules/Makefile b/Linux-PAM/modules/Makefile index 96b3a636..58be5a24 100644 --- a/Linux-PAM/modules/Makefile +++ b/Linux-PAM/modules/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1.1.2 2002/09/15 20:08:43 hartmans Exp $ +# $Id: Makefile,v 1.4 2004/09/28 13:48:47 kukuk Exp $ # # Makefile # @@ -8,7 +8,7 @@ include ../Make.Rules -MODDIRS=$(shell /bin/ls -d pam_*) +MODDIRS=$(shell /bin/ls -d pam_*/Makefile | cut -f1 -d/) all: @echo building the static modutil library diff --git a/Linux-PAM/modules/Simple.Rules b/Linux-PAM/modules/Simple.Rules index bbbf3e50..57b582de 100644 --- a/Linux-PAM/modules/Simple.Rules +++ b/Linux-PAM/modules/Simple.Rules @@ -1,4 +1,4 @@ -# $Id: Simple.Rules,v 1.1.1.2 2002/09/15 20:08:43 hartmans Exp $ +# $Id: Simple.Rules,v 1.7 2004/09/28 13:48:47 kukuk Exp $ # # For simple modules with no significant dependencies, set $(TITLE) # and include this file. @@ -13,13 +13,15 @@ # $(MODULE_SIMPLE_EXTRAFILES) - other files to build (no .c suffix) # +-include ../Make.Rules + LIBFILES = $(TITLE) $(MODULE_SIMPLE_EXTRAFILES) LIBSRC = $(addsuffix .c,$(LIBFILES)) LIBOBJ = $(addsuffix .o,$(LIBFILES)) LIBOBJD = $(addprefix dynamic/,$(LIBOBJ)) LIBOBJS = $(addprefix static/,$(LIBOBJ)) -LINK_PAMMODUTILS = -L../pammodutil -lpammodutil +LINK_PAMMODUTILS = -L../pammodutil -lpammodutil -L../../libpam -lpam INCLUDE_PAMMODUTILS = -I../pammodutil/include ifdef DYNAMIC @@ -77,6 +79,18 @@ install: all ifdef DYNAMIC $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) endif +ifdef MAN3 + test -d $(FAKEROOT)$(mandir)/man3 || $(MKDIR) $(FAKEROOT)$(mandir)/man3 + $(INSTALL) -m $(MANMODE) $(MAN3) $(FAKEROOT)$(mandir)/man3/ +endif +ifdef MAN5 + test -d $(FAKEROOT)$(mandir)/man5 || $(MKDIR) $(FAKEROOT)$(mandir)/man5 + $(INSTALL) -m $(MANMODE) $(MAN5) $(FAKEROOT)$(mandir)/man5/ +endif +ifdef MAN8 + test -d $(FAKEROOT)$(mandir)/man8 || $(MKDIR) $(FAKEROOT)$(mandir)/man8 + $(INSTALL) -m $(MANMODE) $(MAN8) $(FAKEROOT)$(mandir)/man8/ +endif $(MODULE_SIMPLE_INSTALL) remove: diff --git a/Linux-PAM/modules/dont_makefile b/Linux-PAM/modules/dont_makefile index b49e9e7a..48307f02 100644 --- a/Linux-PAM/modules/dont_makefile +++ b/Linux-PAM/modules/dont_makefile @@ -1,5 +1,5 @@ ######################################################################### -# $Id: dont_makefile,v 1.1.1.1 2001/04/29 04:17:16 hartmans Exp $ +# $Id: dont_makefile,v 1.2 2000/11/19 23:54:03 agmorgan Exp $ ######################################################################### # This is a makefile that does nothing. It is designed to be included # by module Makefile-s when they are not compatable with the local diff --git a/Linux-PAM/modules/download-all b/Linux-PAM/modules/download-all index 451b3c51..9b6cf655 100755 --- a/Linux-PAM/modules/download-all +++ b/Linux-PAM/modules/download-all @@ -1,6 +1,6 @@ #!/bin/sh # -# $Id: download-all,v 1.1.1.1 2001/04/29 04:17:16 hartmans Exp $ +# $Id: download-all,v 1.1.1.1 2000/06/20 22:11:29 agmorgan Exp $ # cat <<EOT For a number of reasons it is not practical for Linux-PAM to be diff --git a/Linux-PAM/modules/pam_access/Makefile b/Linux-PAM/modules/pam_access/Makefile index 5f8574ab..d8a71ee5 100644 --- a/Linux-PAM/modules/pam_access/Makefile +++ b/Linux-PAM/modules/pam_access/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:16 hartmans Exp $ +# $Id: Makefile,v 1.3 2003/07/13 18:41:04 vorlon Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know @@ -10,6 +10,9 @@ include ../../Make.Rules TITLE=pam_access LOCAL_CONFILE=./access.conf INSTALLED_CONFILE=$(SCONFIGD)/access.conf +ifeq ($(HAVE_LIBNSL),yes) +MODULE_SIMPLE_EXTRALIBS=-lnsl +endif DEFS=-DDEFAULT_CONF_FILE=\"$(INSTALLED_CONFILE)\" CFLAGS += $(DEFS) diff --git a/Linux-PAM/modules/pam_access/access.conf b/Linux-PAM/modules/pam_access/access.conf index dbaadf67..cec2be0c 100644 --- a/Linux-PAM/modules/pam_access/access.conf +++ b/Linux-PAM/modules/pam_access/access.conf @@ -40,8 +40,15 @@ # logged-in user. Both the user's primary group is matched, as well as # groups in which users are explicitly listed. # +# TTY NAMES: Must be in the form returned by ttyname(3) less the initial +# "/dev" (e.g. tty1 or vc/1) +# ############################################################################## # +# Disallow non-root logins on tty1 +# +#-:ALL EXCEPT root:tty1 +# # Disallow console logins to all but a few accounts. # #-:ALL EXCEPT wheel shutdown sync:LOCAL diff --git a/Linux-PAM/modules/pam_access/pam_access.c b/Linux-PAM/modules/pam_access/pam_access.c index 4005c93b..4f6cf574 100644 --- a/Linux-PAM/modules/pam_access/pam_access.c +++ b/Linux-PAM/modules/pam_access/pam_access.c @@ -5,23 +5,23 @@ * (I took login_access from logdaemon-5.6 and converted it to PAM * using parts of pam_time code.) * - ************************************************************************ + ************************************************************************ * Copyright message from logdaemon-5.6 (original file name DISCLAIMER) - ************************************************************************ - * Copyright 1995 by Wietse Venema. All rights reserved. Individual files - * may be covered by other copyrights (as noted in the file itself.) - * - * This material was originally written and compiled by Wietse Venema at - * Eindhoven University of Technology, The Netherlands, in 1990, 1991, - * 1992, 1993, 1994 and 1995. - * - * Redistribution and use in source and binary forms are permitted - * provided that this entire copyright notice is duplicated in all such - * copies. - * - * This software is provided "as is" and without any expressed or implied - * warranties, including, without limitation, the implied warranties of - * merchantibility and fitness for any particular purpose. + ************************************************************************ + * Copyright 1995 by Wietse Venema. All rights reserved. Individual files + * may be covered by other copyrights (as noted in the file itself.) + * + * This material was originally written and compiled by Wietse Venema at + * Eindhoven University of Technology, The Netherlands, in 1990, 1991, + * 1992, 1993, 1994 and 1995. + * + * Redistribution and use in source and binary forms are permitted + * provided that this entire copyright notice is duplicated in all such + * copies. + * + * This software is provided "as is" and without any expressed or implied + * warranties, including, without limitation, the implied warranties of + * merchantibility and fitness for any particular purpose. ************************************************************************* */ @@ -41,6 +41,7 @@ #include <errno.h> #include <ctype.h> #include <sys/utsname.h> +#include <rpcsvc/ypclnt.h> #ifndef BROKEN_NETWORK_MATCH # include <netdb.h> @@ -58,8 +59,7 @@ #include <security/_pam_macros.h> #include <security/pam_modules.h> - -int strcasecmp(const char *s1, const char *s2); +#include <security/_pam_modutil.h> /* login_access.c from logdaemon-5.6 with several changes by A.Nogin: */ @@ -68,7 +68,7 @@ int strcasecmp(const char *s1, const char *s2); * control based on login names and on host (or domain) names, internet * addresses (or network numbers), or on terminal line names in case of * non-networked logins. Diagnostics are reported through syslog(3). - * + * * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. */ @@ -140,26 +140,27 @@ static int parse_args(struct login_info *loginfo, int argc, const char **argv) , loginfo->service, 11 + argv[i]); return 0; } - + } else { _log_err("unrecognized option [%s]", argv[i]); } } - + return 1; /* OK */ } -typedef int match_func (char *, struct login_info *); +typedef int match_func (pam_handle_t *, char *, struct login_info *); -static int list_match (char *, struct login_info *, - match_func *); -static int user_match (char *, struct login_info *); -static int from_match (char *, struct login_info *); -static int string_match (char *, char *); +static int list_match (pam_handle_t *, char *, struct login_info *, + match_func *); +static int user_match (pam_handle_t *, char *, struct login_info *); +static int from_match (pam_handle_t *, char *, struct login_info *); +static int string_match (pam_handle_t *, char *, char *); /* login_access - match username/group and host/tty with access control file */ -static int login_access(struct login_info *item) +static int +login_access (pam_handle_t *pamh, struct login_info *item) { FILE *fp; char line[BUFSIZ]; @@ -193,10 +194,11 @@ static int login_access(struct login_info *item) line[end] = 0; /* strip trailing whitespace */ if (line[0] == 0) /* skip blank lines */ continue; + + /* Allow trailing: in last field fo froms */ if (!(perm = strtok(line, fs)) || !(users = strtok((char *) 0, fs)) - || !(froms = strtok((char *) 0, fs)) - || strtok((char *) 0, fs)) { + || !(froms = strtok((char *) 0, fs))) { _log_err("%s: line %d: bad field count", item->config_file, lineno); continue; @@ -206,19 +208,21 @@ static int login_access(struct login_info *item) item->config_file, lineno); continue; } - match = (list_match(froms, item, from_match) - && list_match(users, item, user_match)); + match = (list_match(pamh, froms, item, from_match) + && list_match(pamh, users, item, user_match)); } (void) fclose(fp); } else if (errno != ENOENT) { _log_err("cannot open %s: %m", item->config_file); + return NO; } return (match == 0 || (line[0] == '+')); } /* list_match - match an item against a list of tokens with exceptions */ -static int list_match(char *list, struct login_info *item, match_func *match_fn) +static int list_match(pam_handle_t *pamh, + char *list, struct login_info *item, match_func *match_fn) { char *tok; int match = NO; @@ -233,7 +237,7 @@ static int list_match(char *list, struct login_info *item, match_func *match_fn) for (tok = strtok(list, sep); tok != 0; tok = strtok((char *) 0, sep)) { if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */ break; - if ((match = (*match_fn) (tok, item))) /* YES */ + if ((match = (*match_fn) (pamh, tok, item))) /* YES */ break; } /* Process exceptions to matches. */ @@ -241,7 +245,7 @@ static int list_match(char *list, struct login_info *item, match_func *match_fn) if (match != NO) { while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT")) /* VOID */ ; - if (tok == 0 || list_match((char *) 0, item, match_fn) == NO) + if (tok == 0 || list_match(pamh, (char *) 0, item, match_fn) == NO) return (match); } return (NO); @@ -253,35 +257,30 @@ static char * myhostname(void) { static char name[MAXHOSTNAMELEN + 1]; - gethostname(name, MAXHOSTNAMELEN); - name[MAXHOSTNAMELEN] = 0; - return (name); + if (gethostname(name, MAXHOSTNAMELEN) == 0) { + name[MAXHOSTNAMELEN] = 0; + return (name); + } + return NULL; } /* netgroup_match - match group against machine or user */ static int netgroup_match(char *group, char *machine, char *user) { -#ifdef NIS - static char *mydomain = 0; + static char *mydomain = NULL; if (mydomain == 0) yp_get_default_domain(&mydomain); return (innetgr(group, machine, user, mydomain)); -#else - _log_err("NIS netgroup support not configured"); - return (NO); -#endif } /* user_match - match a username against one token */ -static int user_match(char *tok, struct login_info *item) +static int user_match(pam_handle_t *pamh, char *tok, struct login_info *item) { char *string = item->user->pw_name; struct login_info fake_item; - struct group *group; - int i; char *at; /* @@ -294,24 +293,24 @@ static int user_match(char *tok, struct login_info *item) if ((at = strchr(tok + 1, '@')) != 0) { /* split user@host pattern */ *at = 0; fake_item.from = myhostname(); - return (user_match(tok, item) && from_match(at + 1, &fake_item)); - } else if (tok[0] == '@') { /* netgroup */ + if (fake_item.from == NULL) + return NO; + return (user_match (pamh, tok, item) && from_match (pamh, at + 1, &fake_item)); + } else if (tok[0] == '@') /* netgroup */ return (netgroup_match(tok + 1, (char *) 0, string)); - } else if (string_match(tok, string)) { /* ALL or exact match */ - return (YES); - } else if ((group = getgrnam(tok))) { /* try group membership */ - if (item->user->pw_gid == group->gr_gid) - return (YES); - for (i = 0; group->gr_mem[i]; i++) - if (strcasecmp(string, group->gr_mem[i]) == 0) - return (YES); - } - return (NO); + else if (string_match (pamh, tok, string)) /* ALL or exact match */ + return YES; + else if (_pammodutil_user_in_group_nam_nam (pamh, item->user->pw_name, tok)) + /* try group membership */ + return YES; + + return NO; } /* from_match - match a host or tty against a list of tokens */ -static int from_match(char *tok, struct login_info *item) +static int +from_match (pam_handle_t *pamh, char *tok, struct login_info *item) { char *string = item->from; int tok_len; @@ -328,9 +327,9 @@ static int from_match(char *tok, struct login_info *item) if (tok[0] == '@') { /* netgroup */ return (netgroup_match(tok + 1, string, (char *) 0)); - } else if (string_match(tok, string)) { /* ALL or exact match */ - return (YES); - } else if (tok[0] == '.') { /* domain: match last fields */ + } else if (string_match (pamh, tok, string)) /* ALL or exact match */ + return YES; + else if (tok[0] == '.') { /* domain: match last fields */ if ((str_len = strlen(string)) > (tok_len = strlen(tok)) && strcasecmp(tok, string + str_len - tok_len) == 0) return (YES); @@ -374,7 +373,8 @@ static int from_match(char *tok, struct login_info *item) /* string_match - match a string against one token */ -static int string_match(char *tok, char *string) +static int +string_match (pam_handle_t *pamh, char *tok, char *string) { /* @@ -390,14 +390,6 @@ static int string_match(char *tok, char *string) return (NO); } -/* end of login_access.c */ - -int strcasecmp(const char *s1, const char *s2) -{ - while ((toupper(*s1)==toupper(*s2)) && (*s1) && (*s2)) {s1++; s2++;} - return(toupper(*s1)-toupper(*s2)); -} - /* --- public account management functions --- */ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc @@ -447,13 +439,15 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc return PAM_ABORT; } } - if (strncmp("/dev/",from,5) == 0) { /* strip leading /dev/ */ - from += 5; - } + if (from[0] == '/') { /* full path */ + from++; + from = strchr(from, '/'); + from++; + } } - if ((user_pw=getpwnam(user))==NULL) return (PAM_USER_UNKNOWN); + if ((user_pw=_pammodutil_getpwnam(pamh, user))==NULL) return (PAM_USER_UNKNOWN); /* * Bundle up the arguments to avoid unnecessary clumsiness later on. @@ -470,7 +464,7 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc return PAM_ABORT; } - if (login_access(&loginfo)) { + if (login_access(pamh, &loginfo)) { return (PAM_SUCCESS); } else { _log_err("access denied for user `%s' from `%s'",user,from); @@ -494,4 +488,3 @@ struct pam_module _pam_access_modstruct = { NULL }; #endif - diff --git a/Linux-PAM/modules/pam_cracklib/Makefile b/Linux-PAM/modules/pam_cracklib/Makefile index 9e8f69aa..371ac0a8 100644 --- a/Linux-PAM/modules/pam_cracklib/Makefile +++ b/Linux-PAM/modules/pam_cracklib/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:17 hartmans Exp $ +# $Id: Makefile,v 1.3 2001/02/10 22:15:23 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_cracklib/pam_cracklib.c b/Linux-PAM/modules/pam_cracklib/pam_cracklib.c index fa415e32..8f3e4c42 100644 --- a/Linux-PAM/modules/pam_cracklib/pam_cracklib.c +++ b/Linux-PAM/modules/pam_cracklib/pam_cracklib.c @@ -1,6 +1,6 @@ /* * pam_cracklib module - * $Id: pam_cracklib.c,v 1.1.1.2 2002/09/15 20:08:45 hartmans Exp $ + * $Id: pam_cracklib.c,v 1.9 2004/09/15 12:06:17 kukuk Exp $ */ /* @@ -77,7 +77,7 @@ extern char *FascistCheck(char *pw, const char *dictpath); #include <security/pam_modules.h> #include <security/_pam_macros.h> -#ifndef LINUX_PAM +#ifndef LINUX_PAM #include <security/pam_appl.h> #endif /* LINUX_PAM */ @@ -186,11 +186,11 @@ static int converse(pam_handle_t *pamh, int ctrl, int nargs, struct pam_response **response) { int retval; - struct pam_conv *conv; + struct pam_conv *conv = NULL; - retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); + retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); - if ( retval == PAM_SUCCESS ) { + if ( retval == PAM_SUCCESS && conv ) { retval = conv->conv(nargs, (const struct pam_message **)message, response, conv->appdata_ptr); if (retval != PAM_SUCCESS && (ctrl && PAM_DEBUG_ARG)) { @@ -199,7 +199,9 @@ static int converse(pam_handle_t *pamh, int ctrl, int nargs, } } else { _pam_log(LOG_ERR, "couldn't obtain coversation function [%s]", - pam_strerror(pamh, retval)); + pam_strerror(pamh, retval)); + if ( retval == PAM_SUCCESS ) + retval = PAM_BAD_ITEM; /* conv was NULL */ } return retval; /* propagate error status */ @@ -258,12 +260,12 @@ static int distdifferent(const char *old, const char *new, int i, int j) { char c, d; - if ((i == 0) || (strlen(old) <= i)) { + if ((i == 0) || (strlen(old) < i)) { c = 0; } else { c = old[i - 1]; } - if ((j == 0) || (strlen(new) <= i)) { + if ((j == 0) || (strlen(new) < j)) { d = 0; } else { d = new[j - 1]; @@ -389,17 +391,17 @@ static int simple(struct cracklib_options *opt, size -= digits; else if (digits < opt->dig_credit * -1) return 1; - + if (opt->up_credit >= 0) size -= uppers; else if (uppers < opt->up_credit * -1) return 1; - + if (opt->low_credit >= 0) size -= lowers; else if (lowers < opt->low_credit * -1) return 1; - + if (opt->oth_credit >= 0) size -= others; else if (others < opt->oth_credit * -1) @@ -507,7 +509,7 @@ static int _pam_unix_approve_pass(pam_handle_t *pamh, const char *msg = NULL; const char *user; int retval; - + if (pass_new == NULL || (pass_old && !strcmp(pass_old,pass_new))) { if (ctrl && PAM_DEBUG_ARG) _pam_log(LOG_DEBUG, "bad authentication token"); @@ -524,7 +526,7 @@ static int _pam_unix_approve_pass(pam_handle_t *pamh, msg = password_check(opt, pass_old,pass_new); if (!msg) { retval = pam_get_item(pamh, PAM_USER, (const void **)&user); - if (retval != PAM_SUCCESS) { + if (retval != PAM_SUCCESS || user == NULL) { if (ctrl & PAM_DEBUG_ARG) { _pam_log(LOG_ERR,"Can not get username"); return PAM_AUTHTOK_ERR; @@ -535,7 +537,7 @@ static int _pam_unix_approve_pass(pam_handle_t *pamh, if (msg) { char remark[BUFSIZ]; - + memset(remark,0,sizeof(remark)); snprintf(remark,sizeof(remark),"BAD PASSWORD: %s",msg); if (ctrl && PAM_DEBUG_ARG) @@ -543,12 +545,12 @@ static int _pam_unix_approve_pass(pam_handle_t *pamh, msg); make_remark(pamh, ctrl, PAM_ERROR_MSG, remark); return PAM_AUTHTOK_ERR; - }; + }; return PAM_SUCCESS; - + } -/* The Main Thing (by Cristian Gafton, CEO at this module :-) +/* The Main Thing (by Cristian Gafton, CEO at this module :-) * (stolen from http://home.netscape.com) */ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, @@ -559,6 +561,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, D(("called.")); + memset(&options, 0, sizeof(options)); options.retry_times = CO_RETRY_TIMES; options.diff_ok = CO_DIFF_OK; options.diff_ignore = CO_DIFF_IGNORE; @@ -574,7 +577,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, ctrl = _pam_parse(&options, argc, argv); if (flags & PAM_PRELIM_CHECK) { - /* Check for passwd dictionary */ + /* Check for passwd dictionary */ struct stat st; char buf[sizeof(CRACKLIB_DICTPATH)+10]; @@ -591,7 +594,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, CRACKLIB_DICTPATH); return PAM_ABORT; } - + /* Not reached */ return PAM_SERVICE_ERR; @@ -613,12 +616,12 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, retval = PAM_SUCCESS; } - do { + do { /* * make sure nothing inappropriate gets returned */ token1 = token2 = NULL; - + if (!options.retry_times) { D(("returning %s because maxtries reached", pam_strerror(pamh, retval))); @@ -628,7 +631,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, /* Planned modus operandi: * Get a passwd. * Verify it against cracklib. - * If okay get it a second time. + * If okay get it a second time. * Check to be the same with the first one. * set PAM_AUTHTOK and return */ @@ -691,7 +694,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, { char *crack_msg; char remark[BUFSIZ]; - + bzero(remark,sizeof(remark)); D(("against cracklib")); if ((crack_msg = FascistCheck(token1, cracklib_dictpath))) { @@ -779,7 +782,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, retval = PAM_AUTHTOK_RECOVER_ERR; continue; } - + /* Yes, the password was typed correct twice * we store this password as an item */ @@ -804,7 +807,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, return PAM_SUCCESS; } } - + } while (options.retry_times--); } else { @@ -814,7 +817,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, } /* Not reached */ - return PAM_SERVICE_ERR; + return PAM_SERVICE_ERR; } diff --git a/Linux-PAM/modules/pam_debug/Makefile b/Linux-PAM/modules/pam_debug/Makefile index bb759918..56e9a14e 100644 --- a/Linux-PAM/modules/pam_debug/Makefile +++ b/Linux-PAM/modules/pam_debug/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2002/09/15 20:08:45 hartmans Exp $ +# $Id: Makefile,v 1.1 2001/10/10 05:00:11 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_debug/README b/Linux-PAM/modules/pam_debug/README index c1dad0f8..85401651 100644 --- a/Linux-PAM/modules/pam_debug/README +++ b/Linux-PAM/modules/pam_debug/README @@ -1,4 +1,4 @@ -# $Id: README,v 1.1.1.1 2002/09/15 20:08:45 hartmans Exp $ +# $Id: README,v 1.1 2001/10/10 05:00:11 agmorgan Exp $ # This module returns what its module arguments tell it to return. It diff --git a/Linux-PAM/modules/pam_debug/pam_debug.c b/Linux-PAM/modules/pam_debug/pam_debug.c index 6226c829..819cd651 100644 --- a/Linux-PAM/modules/pam_debug/pam_debug.c +++ b/Linux-PAM/modules/pam_debug/pam_debug.c @@ -1,7 +1,7 @@ /* pam_permit module */ /* - * $Id: pam_debug.c,v 1.1.1.1 2002/09/15 20:08:45 hartmans Exp $ + * $Id: pam_debug.c,v 1.2 2004/09/15 12:06:17 kukuk Exp $ * * Written by Andrew Morgan <morgan@kernel.org> 2001/02/04 * @@ -102,7 +102,9 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, } if (user == NULL || *user == '\0') { D(("username not known")); - pam_set_item(pamh, PAM_USER, (const void *) DEFAULT_USER); + retval = pam_set_item(pamh, PAM_USER, (const void *) DEFAULT_USER); + if (retval != PAM_SUCCESS) + return retval; } user = NULL; /* clean up */ diff --git a/Linux-PAM/modules/pam_deny/Makefile b/Linux-PAM/modules/pam_deny/Makefile index f2a49e1d..2fdd6e11 100644 --- a/Linux-PAM/modules/pam_deny/Makefile +++ b/Linux-PAM/modules/pam_deny/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:18 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:03 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_deny/README b/Linux-PAM/modules/pam_deny/README index c6b86c79..2eb96d4e 100644 --- a/Linux-PAM/modules/pam_deny/README +++ b/Linux-PAM/modules/pam_deny/README @@ -1,4 +1,4 @@ -# $Id: README,v 1.1.1.1 2001/04/29 04:17:18 hartmans Exp $ +# $Id: README,v 1.1.1.1 2000/06/20 22:11:33 agmorgan Exp $ # this module always fails, it ignores all options. diff --git a/Linux-PAM/modules/pam_deny/pam_deny.c b/Linux-PAM/modules/pam_deny/pam_deny.c index d1fa42a3..8be1a8a8 100644 --- a/Linux-PAM/modules/pam_deny/pam_deny.c +++ b/Linux-PAM/modules/pam_deny/pam_deny.c @@ -1,7 +1,7 @@ /* pam_permit module */ /* - * $Id: pam_deny.c,v 1.1.1.1 2001/04/29 04:17:18 hartmans Exp $ + * $Id: pam_deny.c,v 1.2 2000/12/04 19:02:34 baggins Exp $ * * Written by Andrew Morgan <morgan@parc.power.net> 1996/3/11 * diff --git a/Linux-PAM/modules/pam_env/Makefile b/Linux-PAM/modules/pam_env/Makefile index 25856f04..189f1ee3 100644 --- a/Linux-PAM/modules/pam_env/Makefile +++ b/Linux-PAM/modules/pam_env/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:18 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:03 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_env/README b/Linux-PAM/modules/pam_env/README index 27d007b9..5053618a 100644 --- a/Linux-PAM/modules/pam_env/README +++ b/Linux-PAM/modules/pam_env/README @@ -1,6 +1,6 @@ -# $Date: 2001/04/29 04:17:19 $ -# $Author: hartmans $ -# $Id: README,v 1.1.1.1 2001/04/29 04:17:19 hartmans Exp $ +# $Date: 2000/06/20 22:11:33 $ +# $Author: agmorgan $ +# $Id: README,v 1.1.1.1 2000/06/20 22:11:33 agmorgan Exp $ # # This is the configuration file for pam_env, a PAM module to load in # a configurable list of environment variables for a diff --git a/Linux-PAM/modules/pam_env/pam_env.c b/Linux-PAM/modules/pam_env/pam_env.c index 2b7533d0..a3cf7684 100644 --- a/Linux-PAM/modules/pam_env/pam_env.c +++ b/Linux-PAM/modules/pam_env/pam_env.c @@ -1,7 +1,7 @@ /* pam_mail module */ /* - * $Id: pam_env.c,v 1.1.1.2 2002/09/15 20:08:46 hartmans Exp $ + * $Id: pam_env.c,v 1.5 2004/09/15 12:06:17 kukuk Exp $ * * Written by Dave Kinchlea <kinch@kinch.ark.com> 1997/01/31 * Inspired by Andrew Morgan <morgan@kernel.org>, who also supplied the @@ -13,7 +13,7 @@ #endif #define DEFAULT_ETC_ENVFILE "/etc/environment" -#define DEFAULT_READ_ENVFILE 1 +#define DEFAULT_READ_ENVFILE 0 #include <security/_pam_aconf.h> @@ -165,8 +165,8 @@ static int _parse_config_file(pam_handle_t *pamh, int ctrl, char **conffile) return PAM_IGNORE; } - /* _pam_assemble_line will provide a complete line from the config file, with all - * comments removed and any escaped newlines fixed up + /* _pam_assemble_line will provide a complete line from the config file, + * with all comments removed and any escaped newlines fixed up */ while (( retval = _assemble_line(conf, buffer, BUF_SIZE)) > 0) { @@ -192,12 +192,13 @@ static int _parse_config_file(pam_handle_t *pamh, int ctrl, char **conffile) (void) fclose(conf); /* tidy up */ - _clean_var(var); /* We could have got here prematurely, this is safe though */ + _clean_var(var); /* We could have got here prematurely, + * this is safe though */ _pam_overwrite(*conffile); _pam_drop(*conffile); file = NULL; D(("Exit.")); - return (retval<0?PAM_ABORT:PAM_SUCCESS); + return (retval != 0 ? PAM_ABORT : PAM_SUCCESS); } static int _parse_env_file(pam_handle_t *pamh, int ctrl, char **env_file) @@ -231,7 +232,7 @@ static int _parse_env_file(pam_handle_t *pamh, int ctrl, char **env_file) continue; /* skip over "export " if present so we can be compat with - bash type declerations */ + bash type declarations */ if (strncmp(key, "export ", (size_t) 7) == 0) key += 7; @@ -279,7 +280,7 @@ static int _parse_env_file(pam_handle_t *pamh, int ctrl, char **env_file) _pam_drop(*env_file); file = NULL; D(("Exit.")); - return (retval<0?PAM_IGNORE:PAM_SUCCESS); + return (retval != 0 ? PAM_IGNORE : PAM_SUCCESS); } /* @@ -765,8 +766,8 @@ int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, retval = _parse_config_file(pamh, ctrl, &conf_file); - if(readenv) - _parse_env_file(pamh, ctrl, &env_file); + if(readenv && retval == PAM_SUCCESS) + retval = _parse_env_file(pamh, ctrl, &env_file); /* indicate success or failure */ @@ -798,8 +799,8 @@ int pam_sm_open_session(pam_handle_t *pamh,int flags,int argc retval = _parse_config_file(pamh, ctrl, &conf_file); - if(readenv) - _parse_env_file(pamh, ctrl, &env_file); + if(readenv && retval == PAM_SUCCESS) + retval = _parse_env_file(pamh, ctrl, &env_file); /* indicate success or failure */ diff --git a/Linux-PAM/modules/pam_env/pam_env.conf-example b/Linux-PAM/modules/pam_env/pam_env.conf-example index fa4e0b84..612a31c2 100644 --- a/Linux-PAM/modules/pam_env/pam_env.conf-example +++ b/Linux-PAM/modules/pam_env/pam_env.conf-example @@ -1,6 +1,6 @@ -# $Date: 2001/04/29 04:17:19 $ -# $Author: hartmans $ -# $Id: pam_env.conf-example,v 1.1.1.1 2001/04/29 04:17:19 hartmans Exp $ +# $Date: 2004/11/16 14:27:41 $ +# $Author: toady $ +# $Id: pam_env.conf-example,v 1.2 2004/11/16 14:27:41 toady Exp $ # # This is the configuration file for pam_env, a PAM module to load in # a configurable list of environment variables for a @@ -43,6 +43,10 @@ # be used in values using the @{string} syntax. Both the $ and @ # characters can be backslash escaped to be used as literal values # values can be delimited with "", escaped " not supported. +# Note that many environment variables that you would like to use +# may not be set by the time the module is called. +# For example, HOME is used below several times, but +# many PAM applications don't make it available by the time you need it. # # # First, some special variables diff --git a/Linux-PAM/modules/pam_filter/Makefile b/Linux-PAM/modules/pam_filter/Makefile index caad06c7..e7d7041e 100644 --- a/Linux-PAM/modules/pam_filter/Makefile +++ b/Linux-PAM/modules/pam_filter/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.2 2002/09/15 20:08:47 hartmans Exp $ +# $Id: Makefile,v 1.4 2001/11/11 07:43:54 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_filter/README b/Linux-PAM/modules/pam_filter/README index 64bac608..12c4aeb5 100644 --- a/Linux-PAM/modules/pam_filter/README +++ b/Linux-PAM/modules/pam_filter/README @@ -1,5 +1,5 @@ # -# $Id: README,v 1.1.1.1 2001/04/29 04:17:19 hartmans Exp $ +# $Id: README,v 1.1.1.1 2000/06/20 22:11:35 agmorgan Exp $ # # This describes the behavior of this module with respect to the # /etc/pam.conf file. diff --git a/Linux-PAM/modules/pam_filter/include/pam_filter.h b/Linux-PAM/modules/pam_filter/include/pam_filter.h index f189c911..69e3a3e2 100644 --- a/Linux-PAM/modules/pam_filter/include/pam_filter.h +++ b/Linux-PAM/modules/pam_filter/include/pam_filter.h @@ -1,5 +1,5 @@ /* - * $Id: pam_filter.h,v 1.1.1.1 2001/04/29 04:17:20 hartmans Exp $ + * $Id: pam_filter.h,v 1.1.1.1 2000/06/20 22:11:36 agmorgan Exp $ * * this file is associated with the Linux-PAM filter module. * it was written by Andrew G. Morgan <morgan@linux.kernel.org> diff --git a/Linux-PAM/modules/pam_filter/pam_filter.c b/Linux-PAM/modules/pam_filter/pam_filter.c index 0ddd3711..9aa23f29 100644 --- a/Linux-PAM/modules/pam_filter/pam_filter.c +++ b/Linux-PAM/modules/pam_filter/pam_filter.c @@ -1,5 +1,5 @@ /* - * $Id: pam_filter.c,v 1.1.1.2 2002/09/15 20:08:47 hartmans Exp $ + * $Id: pam_filter.c,v 1.6 2004/11/16 14:27:41 toady Exp $ * * written by Andrew Morgan <morgan@transmeta.com> with much help from * Richard Stevens' UNIX Network Programming book. @@ -21,7 +21,7 @@ #include <sys/stat.h> #include <sys/socket.h> #include <sys/ioctl.h> -#include <termio.h> +#include <termios.h> #include <signal.h> @@ -131,7 +131,7 @@ static int process_args(pam_handle_t *pamh } else { char **levp; const char *tmp; - int i,size; + int i,size, retval; *filtername = *++argv; if (ctrl & FILTER_DEBUG) { @@ -150,7 +150,7 @@ static int process_args(pam_handle_t *pamh /* the "ARGS" variable */ -#define ARGS_OFFSET 5 /* sizeof('ARGS='); */ +#define ARGS_OFFSET 5 /* strlen('ARGS='); */ #define ARGS_NAME "ARGS=" size += ARGS_OFFSET; @@ -174,10 +174,18 @@ static int process_args(pam_handle_t *pamh /* the "SERVICE" variable */ -#define SERVICE_OFFSET 8 /* sizeof('SERVICE='); */ +#define SERVICE_OFFSET 8 /* strlen('SERVICE='); */ #define SERVICE_NAME "SERVICE=" - pam_get_item(pamh, PAM_SERVICE, (const void **)&tmp); + retval = pam_get_item(pamh, PAM_SERVICE, (const void **)&tmp); + if (retval != PAM_SUCCESS || tmp == NULL) { + _pam_log(LOG_CRIT,"service name not found"); + if (levp) { + free(levp[0]); + free(levp); + } + return -1; + } size = SERVICE_OFFSET+strlen(tmp); levp[1] = (char *) malloc(size+1); @@ -196,9 +204,10 @@ static int process_args(pam_handle_t *pamh /* the "USER" variable */ -#define USER_OFFSET 5 /* sizeof('USER='); */ +#define USER_OFFSET 5 /* strlen('USER='); */ #define USER_NAME "USER=" + tmp = NULL; pam_get_user(pamh, &tmp, NULL); if (tmp == NULL) { tmp = "<unknown>"; @@ -222,7 +231,7 @@ static int process_args(pam_handle_t *pamh /* the "USER" variable */ -#define TYPE_OFFSET 5 /* sizeof('TYPE='); */ +#define TYPE_OFFSET 5 /* strlen('TYPE='); */ #define TYPE_NAME "TYPE=" size = TYPE_OFFSET+strlen(type); @@ -278,7 +287,7 @@ static int set_filter(pam_handle_t *pamh, int flags, int ctrl { int status=-1; char terminal[TERMINAL_LEN]; - struct termio stored_mode; /* initial terminal mode settings */ + struct termios stored_mode; /* initial terminal mode settings */ int fd[2], child=0, child2=0, aterminal; if (filtername == NULL || *filtername != '/') { @@ -305,15 +314,15 @@ static int set_filter(pam_handle_t *pamh, int flags, int ctrl /* set terminal into raw mode.. remember old mode so that we can revert to it after the child has quit. */ - /* this is termio terminal handling... */ + /* this is termios terminal handling... */ - if (ioctl(STDIN_FILENO, TCGETA, (char *) &stored_mode ) < 0) { + if ( tcgetattr(STDIN_FILENO, &stored_mode) < 0 ) { /* in trouble, so close down */ close(fd[0]); _pam_log(LOG_CRIT, "couldn't copy terminal mode"); return PAM_ABORT; } else { - struct termio t_mode = stored_mode; + struct termios t_mode = stored_mode; t_mode.c_iflag = 0; /* no input control */ t_mode.c_oflag &= ~OPOST; /* no ouput post processing */ @@ -326,7 +335,7 @@ static int set_filter(pam_handle_t *pamh, int flags, int ctrl t_mode.c_cc[VMIN] = 1; /* number of chars to satisfy a read */ t_mode.c_cc[VTIME] = 0; /* 0/10th second for chars */ - if (ioctl(STDIN_FILENO, TCSETA, (char *) &t_mode) < 0) { + if ( tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_mode) < 0 ) { close(fd[0]); _pam_log(LOG_WARNING, "couldn't put terminal in RAW mode"); return PAM_ABORT; @@ -356,7 +365,7 @@ static int set_filter(pam_handle_t *pamh, int flags, int ctrl _pam_log(LOG_WARNING,"first fork failed"); if (aterminal) { - (void) ioctl(STDIN_FILENO, TCSETA, (char *) &stored_mode); + (void) tcsetattr(STDIN_FILENO, TCSAFLUSH, &stored_mode); } return PAM_AUTH_ERR; @@ -398,7 +407,7 @@ static int set_filter(pam_handle_t *pamh, int flags, int ctrl /* initialize the child's terminal to be the way the parent's was before we set it into RAW mode */ - if (ioctl(fd[1], TCSETA, (char *) &stored_mode) < 0) { + if ( tcsetattr(fd[1], TCSANOW, &stored_mode) < 0 ) { _pam_log(LOG_WARNING,"cannot set slave terminal mode; %s" ,terminal); close(fd[1]); @@ -572,7 +581,7 @@ static int set_filter(pam_handle_t *pamh, int flags, int ctrl if (aterminal) { /* reset to initial terminal mode */ - (void) ioctl(STDIN_FILENO, TCSETA, (char *) &stored_mode); + (void) tcsetattr(STDIN_FILENO, TCSANOW, &stored_mode); } if (ctrl & FILTER_DEBUG) { diff --git a/Linux-PAM/modules/pam_filter/upperLOWER/Makefile b/Linux-PAM/modules/pam_filter/upperLOWER/Makefile index 3e2d667f..c75f4964 100644 --- a/Linux-PAM/modules/pam_filter/upperLOWER/Makefile +++ b/Linux-PAM/modules/pam_filter/upperLOWER/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.2 2002/09/15 20:08:47 hartmans Exp $ +# $Id: Makefile,v 1.4 2004/09/22 09:37:47 kukuk Exp $ # # This directory contains a pam_filter filter executable # @@ -12,16 +12,19 @@ TITLE=upperLOWER # -CFLAGS += -I../include +CFLAGS += -I../include -I../../pammodutil/include OBJS = $(TITLE).o +LIBS += $(GLIB_LIBS) -L../../pammodutil -lpammodutil +LDFLAGS = $(LIBS) + ####################### don't edit below ####################### all: $(TITLE) $(TITLE): $(OBJS) - $(CC) $(CFLAGS) -o $(TITLE) $(OBJS) + $(CC) $(CFLAGS) -o $(TITLE) $(OBJS) $(LDFLAGS) $(STRIP) $(TITLE) install: diff --git a/Linux-PAM/modules/pam_filter/upperLOWER/upperLOWER.c b/Linux-PAM/modules/pam_filter/upperLOWER/upperLOWER.c index 59c0e0e3..ee3544a1 100644 --- a/Linux-PAM/modules/pam_filter/upperLOWER/upperLOWER.c +++ b/Linux-PAM/modules/pam_filter/upperLOWER/upperLOWER.c @@ -1,5 +1,5 @@ /* - * $Id: upperLOWER.c,v 1.1.1.2 2002/09/15 20:08:48 hartmans Exp $ + * $Id: upperLOWER.c,v 1.5 2004/09/22 09:37:48 kukuk Exp $ * * This is a sample filter program, for use with pam_filter (a module * provided with Linux-PAM). This filter simply transposes upper and @@ -21,6 +21,9 @@ #include <unistd.h> #include <security/pam_filter.h> +#include <security/pam_modules.h> +#include <security/_pam_macros.h> +#include <security/_pam_modutil.h> /* ---------------------------------------------------------------- */ @@ -109,27 +112,27 @@ int main(int argc, char **argv) /* application errors */ if ( FD_ISSET(APPERR_FILENO,&readers) ) { - int got = read(APPERR_FILENO, buffer, BUFSIZ); + int got = _pammodutil_read(APPERR_FILENO, buffer, BUFSIZ); if (got <= 0) { break; } else { /* translate to give to real terminal */ if (before_user != NULL) before_user(buffer, got); - if ( write(STDERR_FILENO, buffer, got) != got ) { + if (_pammodutil_write(STDERR_FILENO, buffer, got) != got ) { log_this(LOG_WARNING,"couldn't write %d bytes?!",got); break; } } } else if ( FD_ISSET(APPOUT_FILENO,&readers) ) { /* app output */ - int got = read(APPOUT_FILENO, buffer, BUFSIZ); + int got = _pammodutil_read(APPOUT_FILENO, buffer, BUFSIZ); if (got <= 0) { break; } else { /* translate to give to real terminal */ if (before_user != NULL) before_user(buffer, got); - if ( write(STDOUT_FILENO, buffer, got) != got ) { + if (_pammodutil_write(STDOUT_FILENO, buffer, got) != got ) { log_this(LOG_WARNING,"couldn't write %d bytes!?",got); break; } @@ -137,7 +140,7 @@ int main(int argc, char **argv) } if ( FD_ISSET(STDIN_FILENO, &readers) ) { /* user input */ - int got = read(STDIN_FILENO, buffer, BUFSIZ); + int got = _pammodutil_read(STDIN_FILENO, buffer, BUFSIZ); if (got < 0) { log_this(LOG_WARNING,"user input junked"); break; @@ -145,7 +148,7 @@ int main(int argc, char **argv) /* translate to give to application */ if (before_app != NULL) before_app(buffer, got); - if ( write(APPIN_FILENO, buffer, got) != got ) { + if (_pammodutil_write(APPIN_FILENO, buffer, got) != got ) { log_this(LOG_WARNING,"couldn't pass %d bytes!?",got); break; } diff --git a/Linux-PAM/modules/pam_ftp/Makefile b/Linux-PAM/modules/pam_ftp/Makefile index a1088e17..456161bf 100644 --- a/Linux-PAM/modules/pam_ftp/Makefile +++ b/Linux-PAM/modules/pam_ftp/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:21 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:03 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_ftp/pam_ftp.c b/Linux-PAM/modules/pam_ftp/pam_ftp.c index 1512a65d..64df95ac 100644 --- a/Linux-PAM/modules/pam_ftp/pam_ftp.c +++ b/Linux-PAM/modules/pam_ftp/pam_ftp.c @@ -1,7 +1,7 @@ /* pam_ftp module */ /* - * $Id: pam_ftp.c,v 1.1.1.1 2001/04/29 04:17:21 hartmans Exp $ + * $Id: pam_ftp.c,v 1.3 2004/09/22 09:37:48 kukuk Exp $ * * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 * @@ -58,7 +58,7 @@ static int converse(pam_handle_t *pamh, int nargs D(("begin to converse\n")); retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; - if ( retval == PAM_SUCCESS ) { + if ( retval == PAM_SUCCESS && conv ) { retval = conv->conv(nargs, ( const struct pam_message ** ) message , response, conv->appdata_ptr); @@ -73,6 +73,8 @@ static int converse(pam_handle_t *pamh, int nargs } else { _pam_log(LOG_ERR, "couldn't obtain coversation function [%s]" , pam_strerror(pamh, retval)); + if (retval == PAM_SUCCESS) + retval = PAM_BAD_ITEM; /* conv was NULL */ } D(("ready to return from module conversation\n")); diff --git a/Linux-PAM/modules/pam_group/Makefile b/Linux-PAM/modules/pam_group/Makefile index 11593e25..06c88998 100644 --- a/Linux-PAM/modules/pam_group/Makefile +++ b/Linux-PAM/modules/pam_group/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:21 hartmans Exp $ +# $Id: Makefile,v 1.3 2003/11/27 07:49:46 kukuk Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know @@ -11,7 +11,7 @@ TITLE=pam_group LOCAL_CONFILE=./group.conf INSTALLED_CONFILE=$(SCONFIGD)/group.conf -DEFS=-DDEFAULT_CONF_FILE=\"$(CONFILE)\" +DEFS=-DDEFAULT_CONF_FILE=\"$(INSTALLED_CONFILE)\" CFLAGS += $(DEFS) MODULE_SIMPLE_INSTALL=bash -f ../install_conf "$(FAKEROOT)" "$(SCONFIGD)" "$(INSTALLED_CONFILE)" "$(TITLE)" "$(LOCAL_CONFILE)" diff --git a/Linux-PAM/modules/pam_group/pam_group.c b/Linux-PAM/modules/pam_group/pam_group.c index b6b6ee08..c7b75fe2 100644 --- a/Linux-PAM/modules/pam_group/pam_group.c +++ b/Linux-PAM/modules/pam_group/pam_group.c @@ -1,13 +1,13 @@ /* pam_group module */ /* - * $Id: pam_group.c,v 1.1.1.2 2002/09/15 20:08:48 hartmans Exp $ + * $Id: pam_group.c,v 1.7 2004/09/24 13:13:20 kukuk Exp $ * * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/7/6 */ const static char rcsid[] = -"$Id: pam_group.c,v 1.1.1.2 2002/09/15 20:08:48 hartmans Exp $;\n" +"$Id: pam_group.c,v 1.7 2004/09/24 13:13:20 kukuk Exp $;\n" "Version 0.5 for Linux-PAM\n" "Copyright (c) Andrew G. Morgan 1996 <morgan@linux.kernel.org>\n"; @@ -57,6 +57,7 @@ typedef enum { AND, OR } operator; #include <security/pam_modules.h> #include <security/_pam_macros.h> +#include <security/_pam_modutil.h> /* --- static functions for checking whether the user should be let in --- */ @@ -79,6 +80,12 @@ static void shift_bytes(char *mem, int from, int by) } } +/* This function should initially be called with buf = NULL. If + * an error occurs, the file descriptor is closed. Subsequent + * calls with a closed descriptor will cause buf to be deallocated. + * Therefore, always check buf after calling this to see if an error + * occurred. + */ static int read_field(int fd, char **buf, int *from, int *to) { /* is buf set ? */ @@ -126,6 +133,7 @@ static int read_field(int fd, char **buf, int *from, int *to) i = read(fd, *to + *buf, PAM_GROUP_BUFLEN - *to); if (i < 0) { _log_err("error reading " PAM_GROUP_CONF); + close(fd); return -1; } else if (!i) { close(fd); @@ -165,6 +173,7 @@ static int read_field(int fd, char **buf, int *from, int *to) } else { _log_err("internal error in " __FILE__ " at line %d", __LINE__ ); + close(fd); return -1; } break; @@ -518,7 +527,7 @@ static int find_member(const char *string, int *at) #define GROUP_BLK 10 #define blk_size(len) (((len-1 + GROUP_BLK)/GROUP_BLK)*GROUP_BLK) -static int mkgrplist(char *buf, gid_t **list, int len) +static int mkgrplist(pam_handle_t *pamh, char *buf, gid_t **list, int len) { int l,at=0; int blks; @@ -581,7 +590,7 @@ static int mkgrplist(char *buf, gid_t **list, int len) { const struct group *grp; - grp = getgrnam(buf+at); + grp = _pammodutil_getgrnam(pamh, buf+at); if (grp == NULL) { _log_err("bad group: %s", buf+at); } else { @@ -600,8 +609,8 @@ static int mkgrplist(char *buf, gid_t **list, int len) } -static int check_account(const char *service, const char *tty - , const char *user) +static int check_account(pam_handle_t *pamh, const char *service, + const char *tty, const char *user) { int from=0,to=0,fd=-1; char *buffer=NULL; @@ -700,7 +709,7 @@ static int check_account(const char *service, const char *tty if (good) { D(("adding %s to gid list", buffer)); - good = mkgrplist(buffer, &grps, no_grps); + good = mkgrplist(pamh, buffer, &grps, no_grps); if (good < 0) { no_grps = 0; } else { @@ -771,7 +780,7 @@ PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags /* only interested in establishing credentials */ setting = flags; - if (!(setting & PAM_ESTABLISH_CRED)) { + if (!(setting & (PAM_ESTABLISH_CRED | PAM_REINITIALIZE_CRED))) { D(("ignoring call - not for establishing credentials")); return PAM_SUCCESS; /* don't fail because of this */ } @@ -823,7 +832,7 @@ PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags /* We initialize the pwdb library and check the account */ retval = pwdb_start(); /* initialize */ if (retval == PWDB_SUCCESS) { - retval = check_account(service,tty,user); /* get groups */ + retval = check_account(pamh, service,tty,user); /* get groups */ (void) pwdb_end(); /* tidy up */ } else { D(("failed to initialize pwdb; %s", pwdb_strerror(retval))); @@ -832,7 +841,7 @@ PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags } #else /* WANT_PWDB */ - retval = check_account(service,tty,user); /* get groups */ + retval = check_account(pamh,service,tty,user); /* get groups */ #endif /* WANT_PWDB */ return retval; diff --git a/Linux-PAM/modules/pam_issue/Makefile b/Linux-PAM/modules/pam_issue/Makefile index 1bc611af..1bd2be21 100644 --- a/Linux-PAM/modules/pam_issue/Makefile +++ b/Linux-PAM/modules/pam_issue/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:22 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:04 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_issue/pam_issue.c b/Linux-PAM/modules/pam_issue/pam_issue.c index 1f4853de..5665966e 100644 --- a/Linux-PAM/modules/pam_issue/pam_issue.c +++ b/Linux-PAM/modules/pam_issue/pam_issue.c @@ -38,7 +38,7 @@ static int _user_prompt_set = 0; -char *do_prompt (FILE *); +static char *do_prompt (FILE *); /* --- authentication management functions (only) --- */ @@ -84,12 +84,19 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, if ((fd = fopen(issue_file, "r")) != NULL) { int tot_size = 0; - if (fstat(fileno(fd), &st) < 0) + if (fstat(fileno(fd), &st) < 0) { + fclose(fd); + if (issue_file) + free(issue_file); return PAM_IGNORE; + } retval = pam_get_item(pamh, PAM_USER_PROMPT, (const void **) &cur_prompt); if (retval != PAM_SUCCESS) { + fclose(fd); + if (issue_file) + free(issue_file); return PAM_IGNORE; } if (cur_prompt == NULL) { @@ -101,6 +108,9 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, if (parse_esc) { prompt_tmp = do_prompt(fd); if (prompt_tmp == NULL) { + fclose(fd); + if (issue_file) + free(issue_file); return PAM_IGNORE; } } else { @@ -108,13 +118,17 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, prompt_tmp = malloc(st.st_size + 1); if (prompt_tmp == NULL) { + fclose(fd); + if (issue_file) + free(issue_file); return PAM_IGNORE; } memset (prompt_tmp, '\0', st.st_size + 1); - count = fread(prompt_tmp, sizeof(char *), st.st_size, fd); + count = fread(prompt_tmp, 1, st.st_size, fd); if (count != st.st_size) { - free(prompt_tmp); - return PAM_IGNORE; + fclose(fd); + retval = PAM_IGNORE; + goto cleanup; } prompt_tmp[st.st_size] = '\0'; } @@ -130,7 +144,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, { char *prompt_tmp_tmp = prompt_tmp; - prompt_tmp = realloc(prompt_tmp, tot_size); + prompt_tmp = realloc(prompt_tmp, tot_size + 1); if (prompt_tmp == NULL) { prompt_tmp = prompt_tmp_tmp; retval = PAM_IGNORE; @@ -151,6 +165,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, } else { D(("could not open issue_file: %s", issue_file)); + free(issue_file); return PAM_IGNORE; } @@ -164,14 +179,18 @@ int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, return PAM_IGNORE; } -char *do_prompt(FILE *fd) +static char *do_prompt(FILE *fd) { int c, size = 1024; - char *issue = (char *)malloc(size); + char *issue; char buf[1024]; struct utsname uts; - if (issue == NULL || fd == NULL) + if (fd == NULL) + return NULL; + + issue = (char *)malloc(size); + if (issue == NULL) return NULL; issue[0] = '\0'; /* zero this, for strcat to work on first buf */ diff --git a/Linux-PAM/modules/pam_lastlog/Makefile b/Linux-PAM/modules/pam_lastlog/Makefile index 18042b47..e8062714 100644 --- a/Linux-PAM/modules/pam_lastlog/Makefile +++ b/Linux-PAM/modules/pam_lastlog/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:22 hartmans Exp $ +# $Id: Makefile,v 1.3 2001/02/10 22:33:10 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_lastlog/pam_lastlog.c b/Linux-PAM/modules/pam_lastlog/pam_lastlog.c index 89cea3d6..c9c5e24e 100644 --- a/Linux-PAM/modules/pam_lastlog/pam_lastlog.c +++ b/Linux-PAM/modules/pam_lastlog/pam_lastlog.c @@ -1,7 +1,7 @@ /* pam_lastlog module */ /* - * $Id: pam_lastlog.c,v 1.1.1.2 2002/09/15 20:08:49 hartmans Exp $ + * $Id: pam_lastlog.c,v 1.8 2004/09/24 13:13:20 kukuk Exp $ * * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 * @@ -79,6 +79,7 @@ struct lastlog { #include <security/pam_modules.h> #include <security/_pam_macros.h> +#include <security/_pam_modutil.h> /* some syslogging */ @@ -149,7 +150,7 @@ static int converse(pam_handle_t *pamh, int ctrl, int nargs D(("begin to converse")); retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; - if ( retval == PAM_SUCCESS ) { + if ( retval == PAM_SUCCESS && conv) { retval = conv->conv(nargs, ( const struct pam_message ** ) message , response, conv->appdata_ptr); @@ -164,6 +165,8 @@ static int converse(pam_handle_t *pamh, int ctrl, int nargs } else { _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" , pam_strerror(pamh, retval)); + if (retval == PAM_SUCCESS) + retval = PAM_BAD_ITEM; /* conv was NULL */ } D(("ready to return from module conversation")); @@ -235,8 +238,8 @@ static int last_login_date(pam_handle_t *pamh, int announce, uid_t uid) sleep(LASTLOG_IGNORE_LOCK_TIME); } - win = ( read(last_fd, &last_login, sizeof(last_login)) - == sizeof(last_login) ); + win = (_pammodutil_read (last_fd, (char *) &last_login, + sizeof(last_login)) == sizeof(last_login)); last_lock.l_type = F_UNLCK; (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */ @@ -254,10 +257,12 @@ static int last_login_date(pam_handle_t *pamh, int announce, uid_t uid) if (!(announce & LASTLOG_QUIET)) { if (last_login.ll_time) { + time_t ll_time; char *the_time; char *remark; - the_time = ctime(&last_login.ll_time); + ll_time = last_login.ll_time; + the_time = ctime(&ll_time); the_time[-1+strlen(the_time)] = '\0'; /* delete '\n' */ remark = malloc(LASTLOG_MAXSIZE); @@ -319,13 +324,15 @@ static int last_login_date(pam_handle_t *pamh, int announce, uid_t uid) /* write latest value */ { + time_t ll_time; const char *remote_host=NULL , *terminal_line=DEFAULT_TERM; /* set this login date */ D(("set the most recent login time")); - (void) time(&last_login.ll_time); /* set the time */ + (void) time(&ll_time); /* set the time */ + last_login.ll_time = ll_time; /* set the remote host */ (void) pam_get_item(pamh, PAM_RHOST, (const void **)&remote_host); @@ -372,7 +379,8 @@ static int last_login_date(pam_handle_t *pamh, int announce, uid_t uid) } D(("writing to the last_log file")); - (void) write(last_fd, &last_login, sizeof(last_login)); + _pammodutil_write (last_fd, (char *) &last_login, + sizeof (last_login)); last_lock.l_type = F_UNLCK; (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */ @@ -417,7 +425,7 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc /* what uid? */ - pwd = getpwnam(user); + pwd = _pammodutil_getpwnam (pamh, user); if (pwd == NULL) { D(("couldn't identify user %s", user)); return PAM_CRED_INSUFFICIENT; diff --git a/Linux-PAM/modules/pam_limits/Makefile b/Linux-PAM/modules/pam_limits/Makefile index b7462851..d15fd9f7 100644 --- a/Linux-PAM/modules/pam_limits/Makefile +++ b/Linux-PAM/modules/pam_limits/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:22 hartmans Exp $ +# $Id: Makefile,v 1.4 2004/09/28 13:48:47 kukuk Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know @@ -21,9 +21,15 @@ CFLAGS += $(DEFS) MODULE_SIMPLE_INSTALL=bash -f ../install_conf "$(FAKEROOT)" "$(SCONFIGD)" "$(INSTALLED_CONFILE)" "$(TITLE)" "$(LOCAL_CONFILE)" MODULE_SIMPLE_REMOVE=rm -f $(FAKEROOT)$(INSTALLED_CONFILE) MODULE_SIMPLE_CLEAN=rm -f ./.ignore_age +ifeq ($(HAVE_LIBCAP),yes) +MODULE_SIMPLE_EXTRALIBS=-lcap +endif include ../Simple.Rules +#else +#include ../dont_makefile +#endif else include ../dont_makefile diff --git a/Linux-PAM/modules/pam_limits/README b/Linux-PAM/modules/pam_limits/README index 023b9575..32afb197 100644 --- a/Linux-PAM/modules/pam_limits/README +++ b/Linux-PAM/modules/pam_limits/README @@ -39,6 +39,9 @@ Where: - maxsyslogins - max number of logins on the system - priority - lower the priority by given value (value can be -ve) - locks - max locked files (Linux 2.4 and higher) + - sigpending - max number of pending signals (Linux 2.6 and higher) + - msgqueue - max memory used by POSIX message queues (bytes) + (Linux 2.6 and higher) Note, if you specify a type of '-' but neglect to supply the item and value fields then the module will never enforce any limits on the diff --git a/Linux-PAM/modules/pam_limits/limits.skel b/Linux-PAM/modules/pam_limits/limits.skel index ccb4e103..9ba31b19 100644 --- a/Linux-PAM/modules/pam_limits/limits.skel +++ b/Linux-PAM/modules/pam_limits/limits.skel @@ -30,6 +30,8 @@ # - maxlogins - max number of logins for this user # - priority - the priority to run user process with # - locks - max number of file locks the user can hold +# - sigpending - max number of pending signals +# - msgqueue - max memory used by POSIX message queues (bytes) # #<domain> <type> <item> <value> # diff --git a/Linux-PAM/modules/pam_limits/pam_limits.c b/Linux-PAM/modules/pam_limits/pam_limits.c index 6837fdef..1482833a 100644 --- a/Linux-PAM/modules/pam_limits/pam_limits.c +++ b/Linux-PAM/modules/pam_limits/pam_limits.c @@ -1,13 +1,13 @@ /* * pam_limits - impose resource limits when opening a user session * - * 1.6 - modified for PLD (added process priority settings) + * 1.6 - modified for PLD (added process priority settings) * by Marcin Korzonek <mkorz@shadow.eu.org> * 1.5 - Elliot Lee's "max system logins patch" * 1.4 - addressed bug in configuration file parser * 1.3 - modified the configuration file format * 1.2 - added 'debug' and 'conf=' arguments - * 1.1 - added @group support + * 1.1 - added @group support * 1.0 - initial release - Linux ONLY * * See end for Copyright information @@ -15,7 +15,7 @@ #if !(defined(linux)) #error THIS CODE IS KNOWN TO WORK ONLY ON LINUX !!! -#endif +#endif #include <security/_pam_aconf.h> @@ -44,17 +44,19 @@ #define LIMITS_DEF_USER 0 /* limit was set by an user entry */ #define LIMITS_DEF_GROUP 1 /* limit was set by a group entry */ -#define LIMITS_DEF_DEFAULT 2 /* limit was set by an default entry */ -#define LIMITS_DEF_NONE 3 /* this limit was not set yet */ -#define LIMITS_DEF_ALL 4 /* limit was set by an default entry */ -#define LIMITS_DEF_ALLGROUP 5 /* limit was set by a group entry */ +#define LIMITS_DEF_ALLGROUP 2 /* limit was set by a group entry */ +#define LIMITS_DEF_ALL 3 /* limit was set by an default entry */ +#define LIMITS_DEF_DEFAULT 4 /* limit was set by an default entry */ +#define LIMITS_DEF_NONE 5 /* this limit was not set yet */ static const char *limits_def_names[] = { "USER", "GROUP", + "ALLGROUP", + "ALL", "DEFAULT", "NONE", - NULL, + NULL }; struct user_limits_struct { @@ -74,6 +76,7 @@ struct pam_limit_s { struct user_limits_struct limits[RLIM_NLIMITS]; char conf_file[BUFSIZ]; int utmp_after_pam_call; + char login_group[LINE_LENGTH]; }; #define LIMIT_LOGIN RLIM_NLIMITS+1 @@ -88,6 +91,7 @@ struct pam_limit_s { #include <security/pam_modules.h> #include <security/_pam_macros.h> +#include <security/_pam_modutil.h> /* logging */ static void _pam_log(int err, const char *format, ...) @@ -145,62 +149,10 @@ static int _pam_parse(int argc, const char **argv, struct pam_limit_s *pl) #define LIMIT_ERR 1 /* error setting a limit */ #define LOGIN_ERR 2 /* too many logins err */ -/* checks if a user is on a list of members of the GID 0 group */ -static int is_on_list(char * const *list, const char *member) -{ - while (*list) { - if (strcmp(*list, member) == 0) - return 1; - list++; - } - return 0; -} - -/* - * Checks if a user is a member of a group - return non-zero if - * the user is in the group. - */ -static int is_in_group(const char *user_name, const char *group_name) -{ - struct passwd *pwd; - struct group *grp, *pgrp; - char uname[LINE_LENGTH], gname[LINE_LENGTH]; - - if (!user_name || !strlen(user_name)) - return 0; - if (!group_name || !strlen(group_name)) - return 0; - memset(uname, 0, sizeof(uname)); - strncpy(uname, user_name, sizeof(uname)-1); - memset(gname, 0, sizeof(gname)); - strncpy(gname, group_name, sizeof(gname)-1); - - pwd = getpwnam(uname); - if (!pwd) - return 0; - - /* the info about this group */ - grp = getgrnam(gname); - if (!grp) - return 0; - - /* first check: is a member of the group_name group ? */ - if (is_on_list(grp->gr_mem, uname)) - return 1; - - /* next check: user primary group is group_name ? */ - pgrp = getgrgid(pwd->pw_gid); - if (!pgrp) - return 0; - if (!strcmp(pgrp->gr_name, gname)) - return 1; - - return 0; -} - /* Counts the number of user logins and check against the limit*/ -static int check_logins(const char *name, int limit, int ctrl, - struct pam_limit_s *pl) +static int +check_logins (pam_handle_t *pamh, const char *name, int limit, int ctrl, + struct pam_limit_s *pl) { struct utmp *ut; unsigned int count; @@ -228,7 +180,7 @@ static int check_logins(const char *name, int limit, int ctrl, standard for this, since if a module wants to actually map a username then any early utmp entry will be for the unmapped name = broken.) */ - + if (ctrl & PAM_UTMP_EARLY) { count = 0; } else { @@ -252,7 +204,7 @@ static int check_logins(const char *name, int limit, int ctrl, continue; } if ((pl->login_limit_def == LIMITS_DEF_ALLGROUP) - && !is_in_group(ut->UT_USER, name)) { + && !_pammodutil_user_in_group_nam_nam(pamh, ut->UT_USER, pl->login_group)) { continue; } } @@ -300,7 +252,7 @@ static int init_limits(struct pam_limit_s *pl) pl->login_limit_def = LIMITS_DEF_NONE; return retval; -} +} static void process_limit(int source, const char *lim_type, const char *lim_item, const char *lim_value, @@ -309,9 +261,9 @@ static void process_limit(int source, const char *lim_type, int limit_item; int limit_type = 0; long limit_value; - const char **endptr = &lim_value; + char *endptr; const char *value_orig = lim_value; - + if (ctrl & PAM_DEBUG_ARG) _pam_log(LOG_DEBUG, "%s: processing %s %s %s for %s\n", __FUNCTION__,lim_type,lim_item,lim_value, @@ -341,6 +293,14 @@ static void process_limit(int source, const char *lim_type, else if (strcmp(lim_item, "locks") == 0) limit_item = RLIMIT_LOCKS; #endif +#ifdef RLIMIT_SIGPENDING + else if (strcmp(lim_item, "sigpending") == 0) + limit_item = RLIMIT_SIGPENDING; +#endif +#ifdef RLIMIT_MSGQUEUE + else if (strcmp(lim_item, "msgqueue") == 0) + limit_item = RLIMIT_MSGQUEUE; +#endif else if (strcmp(lim_item, "maxlogins") == 0) { limit_item = LIMIT_LOGIN; pl->flag_numsyslogins = 0; @@ -365,14 +325,10 @@ static void process_limit(int source, const char *lim_type, return; } - /* - * there is a warning here because the library prototype for this - * function is incorrect. - */ - limit_value = strtol(lim_value, endptr, 10); + limit_value = strtol (lim_value, &endptr, 10); /* special case value when limiting logins */ - if (limit_value == 0 && value_orig == *endptr) { /* no chars read */ + if (limit_value == 0 && value_orig == endptr) { /* no chars read */ if (strcmp(lim_value,"-") != 0) { _pam_log(LOG_DEBUG,"wrong limit value '%s'", lim_value); return; @@ -446,12 +402,12 @@ static void process_limit(int source, const char *lim_type, return; } -static int parse_config_file(const char *uname, int ctrl, +static int parse_config_file(pam_handle_t *pamh, const char *uname, int ctrl, struct pam_limit_s *pl) { FILE *fil; char buf[LINE_LENGTH]; - + #define CONF_FILE (pl->conf_file[0])?pl->conf_file:LIMITS_FILE /* check for the LIMITS_FILE */ if (ctrl & PAM_DEBUG_ARG) @@ -462,7 +418,7 @@ static int parse_config_file(const char *uname, int ctrl, return PAM_SERVICE_ERR; } #undef CONF_FILE - + /* init things */ memset(buf, 0, sizeof(buf)); /* start the show */ @@ -473,14 +429,14 @@ static int parse_config_file(const char *uname, int ctrl, char value[LINE_LENGTH]; int i,j; char *tptr; - + tptr = buf; /* skip the leading white space */ while (*tptr && isspace(*tptr)) tptr++; strncpy(buf, tptr, sizeof(buf)-1); buf[sizeof(buf)-1] = '\0'; - + /* Rip off the comments */ tptr = strchr(buf,'#'); if (tptr) @@ -499,7 +455,7 @@ static int parse_config_file(const char *uname, int ctrl, memset(ltype, 0, sizeof(ltype)); memset(item, 0, sizeof(item)); memset(value, 0, sizeof(value)); - + i = sscanf(buf,"%s%s%s%s", domain, ltype, item, value); D(("scanned line[%d]: domain[%s], ltype[%s], item[%s], value[%s]", i, domain, ltype, item, value)); @@ -521,7 +477,7 @@ static int parse_config_file(const char *uname, int ctrl, _pam_log(LOG_DEBUG, "checking if %s is in group %s", uname, domain + 1); } - if (is_in_group(uname, domain+1)) + if (_pammodutil_user_in_group_nam_nam(pamh, uname, domain+1)) process_limit(LIMITS_DEF_GROUP, ltype, item, value, ctrl, pl); } else if (domain[0]=='%') { @@ -532,9 +488,11 @@ static int parse_config_file(const char *uname, int ctrl, if (strcmp(domain,"%") == 0) process_limit(LIMITS_DEF_ALL, ltype, item, value, ctrl, pl); - else if (is_in_group(uname, domain+1)) + else if (_pammodutil_user_in_group_nam_nam(pamh, uname, domain+1)) { + strcpy(pl->login_group, domain+1); process_limit(LIMITS_DEF_ALLGROUP, ltype, item, value, ctrl, pl); + } } else if (strcmp(domain, "*") == 0) process_limit(LIMITS_DEF_DEFAULT, ltype, item, value, ctrl, pl); @@ -545,7 +503,7 @@ static int parse_config_file(const char *uname, int ctrl, } fclose(fil); return PAM_IGNORE; - } else if (domain[0] == '@' && is_in_group(uname, domain+1)) { + } else if (domain[0] == '@' && _pammodutil_user_in_group_nam_nam(pamh, uname, domain+1)) { if (ctrl & PAM_DEBUG_ARG) { _pam_log(LOG_DEBUG, "no limits for '%s' in group '%s'", uname, domain+1); @@ -558,10 +516,11 @@ static int parse_config_file(const char *uname, int ctrl, } } fclose(fil); - return PAM_SUCCESS; + return PAM_SUCCESS; } -static int setup_limits(const char * uname, uid_t uid, int ctrl, +static int setup_limits(pam_handle_t *pamh, + const char *uname, uid_t uid, int ctrl, struct pam_limit_s *pl) { int i; @@ -588,7 +547,7 @@ static int setup_limits(const char * uname, uid_t uid, int ctrl, } status |= setrlimit(i, &pl->limits[i].limit); } - + if (status) { retval = LIMIT_ERR; } @@ -601,7 +560,7 @@ static int setup_limits(const char * uname, uid_t uid, int ctrl, if (uid == 0) { D(("skip login limit check for uid=0")); } else if (pl->login_limit > 0) { - if (check_logins(uname, pl->login_limit, ctrl, pl) == LOGIN_ERR) { + if (check_logins(pamh, uname, pl->login_limit, ctrl, pl) == LOGIN_ERR) { retval |= LOGIN_ERR; } } else if (pl->login_limit == 0) { @@ -610,7 +569,7 @@ static int setup_limits(const char * uname, uid_t uid, int ctrl, return retval; } - + /* now the session stuff */ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) @@ -631,7 +590,7 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, _pam_log(LOG_CRIT, "open_session - error recovering username"); return PAM_SESSION_ERR; } - + pwd = getpwnam(user_name); if (!pwd) { if (ctrl & PAM_DEBUG_ARG) @@ -639,14 +598,14 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, user_name); return PAM_SESSION_ERR; } - + retval = init_limits(&pl); if (retval != PAM_SUCCESS) { _pam_log(LOG_WARNING, "cannot initialize"); return PAM_IGNORE; } - retval = parse_config_file(pwd->pw_name, ctrl, &pl); + retval = parse_config_file(pamh, pwd->pw_name, ctrl, &pl); if (retval == PAM_IGNORE) { D(("the configuration file has an applicable '<domain> -' entry")); return PAM_SUCCESS; @@ -659,7 +618,7 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, if (ctrl & PAM_DO_SETREUID) { setreuid(pwd->pw_uid, -1); } - retval = setup_limits(pwd->pw_name, pwd->pw_uid, ctrl, &pl); + retval = setup_limits(pamh, pwd->pw_name, pwd->pw_uid, ctrl, &pl); if (retval != LIMITED_OK) { return PAM_PERM_DENIED; } @@ -705,13 +664,13 @@ struct pam_module _pam_limits_modstruct = { * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. - * + * * ALTERNATIVELY, this product may be distributed under the terms of * the GNU Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) - * + * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE diff --git a/Linux-PAM/modules/pam_listfile/Makefile b/Linux-PAM/modules/pam_listfile/Makefile index 5a3d6957..c5447c94 100644 --- a/Linux-PAM/modules/pam_listfile/Makefile +++ b/Linux-PAM/modules/pam_listfile/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:24 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:04 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_listfile/pam_listfile.c b/Linux-PAM/modules/pam_listfile/pam_listfile.c index 934b51fb..965c471d 100644 --- a/Linux-PAM/modules/pam_listfile/pam_listfile.c +++ b/Linux-PAM/modules/pam_listfile/pam_listfile.c @@ -1,5 +1,5 @@ /* - * $Id: pam_listfile.c,v 1.1.1.2 2002/09/15 20:08:51 hartmans Exp $ + * $Id: pam_listfile.c,v 1.6 2004/09/24 13:13:20 kukuk Exp $ * */ @@ -35,9 +35,11 @@ */ #define PAM_SM_AUTH +#define PAM_SM_ACCOUNT #include <security/pam_modules.h> #include <security/_pam_macros.h> +#include <security/_pam_modutil.h> /* some syslogging */ @@ -63,45 +65,6 @@ static int is_on_list(char * const *list, const char *member) return 0; } -/* Checks if a user is a member of a group */ -static int is_on_group(const char *user_name, const char *group_name) -{ - struct passwd *pwd; - struct group *grp, *pgrp; - char uname[BUFSIZ], gname[BUFSIZ]; - - if (!strlen(user_name)) - return 0; - if (!strlen(group_name)) - return 0; - bzero(uname, sizeof(uname)); - strncpy(uname, user_name, sizeof(uname)-1); - bzero(gname, sizeof(gname)); - strncpy(gname, group_name, sizeof(gname)-1); - - pwd = getpwnam(uname); - if (!pwd) - return 0; - - /* the info about this group */ - grp = getgrnam(gname); - if (!grp) - return 0; - - /* first check: is a member of the group_name group ? */ - if (is_on_list(grp->gr_mem, uname)) - return 1; - - /* next check: user primary group is group_name ? */ - pgrp = getgrgid(pwd->pw_gid); - if (!pgrp) - return 0; - if (!strcmp(pgrp->gr_name, gname)) - return 1; - - return 0; -} - /* --- authentication management functions (only) --- */ /* Extended Items that are not directly available via pam_get_item() */ @@ -134,8 +97,6 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **ar struct group *grpinfo; char *itemlist[256]; /* Maximum of 256 items */ - D(("called.")); - apply_type=APPLY_TYPE_NULL; memset(apply_val,0,sizeof(apply_val)); @@ -258,7 +219,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **ar return PAM_IGNORE; } } else if(apply_type==APPLY_TYPE_GROUP) { - if(!is_on_group(user_name,apply_val)) { + if(!_pammodutil_user_in_group_nam_nam(pamh,user_name,apply_val)) { /* Not a member of apply= group */ #ifdef DEBUG _pam_log(LOG_DEBUG, @@ -281,8 +242,14 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **ar if (retval != PAM_SUCCESS) return PAM_SERVICE_ERR; } + if((citem == PAM_TTY) && citemp) { + /* Normalize the TTY name. */ + if(strncmp(citemp, "/dev/", 5) == 0) { + citemp += 5; + } + } - if(!citemp || (strlen(citemp) <= 0)) { + if(!citemp || (strlen(citemp) == 0)) { /* The item was NULL - we are sure not to match */ return sense?PAM_SUCCESS:PAM_AUTH_ERR; } @@ -290,13 +257,13 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **ar if(extitem) { switch(extitem) { case EI_GROUP: - userinfo = getpwnam(citemp); + userinfo = _pammodutil_getpwnam(pamh, citemp); if (userinfo == NULL) { _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "getpwnam(%s) failed", citemp); return onerr; } - grpinfo = getgrgid(userinfo->pw_gid); + grpinfo = _pammodutil_getgrgid(pamh, userinfo->pw_gid); if (grpinfo == NULL) { _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "getgrgid(%d) failed", (int)userinfo->pw_gid); @@ -317,7 +284,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **ar /* Assume that we have already gotten PAM_USER in pam_get_item() - a valid assumption since citem gets set to PAM_USER in the extitem switch */ - userinfo = getpwnam(citemp); + userinfo = _pammodutil_getpwnam(pamh, citemp); if (userinfo == NULL) { _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "getpwnam(%s) failed", citemp); @@ -371,8 +338,10 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **ar assert(PAM_AUTH_ERR != 0); #endif if(extitem == EI_GROUP) { - while((fgets(aline,255,inf) != NULL) + while((fgets(aline,sizeof(aline),inf) != NULL) && retval) { + if(strlen(aline) == 0) + continue; if(aline[strlen(aline) - 1] == '\n') aline[strlen(aline) - 1] = '\0'; for(i=0;itemlist[i];) @@ -383,11 +352,21 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **ar for(i=0;itemlist[i];) free(itemlist[i++]); } else { - while((fgets(aline,255,inf) != NULL) + while((fgets(aline,sizeof(aline),inf) != NULL) && retval) { + char *a = aline; + if(strlen(aline) == 0) + continue; if(aline[strlen(aline) - 1] == '\n') aline[strlen(aline) - 1] = '\0'; - retval = strcmp(aline,citemp); + if(strlen(aline) == 0) + continue; + if(aline[strlen(aline) - 1] == '\r') + aline[strlen(aline) - 1] = '\0'; + if(citem == PAM_TTY) + if(strncmp(a, "/dev/", 5) == 0) + a += 5; + retval = strcmp(a,citemp); } } fclose(inf); @@ -419,6 +398,13 @@ int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) return PAM_SUCCESS; } +PAM_EXTERN +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + return pam_sm_authenticate(pamh, 0, argc, argv); +} + #ifdef PAM_STATIC /* static module data */ @@ -427,13 +413,13 @@ struct pam_module _pam_listfile_modstruct = { "pam_listfile", pam_sm_authenticate, pam_sm_setcred, - NULL, + pam_sm_acct_mgmt, NULL, NULL, NULL, }; -#endif +#endif /* PAM_STATIC */ /* end of module definition */ diff --git a/Linux-PAM/modules/pam_localuser/Makefile b/Linux-PAM/modules/pam_localuser/Makefile new file mode 100644 index 00000000..3dc61aa0 --- /dev/null +++ b/Linux-PAM/modules/pam_localuser/Makefile @@ -0,0 +1,14 @@ +# $Id: Makefile,v 1.1 2004/09/24 11:49:37 kukuk Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# + +include ../../Make.Rules + +TITLE=pam_localuser +MAN8=pam_localuser.8 + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_localuser/README b/Linux-PAM/modules/pam_localuser/README new file mode 100644 index 00000000..b8cdf524 --- /dev/null +++ b/Linux-PAM/modules/pam_localuser/README @@ -0,0 +1,17 @@ +pam_localuser: + Succeeds iff the PAM_USER is listed in /etc/passwd. This seems to be a + common policy need (allowing only a subset of network-wide users, and + any locally-defined users, to access services). Simpler than using + awk to generate a file for use with pam_listfile (-F: '{print $1}'), + I guess. + +RECOGNIZED ARGUMENTS: + debug write debugging messages to syslog + file=FILE scan FILE instead of /etc/passwd + +MODULE SERVICES PROVIDED: + auth,account scan the FILE (/etc/passwd by default) and return + a success code if an entry is found for the user + +AUTHOR: + Nalin Dahyabhai <nalin@redhat.com> diff --git a/Linux-PAM/modules/pam_localuser/pam_localuser.8 b/Linux-PAM/modules/pam_localuser/pam_localuser.8 new file mode 100644 index 00000000..ce0a9465 --- /dev/null +++ b/Linux-PAM/modules/pam_localuser/pam_localuser.8 @@ -0,0 +1,36 @@ +.\" Copyright 2000 Red Hat, Inc. +.TH pam_localuser 8 2000/7/21 "Red Hat" "System Administrator's Manual" + +.SH NAME +pam_localuser \- require users to be listed in /etc/passwd + +.SH SYNOPSIS +.B account sufficient /lib/security/pam_localuser.so \fIargs\fP +.br +.B account required /lib/security/pam_wheel.so group=devel + +.SH DESCRIPTION +pam_localuser.so exists to help implement site-wide login policies, where +they typically include a subset of the network's users and a few accounts +that are local to a particular workstation. Using pam_localuser.so and +pam_wheel.so or pam_listfile.so is an effective way to restrict access to +either local users and/or a subset of the network's users. + +This could also be implemented using pam_listfile.so and a very short awk +script invoked by cron, but it's common enough to have been separated out. + +.SH ARGUMENTS +.IP debug +turns on debugging +.IP file=\fBFILE\fP +uses a file other than \fB/etc/passwd\fP. + +.SH FILES +/etc/passwd + +.SH BUGS +Let's hope not, but if you find any, please report them via the "Bug Track" +link at http://bugzilla.redhat.com/bugzilla/ + +.SH AUTHOR +Nalin Dahyabhai <nalin@redhat.com> diff --git a/Linux-PAM/modules/pam_localuser/pam_localuser.c b/Linux-PAM/modules/pam_localuser/pam_localuser.c new file mode 100644 index 00000000..e5496089 --- /dev/null +++ b/Linux-PAM/modules/pam_localuser/pam_localuser.c @@ -0,0 +1,159 @@ +/* + * Copyright 2001, 2004 Red Hat, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "../../_pam_aconf.h" + +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <stdio.h> +#include <stdarg.h> +#include <time.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +#include "../../libpam/include/security/pam_modules.h" +#include "../../libpam/include/security/_pam_macros.h" + +#define MODULE_NAME "pam_localuser" + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + int i, ret = PAM_SUCCESS; + FILE *fp; + int debug = 0; + const char *filename = "/etc/passwd"; + char line[LINE_MAX], name[LINE_MAX]; + const char* user; + + /* process arguments */ + for(i = 0; i < argc; i++) { + if(strcmp("debug", argv[i]) == 0) { + debug = 1; + } + } + for(i = 0; i < argc; i++) { + if(strncmp("file=", argv[i], 5) == 0) { + filename = argv[i] + 5; + if(debug) { + openlog(MODULE_NAME, LOG_PID, LOG_AUTHPRIV); + syslog(LOG_DEBUG, "set filename to \"%s\"", + filename); + closelog(); + } + } + } + + /* open the file */ + fp = fopen(filename, "r"); + if(fp == NULL) { + openlog(MODULE_NAME, LOG_PID, LOG_AUTHPRIV); + syslog(LOG_ERR, "error opening \"%s\": %s", filename, + strerror(errno)); + closelog(); + return PAM_SYSTEM_ERR; + } + + if(pam_get_user(pamh, &user, NULL) != PAM_SUCCESS) { + openlog(MODULE_NAME, LOG_PID, LOG_AUTHPRIV); + syslog(LOG_ERR, "user name not specified yet"); + closelog(); + fclose(fp); + return PAM_SYSTEM_ERR; + } + + if ((user == NULL) || (strlen(user) == 0)) { + openlog(MODULE_NAME, LOG_PID, LOG_AUTHPRIV); + syslog(LOG_ERR, "user name not valid"); + closelog(); + fclose(fp); + return PAM_SYSTEM_ERR; + } + + /* scan the file, using fgets() instead of fgetpwent() because i + * don't want to mess with applications which call fgetpwent() */ + ret = PAM_PERM_DENIED; + snprintf(name, sizeof(name), "%s:", user); + i = strlen(name); + while(fgets(line, sizeof(line), fp) != NULL) { + if(debug) { + openlog(MODULE_NAME, LOG_PID, LOG_AUTHPRIV); + syslog(LOG_DEBUG, "checking \"%s\"", line); + closelog(); + } + if(strncmp(name, line, i) == 0) { + ret = PAM_SUCCESS; + break; + } + } + + /* okay, we're done */ + fclose(fp); + return ret; +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + return PAM_SUCCESS; +} + +PAM_EXTERN +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + return pam_sm_authenticate(pamh, flags, argc, argv); +} + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_localuser_modstruct = { + "pam_localuser", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + NULL, + NULL, + NULL, +}; + +#endif diff --git a/Linux-PAM/modules/pam_mail/Makefile b/Linux-PAM/modules/pam_mail/Makefile index d5e5c44a..2d9b8e9a 100644 --- a/Linux-PAM/modules/pam_mail/Makefile +++ b/Linux-PAM/modules/pam_mail/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:24 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:04 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_mail/pam_mail.c b/Linux-PAM/modules/pam_mail/pam_mail.c index d63e79b1..7987cb28 100644 --- a/Linux-PAM/modules/pam_mail/pam_mail.c +++ b/Linux-PAM/modules/pam_mail/pam_mail.c @@ -1,7 +1,7 @@ /* pam_mail module */ /* - * $Id: pam_mail.c,v 1.1.1.1 2001/04/29 04:17:24 hartmans Exp $ + * $Id: pam_mail.c,v 1.6 2004/11/16 14:27:41 toady Exp $ * * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 * $HOME additions by David Kinchlea <kinch@kinch.ark.com> 1997/1/7 @@ -32,7 +32,7 @@ #define MAIL_ENV_FORMAT MAIL_ENV_NAME "=%s" #define YOUR_MAIL_VERBOSE_FORMAT "You have %s mail in %s." #define YOUR_MAIL_STANDARD_FORMAT "You have %smail." -#define NO_MAIL_STANDARD_FORMAT "No mail." +#define NO_MAIL_STANDARD_FORMAT "No mail." /* * here, we make a definition for the externally accessible function @@ -46,6 +46,7 @@ #include <security/pam_modules.h> #include <security/_pam_macros.h> +#include <security/_pam_modutil.h> /* some syslogging */ @@ -142,8 +143,8 @@ static int converse(pam_handle_t *pamh, int ctrl, int nargs D(("begin to converse")); - retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; - if ( retval == PAM_SUCCESS ) { + retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; + if ( retval == PAM_SUCCESS && conv ) { retval = conv->conv(nargs, ( const struct pam_message ** ) message , response, conv->appdata_ptr); @@ -158,6 +159,8 @@ static int converse(pam_handle_t *pamh, int ctrl, int nargs } else { _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" , pam_strerror(pamh, retval)); + if (retval == PAM_SUCCESS) + retval = PAM_BAD_ITEM; /* conv was NULL */ } D(("ready to return from module conversation")); @@ -182,7 +185,7 @@ static int get_folder(pam_handle_t *pamh, int ctrl, if (ctrl & PAM_NEW_MAIL_DIR) { path = *path_mail; if (*path == '~') { /* support for $HOME delivery */ - pwd = getpwnam(user); + pwd = _pammodutil_getpwnam(pamh, user); if (pwd == NULL) { _log_err(LOG_ERR, "user [%s] unknown", user); _pam_overwrite(*path_mail); @@ -234,7 +237,9 @@ static int get_folder(pam_handle_t *pamh, int ctrl, _pam_overwrite(hash); _pam_drop(hash); } else { - sprintf(folder, "error"); + _pam_drop(folder); + _log_err(LOG_CRIT, "out of memory for mail folder"); + return PAM_BUF_ERR; } } D(("folder =[%s]", folder)); @@ -386,7 +391,7 @@ PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc ,const char **argv) { - return _do_mail(pamh,flags,argc,argv,0);; + return _do_mail(pamh,flags,argc,argv,0); } /* Checking mail as part of the session management */ @@ -467,9 +472,9 @@ static int _do_mail(pam_handle_t *pamh, int flags, int argc, type = NULL; } } - - /* Delete environment variable? */ - if (!est) + + /* Delete environment variable? */ + if ( ! est && ! (ctrl & PAM_NO_ENV) ) (void) pam_putenv(pamh, MAIL_ENV_NAME); _pam_overwrite(folder); /* clean up */ diff --git a/Linux-PAM/modules/pam_mkhomedir/Makefile b/Linux-PAM/modules/pam_mkhomedir/Makefile index 14802d55..f017f4a4 100644 --- a/Linux-PAM/modules/pam_mkhomedir/Makefile +++ b/Linux-PAM/modules/pam_mkhomedir/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:25 hartmans Exp $ +# $Id: Makefile,v 1.3 2000/11/19 23:54:04 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_mkhomedir/README b/Linux-PAM/modules/pam_mkhomedir/README new file mode 100644 index 00000000..2a3e705e --- /dev/null +++ b/Linux-PAM/modules/pam_mkhomedir/README @@ -0,0 +1,25 @@ +PAM Make Home Dir module + +This module will create a users home directory if it does not exist +when the session begins. This allows users to be present in central +database (such as nis, kerb or ldap) without using a distributed +file system or pre-creating a large number of directories. + +Here is a sample /etc/pam.d/login file: + + auth requisite pam_securetty.so + auth sufficient pam_ldap.so + auth required pam_unix.so + auth optional pam_group.so + auth optional pam_mail.so + account requisite pam_time.so + account sufficient pam_ldap.so + account required pam_unix.so + session required pam_mkhomedir.so skel=/etc/skel/ umask=0022 + session required pam_unix.so + session optional pam_lastlog.so + password required pam_unix.so + +Released under the GNU LGPL version 2 or later +Originally written by Jason Gunthorpe <jgg@debian.org> Feb 1999 + diff --git a/Linux-PAM/modules/pam_mkhomedir/pam_mkhomedir.c b/Linux-PAM/modules/pam_mkhomedir/pam_mkhomedir.c index 9a4640dd..f63177bf 100644 --- a/Linux-PAM/modules/pam_mkhomedir/pam_mkhomedir.c +++ b/Linux-PAM/modules/pam_mkhomedir/pam_mkhomedir.c @@ -4,10 +4,10 @@ when the session begins. This allows users to be present in central database (such as nis, kerb or ldap) without using a distributed file system or pre-creating a large number of directories. - + Here is a sample /etc/pam.d/login file for Debian GNU/Linux 2.1: - + auth requisite pam_securetty.so auth sufficient pam_ldap.so auth required pam_pwdb.so @@ -19,11 +19,11 @@ session required pam_mkhomedir.so skel=/etc/skel/ umask=0022 session required pam_pwdb.so session optional pam_lastlog.so - password required pam_pwdb.so - + password required pam_pwdb.so + Released under the GNU LGPL version 2 or later Originally written by Jason Gunthorpe <jgg@debian.org> Feb 1999 - Structure taken from pam_lastlogin by Andrew Morgan + Structure taken from pam_lastlogin by Andrew Morgan <morgan@parc.power.net> 1996 */ @@ -51,6 +51,8 @@ #include <security/pam_modules.h> #include <security/_pam_macros.h> +#include <security/_pam_modutil.h> + /* argument parsing */ #define MKHOMEDIR_DEBUG 020 /* keep quiet about things */ @@ -98,8 +100,8 @@ static int _pam_parse(int flags, int argc, const char **argv) return ctrl; } -/* This common function is used to send a message to the applications - conversion function. Our only use is to ask the application to print +/* This common function is used to send a message to the applications + conversion function. Our only use is to ask the application to print an informative message that we are creating a home directory */ static int converse(pam_handle_t * pamh, int ctrl, int nargs ,struct pam_message **message @@ -111,7 +113,7 @@ static int converse(pam_handle_t * pamh, int ctrl, int nargs D(("begin to converse")); retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); - if (retval == PAM_SUCCESS) + if (retval == PAM_SUCCESS && conv) { retval = conv->conv(nargs, (const struct pam_message **) message @@ -130,6 +132,8 @@ static int converse(pam_handle_t * pamh, int ctrl, int nargs { _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" ,pam_strerror(pamh, retval)); + if (retval == PAM_SUCCESS) + retval = PAM_BAD_ITEM; /* conv was NULL */ } D(("ready to return from module conversation")); @@ -187,9 +191,9 @@ static int create_homedir(pam_handle_t * pamh, int ctrl, /* Create the new directory */ if (mkdir(dest,0700) != 0) { - _log_err(LOG_DEBUG, "unable to create directory %s",source); + _log_err(LOG_DEBUG, "unable to create directory %s",dest); return PAM_PERM_DENIED; - } + } if (chmod(dest,0777 & (~UMask)) != 0 || chown(dest,pwd->pw_uid,pwd->pw_gid) != 0) { @@ -212,12 +216,19 @@ static int create_homedir(pam_handle_t * pamh, int ctrl, } for (Dir = readdir(D); Dir != 0; Dir = readdir(D)) - { + { int SrcFd; int DestFd; int Res; struct stat St; +#ifndef PATH_MAX + char *newsource = NULL, *newdest = NULL; + /* track length of buffers */ + int nslen = 0, ndlen = 0; + int slen = strlen(source), dlen = strlen(dest); +#else char newsource[PATH_MAX], newdest[PATH_MAX]; +#endif /* Skip some files.. */ if (strcmp(Dir->d_name,".") == 0 || @@ -225,37 +236,124 @@ static int create_homedir(pam_handle_t * pamh, int ctrl, continue; /* Determine what kind of file it is. */ +#ifndef PATH_MAX + nslen = slen + strlen(Dir->d_name) + 2; + + if (nslen <= 0) + return PAM_BUF_ERR; + + if ( (newsource = malloc(nslen)) == NULL ) + return PAM_BUF_ERR; + + sprintf(newsource, "%s/%s", source, Dir->d_name); +#else snprintf(newsource,sizeof(newsource),"%s/%s",source,Dir->d_name); +#endif + if (lstat(newsource,&St) != 0) +#ifndef PATH_MAX + { + free(newsource); + newsource = NULL; continue; + } +#else + continue; +#endif + /* We'll need the new file's name. */ +#ifndef PATH_MAX + ndlen = dlen + strlen(Dir->d_name)+2; + + if (ndlen <= 0) + return PAM_BUF_ERR; + + if ( (newdest = malloc(ndlen)) == NULL ) { + free(newsource); + return PAM_BUF_ERR; + } + + sprintf(newdest, "%s/%s", dest, Dir->d_name); +#else snprintf(newdest,sizeof(newdest),"%s/%s",dest,Dir->d_name); +#endif /* If it's a directory, recurse. */ if (S_ISDIR(St.st_mode)) { - create_homedir(pamh, ctrl, pwd, newsource, newdest); + int retval = create_homedir(pamh, ctrl, pwd, newsource, newdest); + +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif + + if (retval != PAM_SUCCESS) { + closedir(D); + return retval; + } continue; } /* If it's a symlink, create a new link. */ if (S_ISLNK(St.st_mode)) { + int pointedlen = 0; +#ifndef PATH_MAX + char *pointed = NULL; + { + int size = 100; + + while (1) { + pointed = (char *) malloc(size); + if ( ! pointed ) { + free(newsource); + free(newdest); + return PAM_BUF_ERR; + } + pointedlen = readlink (newsource, pointed, size); + if ( pointedlen < 0 ) break; + if ( pointedlen < size ) break; + free (pointed); + size *= 2; + } + } + if ( pointedlen < 0 ) + free(pointed); + else + pointed[pointedlen] = 0; +#else char pointed[PATH_MAX]; memset(pointed, 0, sizeof(pointed)); - if(readlink(newsource, pointed, sizeof(pointed) - 1) != -1) - { + + pointedlen = readlink(newsource, pointed, sizeof(pointed) - 1); +#endif + + if ( pointedlen >= 0 ) { if(symlink(pointed, newdest) == 0) { if (lchown(newdest,pwd->pw_uid,pwd->pw_gid) != 0) { - _log_err(LOG_DEBUG, "unable to chang perms on link %s", + closedir(D); + _log_err(LOG_DEBUG, "unable to change perms on link %s", newdest); +#ifndef PATH_MAX + free(pointed); + free(newsource); + free(newdest); +#endif return PAM_PERM_DENIED; } } +#ifndef PATH_MAX + free(pointed); +#endif } +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif continue; } @@ -263,13 +361,24 @@ static int create_homedir(pam_handle_t * pamh, int ctrl, * the new device node, FIFO, or whatever it is. */ if (!S_ISREG(St.st_mode)) { +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif continue; } /* Open the source file */ if ((SrcFd = open(newsource,O_RDONLY)) < 0 || fstat(SrcFd,&St) != 0) { + closedir(D); _log_err(LOG_DEBUG, "unable to open src file %s",newsource); + +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif + return PAM_PERM_DENIED; } stat(newsource,&St); @@ -278,7 +387,13 @@ static int create_homedir(pam_handle_t * pamh, int ctrl, if ((DestFd = open(newdest,O_WRONLY | O_TRUNC | O_CREAT,0600)) < 0) { close(SrcFd); + closedir(D); _log_err(LOG_DEBUG, "unable to open dest file %s",newdest); + +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif return PAM_PERM_DENIED; } @@ -290,26 +405,55 @@ static int create_homedir(pam_handle_t * pamh, int ctrl, { close(SrcFd); close(DestFd); + closedir(D); _log_err(LOG_DEBUG, "unable to chang perms on copy %s",newdest); + +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif + return PAM_PERM_DENIED; } /* Copy the file */ do { - Res = read(SrcFd,remark,sizeof(remark)); - if (Res < 0 || write(DestFd,remark,Res) != Res) - { - close(SrcFd); - close(DestFd); - _log_err(LOG_DEBUG, "unable to perform IO"); - return PAM_PERM_DENIED; + Res = _pammodutil_read(SrcFd,remark,sizeof(remark)); + + if (Res == 0) + continue; + + if (Res > 0) { + if (_pammodutil_write(DestFd,remark,Res) == Res) + continue; } + + /* If we get here, pammodutil_read returned a -1 or + _pammodutil_write returned something unexpected. */ + close(SrcFd); + close(DestFd); + closedir(D); + _log_err(LOG_DEBUG, "unable to perform IO"); + +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif + + return PAM_PERM_DENIED; } while (Res != 0); close(SrcFd); close(DestFd); + +#ifndef PATH_MAX + free(newsource); newsource = NULL; + free(newdest); newdest = NULL; +#endif + } + closedir(D); return PAM_SUCCESS; } @@ -324,7 +468,7 @@ int pam_sm_open_session(pam_handle_t * pamh, int flags, int argc const char *user; const struct passwd *pwd; struct stat St; - + /* Parse the flag values */ ctrl = _pam_parse(flags, argc, argv); @@ -337,7 +481,7 @@ int pam_sm_open_session(pam_handle_t * pamh, int flags, int argc } /* Get the password entry */ - pwd = getpwnam(user); + pwd = _pammodutil_getpwnam (pamh, user); if (pwd == NULL) { D(("couldn't identify user %s", user)); @@ -353,7 +497,7 @@ int pam_sm_open_session(pam_handle_t * pamh, int flags, int argc } /* Ignore */ -PAM_EXTERN +PAM_EXTERN int pam_sm_close_session(pam_handle_t * pamh, int flags, int argc ,const char **argv) { diff --git a/Linux-PAM/modules/pam_motd/Makefile b/Linux-PAM/modules/pam_motd/Makefile index ad6a2497..fb83807a 100644 --- a/Linux-PAM/modules/pam_motd/Makefile +++ b/Linux-PAM/modules/pam_motd/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:26 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:04 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_motd/pam_motd.c b/Linux-PAM/modules/pam_motd/pam_motd.c index 931dfd10..ce695f92 100644 --- a/Linux-PAM/modules/pam_motd/pam_motd.c +++ b/Linux-PAM/modules/pam_motd/pam_motd.c @@ -4,7 +4,7 @@ * Modified for pam_motd by Ben Collins <bcollins@debian.org> * * Based off of: - * $Id: pam_motd.c,v 1.1.1.2 2002/09/15 20:08:52 hartmans Exp $ + * $Id: pam_motd.c,v 1.3 2004/09/22 09:37:49 kukuk Exp $ * * Written by Michael K. Johnson <johnsonm@redhat.com> 1996/10/24 * @@ -33,6 +33,7 @@ #define DEFAULT_MOTD "/etc/motd" #include <security/pam_modules.h> +#include <security/_pam_modutil.h> /* --- session management functions (only) --- */ @@ -80,24 +81,33 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, if ((fd = open(motd_path, O_RDONLY, 0)) >= 0) { /* fill in message buffer with contents of motd */ - if ((fstat(fd, &st) < 0) || !st.st_size) + if ((fstat(fd, &st) < 0) || !st.st_size) { + close(fd); return retval; + } message.msg = mtmp = malloc(st.st_size+1); /* if malloc failed... */ - if (!message.msg) return retval; - read(fd, mtmp, st.st_size); - if (mtmp[st.st_size-1] == '\n') - mtmp[st.st_size-1] = '\0'; - else - mtmp[st.st_size] = '\0'; - close(fd); - /* Use conversation function to give user contents of motd */ - pam_get_item(pamh, PAM_CONV, (const void **)&conversation); - conversation->conv(1, (const struct pam_message **)&pmessage, - &resp, conversation->appdata_ptr); + if (!message.msg) { + close(fd); + return retval; + } + if (_pammodutil_read(fd, mtmp, st.st_size) == st.st_size) { + if (mtmp[st.st_size-1] == '\n') + mtmp[st.st_size-1] = '\0'; + else + mtmp[st.st_size] = '\0'; + close(fd); + + /* Use conversation function to give user contents of motd */ + if (pam_get_item(pamh, PAM_CONV, (const void **)&conversation) == + PAM_SUCCESS && conversation) { + conversation->conv(1, (const struct pam_message **)&pmessage, + &resp, conversation->appdata_ptr); + if (resp) + _pam_drop_reply(resp, 1); + } + } free(mtmp); - if (resp) - _pam_drop_reply(resp, 1); } return retval; diff --git a/Linux-PAM/modules/pam_nologin/Makefile b/Linux-PAM/modules/pam_nologin/Makefile index 494d2909..2ad38ffd 100644 --- a/Linux-PAM/modules/pam_nologin/Makefile +++ b/Linux-PAM/modules/pam_nologin/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:26 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:04 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_nologin/README b/Linux-PAM/modules/pam_nologin/README index 5f7d6ced..5de704c3 100644 --- a/Linux-PAM/modules/pam_nologin/README +++ b/Linux-PAM/modules/pam_nologin/README @@ -1,4 +1,4 @@ -# $Id: README,v 1.1.1.2 2002/09/15 20:08:52 hartmans Exp $ +# $Id: README,v 1.2 2002/06/27 05:43:28 agmorgan Exp $ # This module always lets root in; it lets other users in only if the file diff --git a/Linux-PAM/modules/pam_nologin/pam_nologin.c b/Linux-PAM/modules/pam_nologin/pam_nologin.c index ea5d86e9..8e7e124a 100644 --- a/Linux-PAM/modules/pam_nologin/pam_nologin.c +++ b/Linux-PAM/modules/pam_nologin/pam_nologin.c @@ -1,7 +1,7 @@ /* pam_nologin module */ /* - * $Id: pam_nologin.c,v 1.1.1.2 2002/09/15 20:08:53 hartmans Exp $ + * $Id: pam_nologin.c,v 1.6 2005/01/07 15:31:26 t8m Exp $ * * Written by Michael K. Johnson <johnsonm@redhat.com> 1996/10/24 * @@ -24,6 +24,7 @@ */ #define PAM_SM_AUTH +#define PAM_SM_ACCOUNT #include <security/pam_modules.h> @@ -116,21 +117,29 @@ static int perform_check(pam_handle_t *pamh, struct opt_s *opts) goto clean_up_fd; } - read(fd, mtmp, st.st_size); - mtmp[st.st_size] = '\000'; + if (_pammodutil_read(fd, mtmp, st.st_size) == st.st_size) { + mtmp[st.st_size] = '\000'; - /* - * Use conversation function to give user contents of /etc/nologin - */ + /* + * Use conversation function to give user contents + * of /etc/nologin + */ - pam_get_item(pamh, PAM_CONV, (const void **)&conversation); - (void) conversation->conv(1, (const struct pam_message **)&pmessage, - &resp, conversation->appdata_ptr); - free(mtmp); + if (pam_get_item(pamh, PAM_CONV, (const void **)&conversation) + == PAM_SUCCESS && conversation && conversation->conv) { + (void) conversation->conv(1, + (const struct pam_message **)&pmessage, + &resp, conversation->appdata_ptr); - if (resp) { - _pam_drop_reply(resp, 1); + if (resp) { + _pam_drop_reply(resp, 1); + } + } } + else + retval = PAM_SYSTEM_ERR; + + free(mtmp); clean_up_fd: @@ -192,6 +201,6 @@ struct pam_module _pam_nologin_modstruct = { NULL, }; -#endif +#endif /* PAM_STATIC */ /* end of module definition */ diff --git a/Linux-PAM/modules/pam_permit/Makefile b/Linux-PAM/modules/pam_permit/Makefile index 23835be4..49f3b3dd 100644 --- a/Linux-PAM/modules/pam_permit/Makefile +++ b/Linux-PAM/modules/pam_permit/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:26 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:04 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_permit/README b/Linux-PAM/modules/pam_permit/README index 15d95942..52e7364e 100644 --- a/Linux-PAM/modules/pam_permit/README +++ b/Linux-PAM/modules/pam_permit/README @@ -1,4 +1,4 @@ -# $Id: README,v 1.1.1.1 2001/04/29 04:17:26 hartmans Exp $ +# $Id: README,v 1.1.1.1 2000/06/20 22:11:46 agmorgan Exp $ # this module always returns PAM_SUCCESS, it ignores all options. diff --git a/Linux-PAM/modules/pam_permit/pam_permit.c b/Linux-PAM/modules/pam_permit/pam_permit.c index 1041ca84..08d464b8 100644 --- a/Linux-PAM/modules/pam_permit/pam_permit.c +++ b/Linux-PAM/modules/pam_permit/pam_permit.c @@ -1,7 +1,7 @@ /* pam_permit module */ /* - * $Id: pam_permit.c,v 1.1.1.1 2001/04/29 04:17:26 hartmans Exp $ + * $Id: pam_permit.c,v 1.3 2004/09/22 09:37:49 kukuk Exp $ * * Written by Andrew Morgan <morgan@parc.power.net> 1996/3/11 * @@ -45,7 +45,9 @@ int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc } if (user == NULL || *user == '\0') { D(("username not known")); - pam_set_item(pamh, PAM_USER, (const void *) DEFAULT_USER); + retval = pam_set_item(pamh, PAM_USER, (const void *) DEFAULT_USER); + if (retval != PAM_SUCCESS) + return PAM_USER_UNKNOWN; } user = NULL; /* clean up */ diff --git a/Linux-PAM/modules/pam_pwdb/BUGS b/Linux-PAM/modules/pam_pwdb/BUGS index 7258822c..d51686e5 100644 --- a/Linux-PAM/modules/pam_pwdb/BUGS +++ b/Linux-PAM/modules/pam_pwdb/BUGS @@ -1,3 +1,3 @@ -$Id: BUGS,v 1.1.1.1 2001/04/29 04:17:27 hartmans Exp $ +$Id: BUGS,v 1.2 2000/12/04 19:02:34 baggins Exp $ As of Linux-PAM-0.52 this is new. No known bugs yet. diff --git a/Linux-PAM/modules/pam_pwdb/CHANGELOG b/Linux-PAM/modules/pam_pwdb/CHANGELOG index 78c1a239..a3614031 100644 --- a/Linux-PAM/modules/pam_pwdb/CHANGELOG +++ b/Linux-PAM/modules/pam_pwdb/CHANGELOG @@ -1,4 +1,4 @@ -$Id: CHANGELOG,v 1.1.1.1 2001/04/29 04:17:27 hartmans Exp $ +$Id: CHANGELOG,v 1.1.1.1 2000/06/20 22:11:46 agmorgan Exp $ Tue Apr 23 12:28:09 EDT 1996 (Alexander O. Yuriev alex@bach.cis.temple.edu) diff --git a/Linux-PAM/modules/pam_pwdb/Makefile b/Linux-PAM/modules/pam_pwdb/Makefile index bce2950f..228c6704 100644 --- a/Linux-PAM/modules/pam_pwdb/Makefile +++ b/Linux-PAM/modules/pam_pwdb/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:27 hartmans Exp $ +# $Id: Makefile,v 1.3 2004/09/28 13:48:47 kukuk Exp $ # # This Makefile controls a build process of the pam_unix module # for Linux-PAM. You should not modify this Makefile. @@ -17,6 +17,9 @@ EXTRAS += -DCHKPWD_HELPER=\"$(SUPLEMENTED)/$(CHKPWD)\" ifeq ($(HAVE_LIBCRYPT),yes) EXTRALS += -lcrypt endif +ifeq ($(HAVE_LIBNSL),yes) + EXTRALS += -lnsl +endif TITLE=pam_pwdb CHKPWD=pwdb_chkpwd @@ -53,7 +56,7 @@ info: $(CHKPWD): pwdb_chkpwd.o md5_good.o md5_broken.o \ md5_crypt_good.o md5_crypt_broken.o - $(CC) -o $(CHKPWD) $^ -lpwdb + $(CC) $(CFLAGS) -o $(CHKPWD) $^ $(LDFLAGS) -lpwdb $(EXTRALS) pwdb_chkpwd.o: pwdb_chkpwd.c pam_unix_md.-c bigcrypt.-c diff --git a/Linux-PAM/modules/pam_pwdb/TODO b/Linux-PAM/modules/pam_pwdb/TODO index 04635859..520a262e 100644 --- a/Linux-PAM/modules/pam_pwdb/TODO +++ b/Linux-PAM/modules/pam_pwdb/TODO @@ -1,4 +1,4 @@ -$Id: TODO,v 1.1.1.1 2001/04/29 04:17:27 hartmans Exp $ +$Id: TODO,v 1.1.1.1 2000/06/20 22:11:47 agmorgan Exp $ * get NIS working * .. including "nonis" argument diff --git a/Linux-PAM/modules/pam_pwdb/md5.c b/Linux-PAM/modules/pam_pwdb/md5.c index a0e5a974..44282941 100644 --- a/Linux-PAM/modules/pam_pwdb/md5.c +++ b/Linux-PAM/modules/pam_pwdb/md5.c @@ -1,4 +1,4 @@ -/* $Id: md5.c,v 1.1.1.1 2001/04/29 04:17:27 hartmans Exp $ +/* $Id: md5.c,v 1.2 2000/12/04 19:02:34 baggins Exp $ * * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was diff --git a/Linux-PAM/modules/pam_pwdb/md5_crypt.c b/Linux-PAM/modules/pam_pwdb/md5_crypt.c index 28f22727..826087f2 100644 --- a/Linux-PAM/modules/pam_pwdb/md5_crypt.c +++ b/Linux-PAM/modules/pam_pwdb/md5_crypt.c @@ -1,4 +1,4 @@ -/* $Id: md5_crypt.c,v 1.1.1.1 2001/04/29 04:17:27 hartmans Exp $ +/* $Id: md5_crypt.c,v 1.2 2000/12/04 19:02:34 baggins Exp $ * * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): diff --git a/Linux-PAM/modules/pam_pwdb/pam_pwdb.c b/Linux-PAM/modules/pam_pwdb/pam_pwdb.c index c2a5639c..8c75ac23 100644 --- a/Linux-PAM/modules/pam_pwdb/pam_pwdb.c +++ b/Linux-PAM/modules/pam_pwdb/pam_pwdb.c @@ -1,5 +1,5 @@ /* - * $Id: pam_pwdb.c,v 1.1.1.1 2001/04/29 04:17:28 hartmans Exp $ + * $Id: pam_pwdb.c,v 1.3 2000/11/19 23:54:04 agmorgan Exp $ * * This is the single file that will be compiled for pam_unix. * it includes each of the modules that have beed defined in the .-c @@ -14,7 +14,7 @@ */ static const char rcsid[] = -"$Id: pam_pwdb.c,v 1.1.1.1 2001/04/29 04:17:28 hartmans Exp $\n" +"$Id: pam_pwdb.c,v 1.3 2000/11/19 23:54:04 agmorgan Exp $\n" " - PWDB Pluggable Authentication module. <morgan@linux.kernel.org>" ; diff --git a/Linux-PAM/modules/pam_pwdb/pam_unix_acct.-c b/Linux-PAM/modules/pam_pwdb/pam_unix_acct.-c index 3a6ff1ed..adcb6538 100644 --- a/Linux-PAM/modules/pam_pwdb/pam_unix_acct.-c +++ b/Linux-PAM/modules/pam_pwdb/pam_unix_acct.-c @@ -1,11 +1,11 @@ /* - * $Id: pam_unix_acct.-c,v 1.1.1.1 2001/04/29 04:17:28 hartmans Exp $ + * $Id: pam_unix_acct.-c,v 1.2 2000/12/04 19:02:34 baggins Exp $ * * See end of file for copyright information */ static const char rcsid_acct[] = -"$Id: pam_unix_acct.-c,v 1.1.1.1 2001/04/29 04:17:28 hartmans Exp $\n" +"$Id: pam_unix_acct.-c,v 1.2 2000/12/04 19:02:34 baggins Exp $\n" " - PAM_PWDB account management <gafton@redhat.com>"; /* the shadow suite has accout managment.. */ diff --git a/Linux-PAM/modules/pam_pwdb/pam_unix_auth.-c b/Linux-PAM/modules/pam_pwdb/pam_unix_auth.-c index 14d74b74..31230394 100644 --- a/Linux-PAM/modules/pam_pwdb/pam_unix_auth.-c +++ b/Linux-PAM/modules/pam_pwdb/pam_unix_auth.-c @@ -1,11 +1,11 @@ /* - * $Id: pam_unix_auth.-c,v 1.1.1.1 2001/04/29 04:17:28 hartmans Exp $ + * $Id: pam_unix_auth.-c,v 1.1.1.1 2000/06/20 22:11:49 agmorgan Exp $ * * See end of file for Copyright information. */ static const char rcsid_auth[] = -"$Id: pam_unix_auth.-c,v 1.1.1.1 2001/04/29 04:17:28 hartmans Exp $: pam_unix_auth.-c,v 1.2 1996/09/05 06:46:53 morgan Exp morgan $\n" +"$Id: pam_unix_auth.-c,v 1.1.1.1 2000/06/20 22:11:49 agmorgan Exp $: pam_unix_auth.-c,v 1.2 1996/09/05 06:46:53 morgan Exp morgan $\n" " - PAM_PWDB authentication functions. <morgan@parc.power.net>"; /* diff --git a/Linux-PAM/modules/pam_pwdb/pam_unix_passwd.-c b/Linux-PAM/modules/pam_pwdb/pam_unix_passwd.-c index dc106431..7ed65000 100644 --- a/Linux-PAM/modules/pam_pwdb/pam_unix_passwd.-c +++ b/Linux-PAM/modules/pam_pwdb/pam_unix_passwd.-c @@ -1,7 +1,7 @@ -/* $Id: pam_unix_passwd.-c,v 1.1.1.2 2002/09/15 20:08:55 hartmans Exp $ */ +/* $Id: pam_unix_passwd.-c,v 1.3 2001/11/12 06:57:38 agmorgan Exp $ */ static const char rcsid_pass[] = -"$Id: pam_unix_passwd.-c,v 1.1.1.2 2002/09/15 20:08:55 hartmans Exp $\n" +"$Id: pam_unix_passwd.-c,v 1.3 2001/11/12 06:57:38 agmorgan Exp $\n" " - PAM_PWDB password module <morgan@parc.power.net>" ; diff --git a/Linux-PAM/modules/pam_pwdb/pam_unix_pwupd.-c b/Linux-PAM/modules/pam_pwdb/pam_unix_pwupd.-c index adb286e2..a1fc65ff 100644 --- a/Linux-PAM/modules/pam_pwdb/pam_unix_pwupd.-c +++ b/Linux-PAM/modules/pam_pwdb/pam_unix_pwupd.-c @@ -1,5 +1,5 @@ /* - * $Id: pam_unix_pwupd.-c,v 1.1.1.1 2001/04/29 04:17:29 hartmans Exp $ + * $Id: pam_unix_pwupd.-c,v 1.1.1.1 2000/06/20 22:11:51 agmorgan Exp $ * * This file contains the routines to update the passwd databases. */ diff --git a/Linux-PAM/modules/pam_pwdb/pam_unix_sess.-c b/Linux-PAM/modules/pam_pwdb/pam_unix_sess.-c index 3e03fc55..395bd9bb 100644 --- a/Linux-PAM/modules/pam_pwdb/pam_unix_sess.-c +++ b/Linux-PAM/modules/pam_pwdb/pam_unix_sess.-c @@ -1,11 +1,11 @@ /* - * $Id: pam_unix_sess.-c,v 1.1.1.1 2001/04/29 04:17:29 hartmans Exp $ + * $Id: pam_unix_sess.-c,v 1.2 2000/12/04 19:02:34 baggins Exp $ * * See end for Copyright information */ static const char rcsid_sess[] = -"$Id: pam_unix_sess.-c,v 1.1.1.1 2001/04/29 04:17:29 hartmans Exp $\n" +"$Id: pam_unix_sess.-c,v 1.2 2000/12/04 19:02:34 baggins Exp $\n" " - PAM_PWDB session management. morgan@parc.power.net"; /* Define internal functions */ diff --git a/Linux-PAM/modules/pam_pwdb/pwdb_chkpwd.c b/Linux-PAM/modules/pam_pwdb/pwdb_chkpwd.c index 0b55c952..36c248ef 100644 --- a/Linux-PAM/modules/pam_pwdb/pwdb_chkpwd.c +++ b/Linux-PAM/modules/pam_pwdb/pwdb_chkpwd.c @@ -1,5 +1,5 @@ /* - * $Id: pwdb_chkpwd.c,v 1.1.1.2 2002/09/15 20:08:55 hartmans Exp $ + * $Id: pwdb_chkpwd.c,v 1.4 2001/12/09 21:44:58 agmorgan Exp $ * * This program is designed to run setuid(root) or with sufficient * privilege to read all of the unix password databases. It is designed diff --git a/Linux-PAM/modules/pam_pwdb/support.-c b/Linux-PAM/modules/pam_pwdb/support.-c index 623fe2c3..bfa4e8a1 100644 --- a/Linux-PAM/modules/pam_pwdb/support.-c +++ b/Linux-PAM/modules/pam_pwdb/support.-c @@ -1,5 +1,5 @@ /* - * $Id: support.-c,v 1.1.1.2 2002/09/15 20:08:55 hartmans Exp $ + * $Id: support.-c,v 1.6 2004/09/15 12:06:17 kukuk Exp $ * * Copyright information at end of file. */ @@ -79,8 +79,9 @@ typedef struct { #define UNIX_UNIX 19 /* wish to use /etc/passwd for pwd */ #define UNIX_BIGCRYPT 20 /* use DEC-C2 crypt()^x function */ #define UNIX_LIKE_AUTH 21 /* need to auth for setcred to work */ +#define UNIX_NOREAP 22 /* don't reap child process */ /* -------------- */ -#define UNIX_CTRLS_ 22 /* number of ctrl arguments defined */ +#define UNIX_CTRLS_ 23 /* number of ctrl arguments defined */ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = { @@ -109,6 +110,7 @@ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = { /* UNIX_UNIX */ { "unix", _ALL_ON_^(050000), 01000000 }, /* UNIX_BIGCRYPT */ { "bigcrypt", _ALL_ON_^(020000), 02000000 }, /* UNIX_LIKE_AUTH */ { "likeauth", _ALL_ON_, 04000000 }, +/* UNIX_NOREAP */ {"noreap", _ALL_ON_, 010000000 }, }; #define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag) @@ -342,13 +344,15 @@ static void _cleanup_failures(pam_handle_t *pamh, void *fl, int err) * verify the password of a user */ +#include <signal.h> #include <sys/types.h> #include <sys/wait.h> static int pwdb_run_helper_binary(pam_handle_t *pamh, const char *passwd, - const char *user) + unsigned int ctrl, const char *user) { int retval, child, fds[2]; + void (*sighandler)(int) = NULL; D(("called.")); /* create a pipe for the password */ @@ -357,6 +361,18 @@ static int pwdb_run_helper_binary(pam_handle_t *pamh, const char *passwd, return PAM_AUTH_ERR; } + if (off(UNIX_NOREAP, ctrl)) { + /* + * This code arranges that the demise of the child does not cause + * the application to receive a signal it is not expecting - which + * may kill the application or worse. + * + * The "noreap" module argument is provided so that the admin can + * override this behavior. + */ + sighandler = signal(SIGCHLD, SIG_DFL); + } + /* fork */ child = fork(); if (child == 0) { @@ -397,6 +413,10 @@ static int pwdb_run_helper_binary(pam_handle_t *pamh, const char *passwd, retval = PAM_AUTH_ERR; } + if (sighandler != NULL) { + (void) signal(SIGCHLD, sighandler); /* restore old signal handler */ + } + D(("returning %d", retval)); return retval; } @@ -468,7 +488,7 @@ static int _unix_verify_password(pam_handle_t *pamh, const char *name, if (geteuid()) { /* we are not root perhaps this is the reason? Run helper */ D(("running helper binary")); - retval = pwdb_run_helper_binary(pamh, p, name); + retval = pwdb_run_helper_binary(pamh, p, ctrl, name); } else { retval = PAM_AUTHINFO_UNAVAIL; _log_err(LOG_ALERT, "get passwd; %s", pwdb_strerror(retval)); diff --git a/Linux-PAM/modules/pam_radius/pam_radius.h b/Linux-PAM/modules/pam_radius/pam_radius.h index 8193c844..67230243 100644 --- a/Linux-PAM/modules/pam_radius/pam_radius.h +++ b/Linux-PAM/modules/pam_radius/pam_radius.h @@ -1,5 +1,5 @@ /* - * $Id: pam_radius.h,v 1.1.1.1 2001/04/29 04:17:32 hartmans Exp $ + * $Id: pam_radius.h,v 1.2 2000/11/19 23:54:05 agmorgan Exp $ */ #ifndef PAM_RADIUS_H diff --git a/Linux-PAM/modules/pam_rhosts/Makefile b/Linux-PAM/modules/pam_rhosts/Makefile index 0c4ec77e..d12e00c0 100644 --- a/Linux-PAM/modules/pam_rhosts/Makefile +++ b/Linux-PAM/modules/pam_rhosts/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:32 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:05 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_rhosts/pam_rhosts_auth.c b/Linux-PAM/modules/pam_rhosts/pam_rhosts_auth.c index 7266b4e8..979580ec 100644 --- a/Linux-PAM/modules/pam_rhosts/pam_rhosts_auth.c +++ b/Linux-PAM/modules/pam_rhosts/pam_rhosts_auth.c @@ -42,7 +42,7 @@ #define USER_RHOSTS_FILE "/.rhosts" /* prefixed by user's home dir */ -#ifdef linux +#ifdef __linux__ #include <endian.h> #endif @@ -50,6 +50,10 @@ #include <sys/fsuid.h> #endif /* HAVE_SYS_FSUID_H */ +#ifdef HAVE_NET_IF_H +#include <sys/if.h> +#endif + #include <sys/types.h> #include <sys/uio.h> #include <string.h> @@ -74,19 +78,13 @@ int innetgr(const char *, const char *, const char *,const char *); #include <ctype.h> #include <net/if.h> -#ifdef linux -# include <linux/sockios.h> -# ifndef __USE_MISC -# define __USE_MISC -# include <sys/fsuid.h> -# endif /* __USE_MISC */ -#endif #include <pwd.h> #include <grp.h> #include <sys/file.h> #include <sys/signal.h> #include <sys/stat.h> +#include <stdint.h> #include <syslog.h> #ifndef _PATH_HEQUIV #define _PATH_HEQUIV "/etc/hosts.equiv" @@ -98,8 +96,17 @@ int innetgr(const char *, const char *, const char *,const char *); #include <security/_pam_macros.h> #include <security/_pam_modutil.h> -/* to the best of my knowledge, all modern UNIX boxes have 32 bit integers */ +#ifdef _ISOC9X_SOURCE +#include <inttypes.h> +#define U32 uint32_t +#else +/* to the best of my knowledge, all modern UNIX boxes have 32 bits integers */ #define U32 unsigned int +#endif /* _ISOC9X_SOURCE */ + +/* Use the C99 type; older platforms will need this to be typedef'ed + elsewhere */ +#define U32 uint32_t /* @@ -183,7 +190,7 @@ static void set_option (struct _options *opts, const char *arg) return; } - if (strcmp(arg, "superuser=") == 0) { + if (strncmp(arg, "superuser=", sizeof("superuser=")-1) == 0) { opts->superuser = arg+sizeof("superuser=")-1; return; } @@ -298,7 +305,7 @@ __icheckhost (pam_handle_t *pamh, struct _options *opts, U32 raddr hp = gethostbyname(lhost); if (hp == NULL) return (0); - + /* Spin through ip addresses. */ for (pp = hp->h_addr_list; *pp; ++pp) if (!memcmp (&raddr, *pp, sizeof (U32))) @@ -413,7 +420,7 @@ __ivaliduser (pam_handle_t *pamh, struct _options *opts, user = p; /* this is the user's name */ while (*p && !isspace(*p)) ++p; /* find end of user's name */ - } else + } else user = p; *p = '\0'; /* <nul> terminate username (+host?) */ @@ -485,7 +492,7 @@ pam_iruserok(pam_handle_t *pamh, No hosts.equiv file on system. } */ } - + if ( opts->opt_no_rhosts ) return 1; @@ -495,10 +502,10 @@ pam_iruserok(pam_handle_t *pamh, pwd = _pammodutil_getpwnam(pamh, luser); if (pwd == NULL) { - /* + /* * luser is assumed to be valid because of an earlier check for uid = 0 * we don't log this error twice. However, this shouldn't happen ! - * --cristiang + * --cristiang */ return(1); } @@ -520,7 +527,7 @@ pam_iruserok(pam_handle_t *pamh, */ /* We are root, this will not fail */ -#ifdef linux +#ifdef __linux__ /* If we are on linux the better way is setfsuid */ uid = setfsuid(pwd->pw_uid); hostf = fopen(pbuf, "r"); @@ -555,7 +562,7 @@ pam_iruserok(pam_handle_t *pamh, /* private group caveat */ if (opts->opt_private_group) { - struct group *grp = getgrgid(sbuf.st_gid); + struct group *grp = _pammodutil_getgrgid(pamh, sbuf.st_gid); if (NULL == grp || NULL == grp->gr_name || strcmp(luser,grp->gr_name)) { @@ -596,7 +603,7 @@ exit_function: * they are reset before we exit. */ -#ifdef linux +#ifdef __linux__ setfsuid(uid); #else (void)seteuid(uid); @@ -657,9 +664,9 @@ pam_ruserok (pam_handle_t *pamh, */ static int _pam_auth_rhosts (pam_handle_t *pamh, - int flags, + int flags, int argc, - const char **argv) + const char **argv) { int retval; const char *luser = NULL; @@ -750,9 +757,9 @@ static int _pam_auth_rhosts (pam_handle_t *pamh, /* --- authentication management functions --- */ PAM_EXTERN -int pam_sm_authenticate (pam_handle_t *pamh, +int pam_sm_authenticate (pam_handle_t *pamh, int flags, - int argc, + int argc, const char **argv) { int retval; diff --git a/Linux-PAM/modules/pam_rootok/Makefile b/Linux-PAM/modules/pam_rootok/Makefile index f6c58635..b908b115 100644 --- a/Linux-PAM/modules/pam_rootok/Makefile +++ b/Linux-PAM/modules/pam_rootok/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:33 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:05 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_rootok/README b/Linux-PAM/modules/pam_rootok/README index 4e19c097..43b92e6c 100644 --- a/Linux-PAM/modules/pam_rootok/README +++ b/Linux-PAM/modules/pam_rootok/README @@ -1,4 +1,4 @@ -# $Id: README,v 1.1.1.2 2002/09/15 20:08:57 hartmans Exp $ +# $Id: README,v 1.2 2001/11/27 05:37:30 agmorgan Exp $ # this module is an authentication module that performs one task: if the diff --git a/Linux-PAM/modules/pam_rootok/pam_rootok.c b/Linux-PAM/modules/pam_rootok/pam_rootok.c index 57ddebe5..e1e09b6e 100644 --- a/Linux-PAM/modules/pam_rootok/pam_rootok.c +++ b/Linux-PAM/modules/pam_rootok/pam_rootok.c @@ -1,7 +1,7 @@ /* pam_rootok module */ /* - * $Id: pam_rootok.c,v 1.1.1.2 2002/09/15 20:08:57 hartmans Exp $ + * $Id: pam_rootok.c,v 1.3 2002/05/26 23:00:28 agmorgan Exp $ * * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 */ diff --git a/Linux-PAM/modules/pam_securetty/Makefile b/Linux-PAM/modules/pam_securetty/Makefile index 65e50d51..8ac853c5 100644 --- a/Linux-PAM/modules/pam_securetty/Makefile +++ b/Linux-PAM/modules/pam_securetty/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:33 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:05 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_securetty/pam_securetty.c b/Linux-PAM/modules/pam_securetty/pam_securetty.c index 9e6121e8..3a9ae421 100644 --- a/Linux-PAM/modules/pam_securetty/pam_securetty.c +++ b/Linux-PAM/modules/pam_securetty/pam_securetty.c @@ -21,8 +21,7 @@ #include <stdarg.h> #include <pwd.h> #include <string.h> - -#define PAM_SM_AUTH +#include <ctype.h> /* * here, we make a definition for the externally accessible function @@ -32,8 +31,10 @@ */ #define PAM_SM_AUTH +#define PAM_SM_ACCOUNT #include <security/pam_modules.h> +#include <security/_pam_modutil.h> /* some syslogging */ @@ -71,31 +72,39 @@ static int _pam_parse(int argc, const char **argv) return ctrl; } -/* --- authentication management functions (only) --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc - ,const char **argv) +static int securetty_perform_check(pam_handle_t *pamh, int flags, int ctrl, + const char *function_name) { int retval = PAM_AUTH_ERR; const char *username; char *uttyname; char ttyfileline[256]; + char ptname[256]; struct stat ttyfileinfo; struct passwd *user_pwd; FILE *ttyfile; - int ctrl; - /* parse the arguments */ - ctrl = _pam_parse(argc, argv); + /* log a trail for debugging */ + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_DEBUG, "pam_securetty called via %s function", + function_name); + } retval = pam_get_user(pamh, &username, NULL); if (retval != PAM_SUCCESS || username == NULL) { if (ctrl & PAM_DEBUG_ARG) { _pam_log(LOG_WARNING, "cannot determine username"); } - return (retval == PAM_CONV_AGAIN - ? PAM_INCOMPLETE:PAM_SERVICE_ERR); + return (retval == PAM_CONV_AGAIN ? PAM_INCOMPLETE:PAM_SERVICE_ERR); + } + + user_pwd = _pammodutil_getpwnam(pamh, username); + if (user_pwd == NULL) { + return PAM_IGNORE; + } else if (user_pwd->pw_uid != 0) { /* If the user is not root, + securetty's does not apply + to them */ + return PAM_SUCCESS; } retval = pam_get_item(pamh, PAM_TTY, (const void **)&uttyname); @@ -107,16 +116,8 @@ int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc } /* The PAM_TTY item may be prefixed with "/dev/" - skip that */ - if (strncmp(TTY_PREFIX, uttyname, sizeof(TTY_PREFIX)-1) == 0) + if (strncmp(TTY_PREFIX, uttyname, sizeof(TTY_PREFIX)-1) == 0) { uttyname += sizeof(TTY_PREFIX)-1; - - user_pwd = getpwnam(username); - if (user_pwd == NULL) { - return PAM_IGNORE; - } else if (user_pwd->pw_uid != 0) { /* If the user is not root, - securetty's does not apply - to them */ - return PAM_SUCCESS; } if (stat(SECURETTY_FILE, &ttyfileinfo)) { @@ -126,8 +127,7 @@ int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc error. */ } - if ((ttyfileinfo.st_mode & S_IWOTH) - || !S_ISREG(ttyfileinfo.st_mode)) { + if ((ttyfileinfo.st_mode & S_IWOTH) || !S_ISREG(ttyfileinfo.st_mode)) { /* If the file is world writable or is not a normal file, return error */ _pam_log(LOG_ERR, SECURETTY_FILE @@ -136,39 +136,80 @@ int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc } ttyfile = fopen(SECURETTY_FILE,"r"); - if(ttyfile == NULL) { /* Check that we opened it successfully */ + if (ttyfile == NULL) { /* Check that we opened it successfully */ _pam_log(LOG_ERR, "Error opening " SECURETTY_FILE); return PAM_SERVICE_ERR; } - /* There should be no more errors from here on */ - retval=PAM_AUTH_ERR; - /* This loop assumes that PAM_SUCCESS == 0 - and PAM_AUTH_ERR != 0 */ - while((fgets(ttyfileline,sizeof(ttyfileline)-1, ttyfile) != NULL) - && retval) { - if(ttyfileline[strlen(ttyfileline) - 1] == '\n') + + if (isdigit(uttyname[0])) { + snprintf(ptname, sizeof(ptname), "pts/%s", uttyname); + } else { + ptname[0] = '\0'; + } + + retval = 1; + + while ((fgets(ttyfileline, sizeof(ttyfileline)-1, ttyfile) != NULL) + && retval) { + if (ttyfileline[strlen(ttyfileline) - 1] == '\n') ttyfileline[strlen(ttyfileline) - 1] = '\0'; - retval = strcmp(ttyfileline,uttyname); + + retval = ( strcmp(ttyfileline, uttyname) + && (!ptname[0] || strcmp(ptname, uttyname)) ); } fclose(ttyfile); - if(retval) { - if (ctrl & PAM_DEBUG_ARG) + + if (retval) { _pam_log(LOG_WARNING, "access denied: tty '%s' is not secure !", uttyname); - retval = PAM_AUTH_ERR; + + retval = PAM_AUTH_ERR; + } else { + if ((retval == PAM_SUCCESS) && (ctrl & PAM_DEBUG_ARG)) { + _pam_log(LOG_DEBUG, "access allowed for '%s' on '%s'", + username, uttyname); + } + retval = PAM_SUCCESS; + } - if ((retval == PAM_SUCCESS) && (ctrl & PAM_DEBUG_ARG)) - _pam_log(LOG_DEBUG, "access allowed for '%s' on '%s'", - username, uttyname); + return retval; } +/* --- authentication management functions --- */ + PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc - ,const char **argv) +int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + const char **argv) { - return PAM_SUCCESS; + int ctrl; + + /* parse the arguments */ + ctrl = _pam_parse(argc, argv); + + return securetty_perform_check(pamh, flags, ctrl, __FUNCTION__); +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + return PAM_SUCCESS; +} + +/* --- account management functions --- */ + +PAM_EXTERN +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + int ctrl; + + /* parse the arguments */ + ctrl = _pam_parse(argc, argv); + + /* take the easy route */ + return securetty_perform_check(pamh, flags, ctrl, __FUNCTION__); } @@ -180,12 +221,12 @@ struct pam_module _pam_securetty_modstruct = { "pam_securetty", pam_sm_authenticate, pam_sm_setcred, - NULL, + pam_sm_acct_mgmt, NULL, NULL, NULL, }; -#endif +#endif /* PAM_STATIC */ /* end of module definition */ diff --git a/Linux-PAM/modules/pam_shells/Makefile b/Linux-PAM/modules/pam_shells/Makefile index 1ead26c5..f1d7ff51 100644 --- a/Linux-PAM/modules/pam_shells/Makefile +++ b/Linux-PAM/modules/pam_shells/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:33 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:05 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_shells/README b/Linux-PAM/modules/pam_shells/README index cbd5bfb5..aa63a827 100644 --- a/Linux-PAM/modules/pam_shells/README +++ b/Linux-PAM/modules/pam_shells/README @@ -1,7 +1,6 @@ pam_shells: Authentication is granted if the users shell is listed in - /etc/shells. If no shell is in /etc/passwd (empty), the - /bin/sh is used (following ftpd's convention). + /etc/shells. Also checks to make sure that /etc/shells is a plain file and not world writable. diff --git a/Linux-PAM/modules/pam_shells/pam_shells.c b/Linux-PAM/modules/pam_shells/pam_shells.c index 36dd1a91..64359eac 100644 --- a/Linux-PAM/modules/pam_shells/pam_shells.c +++ b/Linux-PAM/modules/pam_shells/pam_shells.c @@ -12,8 +12,10 @@ #include <pwd.h> #include <stdarg.h> +#include <string.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/stat.h> #include <syslog.h> #include <unistd.h> @@ -26,8 +28,10 @@ */ #define PAM_SM_AUTH +#define PAM_SM_ACCOUNT #include <security/pam_modules.h> +#include <security/_pam_modutil.h> /* some syslogging */ @@ -42,77 +46,98 @@ static void _pam_log(int err, const char *format, ...) closelog(); } -/* --- authentication management functions (only) --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc - ,const char **argv) +static int perform_check(pam_handle_t *pamh, int flags) { - int retval = PAM_AUTH_ERR; - const char *userName; - char *userShell; - char shellFileLine[256]; - struct stat sb; - struct passwd * pw; - FILE * shellFile; - - retval = pam_get_user(pamh,&userName,NULL); - if(retval != PAM_SUCCESS) - return PAM_SERVICE_ERR; - - if(!userName || (strlen(userName) <= 0)) { - /* Don't let them use a NULL username... */ - pam_get_user(pamh,&userName,NULL); + int retval = PAM_AUTH_ERR; + const char *userName; + char *userShell; + char shellFileLine[256]; + struct stat sb; + struct passwd * pw; + FILE * shellFile; + + retval = pam_get_user(pamh, &userName, NULL); + if (retval != PAM_SUCCESS) { + return PAM_SERVICE_ERR; + } + + if (!userName || (userName[0] == '\0')) { + + /* Don't let them use a NULL username... */ + retval = pam_get_user(pamh,&userName,NULL); if (retval != PAM_SUCCESS) - return PAM_SERVICE_ERR; - } + return PAM_SERVICE_ERR; - pw = getpwnam(userName); - if (!pw) + /* It could still be NULL the second time. */ + if (!userName || (userName[0] == '\0')) + return PAM_SERVICE_ERR; + } + + pw = _pammodutil_getpwnam(pamh, userName); + if (!pw) { return PAM_AUTH_ERR; /* user doesn't exist */ - userShell = pw->pw_shell; + } + userShell = pw->pw_shell; - if(stat(SHELL_FILE,&sb)) { - _pam_log(LOG_ERR, - "%s cannot be stat'd (it probably does not exist)", SHELL_FILE); + if (stat(SHELL_FILE,&sb)) { + _pam_log(LOG_ERR, "%s cannot be stat'd (it probably does not exist)", + SHELL_FILE); return PAM_AUTH_ERR; /* must have /etc/shells */ - } + } - if((sb.st_mode & S_IWOTH) || !S_ISREG(sb.st_mode)) { - _pam_log(LOG_ERR, - "%s is either world writable or not a normal file", SHELL_FILE); + if ((sb.st_mode & S_IWOTH) || !S_ISREG(sb.st_mode)) { + _pam_log(LOG_ERR, "%s is either world writable or not a normal file", + SHELL_FILE); return PAM_AUTH_ERR; - } + } - shellFile = fopen(SHELL_FILE,"r"); - if(shellFile == NULL) { /* Check that we opened it successfully */ + shellFile = fopen(SHELL_FILE,"r"); + if (shellFile == NULL) { /* Check that we opened it successfully */ _pam_log(LOG_ERR, - "Error opening %s", SHELL_FILE); - return PAM_SERVICE_ERR; - } - /* There should be no more errors from here on */ - retval=PAM_AUTH_ERR; - /* This loop assumes that PAM_SUCCESS == 0 - and PAM_AUTH_ERR != 0 */ - while((fgets(shellFileLine,255,shellFile) != NULL) - && retval) { - if (shellFileLine[strlen(shellFileLine) - 1] == '\n') - shellFileLine[strlen(shellFileLine) - 1] = '\0'; - retval = strcmp(shellFileLine, userShell); - } - fclose(shellFile); - if(retval) - retval = PAM_AUTH_ERR; - return retval; + "Error opening %s", SHELL_FILE); + return PAM_SERVICE_ERR; + } + + retval = 1; + + while(retval && (fgets(shellFileLine, 255, shellFile) != NULL)) { + if (shellFileLine[strlen(shellFileLine) - 1] == '\n') + shellFileLine[strlen(shellFileLine) - 1] = '\0'; + retval = strcmp(shellFileLine, userShell); + } + + fclose(shellFile); + + if (retval) { + return PAM_AUTH_ERR; + } else { + return PAM_SUCCESS; + } +} + +/* --- authentication management functions (only) --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + return perform_check(pamh, flags); } PAM_EXTERN -int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc - ,const char **argv) +int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,const char **argv) { return PAM_SUCCESS; } +/* --- account management functions (only) --- */ + +PAM_EXTERN +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + return perform_check(pamh, flags); +} #ifdef PAM_STATIC @@ -122,12 +147,12 @@ struct pam_module _pam_shells_modstruct = { "pam_shells", pam_sm_authenticate, pam_sm_setcred, - NULL, + pam_sm_acct_mgmt, NULL, NULL, NULL, }; -#endif +#endif /* PAM_STATIC */ /* end of module definition */ diff --git a/Linux-PAM/modules/pam_stress/Makefile b/Linux-PAM/modules/pam_stress/Makefile index 15a891c0..3512c853 100644 --- a/Linux-PAM/modules/pam_stress/Makefile +++ b/Linux-PAM/modules/pam_stress/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:33 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:05 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_stress/README b/Linux-PAM/modules/pam_stress/README index 7a88f12d..b4273f50 100644 --- a/Linux-PAM/modules/pam_stress/README +++ b/Linux-PAM/modules/pam_stress/README @@ -1,5 +1,5 @@ # -# $Id: README,v 1.1.1.1 2001/04/29 04:17:34 hartmans Exp $ +# $Id: README,v 1.1.1.1 2000/06/20 22:11:57 agmorgan Exp $ # # This describes the behavior of this module with respect to the # /etc/pam.conf file. diff --git a/Linux-PAM/modules/pam_stress/pam_stress.c b/Linux-PAM/modules/pam_stress/pam_stress.c index 8bc85f5d..2d361c3e 100644 --- a/Linux-PAM/modules/pam_stress/pam_stress.c +++ b/Linux-PAM/modules/pam_stress/pam_stress.c @@ -1,6 +1,6 @@ /* pam_stress module */ -/* $Id: pam_stress.c,v 1.1.1.1 2001/04/29 04:17:34 hartmans Exp $ +/* $Id: pam_stress.c,v 1.4 2004/09/22 09:37:50 kukuk Exp $ * * created by Andrew Morgan <morgan@linux.kernel.org> 1996/3/12 */ @@ -10,7 +10,6 @@ #include <stdlib.h> #include <stdio.h> -#define __USE_BSD #include <syslog.h> #include <stdarg.h> @@ -32,13 +31,6 @@ #include <security/pam_modules.h> #include <security/_pam_macros.h> -static char *_strdup(const char *x) -{ - char *new; - new = malloc(strlen(x)+1); - strcpy(new,x); - return new; -} /* log errors */ @@ -142,8 +134,8 @@ static int converse(pam_handle_t *pamh, int nargs int retval; struct pam_conv *conv; - if ((retval = pam_get_item(pamh,PAM_CONV,(const void **)&conv)) - == PAM_SUCCESS) { + retval = pam_get_item(pamh,PAM_CONV,(const void **)&conv); + if (retval == PAM_SUCCESS && conv) { retval = conv->conv(nargs, (const struct pam_message **) message , response, conv->appdata_ptr); if (retval != PAM_SUCCESS) { @@ -152,6 +144,8 @@ static int converse(pam_handle_t *pamh, int nargs } } else { _pam_log(LOG_ERR,"(pam_stress) converse failed to get pam_conv"); + if (retval == PAM_SUCCESS) + retval = PAM_BAD_ITEM; /* conv was null */ } return retval; @@ -168,7 +162,8 @@ static int stress_get_password(pam_handle_t *pamh, int flags && (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass) == PAM_SUCCESS) && (pass != NULL) ) { - pass = _strdup(pass); + if ((pass = strdup(pass)) == NULL) + return PAM_BUF_ERR; } else if ((ctrl & PAM_ST_USE_PASS1)) { _pam_log(LOG_WARNING, "pam_stress: no forwarded password"); return PAM_PERM_DENIED; @@ -207,7 +202,8 @@ static int stress_get_password(pam_handle_t *pamh, int flags _pam_log(LOG_DEBUG,"getting password, but NULL returned!?"); return PAM_CONV_ERR; } - free(resp); + if (resp) + free(resp); } *password = pass; /* this *MUST* be free()'d by this module */ @@ -239,12 +235,15 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, /* try to get the username */ retval = pam_get_user(pamh, &username, "username: "); - if ((ctrl & PAM_ST_DEBUG) && (retval == PAM_SUCCESS)) { - _pam_log(LOG_DEBUG, "pam_sm_authenticate: username = %s", username); - } else if (retval != PAM_SUCCESS) { + if (retval != PAM_SUCCESS || !username) { _pam_log(LOG_WARNING, "pam_sm_authenticate: failed to get username"); + if (retval == PAM_SUCCESS) + retval = PAM_USER_UNKNOWN; /* username was null */ return retval; } + else if ((ctrl & PAM_ST_DEBUG) && (retval == PAM_SUCCESS)) { + _pam_log(LOG_DEBUG, "pam_sm_authenticate: username = %s", username); + } /* now get the password */ @@ -258,20 +257,15 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, /* try to set password item */ retval = pam_set_item(pamh,PAM_AUTHTOK,pass); + _pam_overwrite(pass); /* clean up local copy of password */ + free(pass); + pass = NULL; if (retval != PAM_SUCCESS) { _pam_log(LOG_WARNING, "pam_sm_authenticate: " "failed to store new password"); - _pam_overwrite(pass); - free(pass); return retval; } - /* clean up local copy of password */ - - _pam_overwrite(pass); - free(pass); - pass = NULL; - /* if we are debugging then we print the password */ if (ctrl & PAM_ST_DEBUG) { @@ -320,9 +314,18 @@ int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, if (ctrl & PAM_ST_FAIL_1) return PAM_PERM_DENIED; else if (ctrl & PAM_ST_EXPIRED) { - void *text = malloc(sizeof("yes")+1); - strcpy(text,"yes"); - pam_set_data(pamh,"stress_new_pwd",text,wipe_up); + int retval; + void *text = strdup("yes"); + if (!text) + return PAM_BUF_ERR; + retval = pam_set_data(pamh,"stress_new_pwd",text,wipe_up); + if (retval != PAM_SUCCESS) { + _pam_log(LOG_DEBUG, + "pam_sm_acct_mgmt: failed setting stress_new_pwd"); + free(text); + return retval; + } + if (ctrl & PAM_ST_DEBUG) { _pam_log(LOG_DEBUG,"pam_sm_acct_mgmt: need a new password"); } @@ -344,9 +347,9 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags, _pam_report(ctrl,"pam_sm_open_session", flags, argc, argv); if ((pam_get_item(pamh, PAM_USER, (const void **) &username) - != PAM_SUCCESS) + != PAM_SUCCESS || !username) || (pam_get_item(pamh, PAM_SERVICE, (const void **) &service) - != PAM_SUCCESS)) { + != PAM_SUCCESS || !service)) { _pam_log(LOG_WARNING,"pam_sm_open_session: for whom?"); return PAM_SESSION_ERR; } @@ -372,9 +375,9 @@ int pam_sm_close_session(pam_handle_t *pamh, int flags, _pam_report(ctrl,"pam_sm_close_session", flags, argc, argv); if ((pam_get_item(pamh, PAM_USER, (const void **)&username) - != PAM_SUCCESS) + != PAM_SUCCESS || !username) || (pam_get_item(pamh, PAM_SERVICE, (const void **)&service) - != PAM_SUCCESS)) { + != PAM_SUCCESS || !service)) { _pam_log(LOG_WARNING,"pam_sm_close_session: for whom?"); return PAM_SESSION_ERR; } @@ -448,15 +451,14 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags, return retval; } retval = pam_set_item(pamh, PAM_OLDAUTHTOK, pass); + _pam_overwrite(pass); + free(pass); + pass = NULL; if (retval != PAM_SUCCESS) { _pam_log(LOG_DEBUG ,"pam_sm_chauthtok: could not set OLDAUTHTOK"); - _pam_overwrite(pass); - free(pass); return retval; } - _pam_overwrite(pass); - free(pass); } /* set up for conversation */ @@ -517,7 +519,7 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags, pmsg[0] = &msg[0]; msg[0].msg_style = PAM_ERROR_MSG; msg[0].msg = "Verification mis-typed; " - "password unchaged"; + "password unchanged"; resp = NULL; (void) converse(pamh,1,pmsg,&resp); if (resp) { diff --git a/Linux-PAM/modules/pam_succeed_if/Makefile b/Linux-PAM/modules/pam_succeed_if/Makefile new file mode 100644 index 00000000..cea9be3b --- /dev/null +++ b/Linux-PAM/modules/pam_succeed_if/Makefile @@ -0,0 +1,16 @@ +# +# $Id: Makefile,v 1.1 2004/09/24 11:42:39 kukuk Exp $ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# +# Created by Andrew Morgan <morgan@linux.kernel.org> 2000/08/27 +# + +include ../../Make.Rules + +TITLE=pam_succeed_if +MAN8=$(TITLE).8 + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_succeed_if/README b/Linux-PAM/modules/pam_succeed_if/README new file mode 100644 index 00000000..fdb278ef --- /dev/null +++ b/Linux-PAM/modules/pam_succeed_if/README @@ -0,0 +1,68 @@ +pam_succeed_if: + Succeed or fail based on account characteristics. + + pam_succeed_if.so is designed to succeed or fail authentication based + on characteristics of the account belonging to the user being + authenticated. + + The module can be given one or more conditions as module arguments, and + authentication will succeed only if all of the conditions are met. + + Conditions are expressed in the form + + ATTRIBUTE OPERATOR VALUE + + Recognized attributes: + + LOGIN - The user's login name. + UID - The user's UID. + GID - The user's primary GID. + SHELL - The user's shell. + HOME - The user's home directory. + + Recognized operators: + + < - Arithmetic less-than. + <= - Arithmetic less-than-or-equal-to. + > - Arithmetic greater-than. + >= - Arithmetic greater-than-or-equal-to. + eq - Arithmetic equality. + = - String equality. + ne - Arithmetic inequality. + != - String inequality. + =~ - Wildcard match. + !~ - Wildcard mismatch. + ingroup - Group membership check. [*] + notingroup - Group non-membership check. [*] + + * The "ingroup" and "notingroup" operators should only be + used with the USER attribute. + + Examples: + + Deny authentication to all users except those in the wheel + group, before even asking for a password: + auth requisite pam_succeed_if.so user ingroup wheel + + Assume all users with UID less than 500 ("system users") have + valid accounts. + account sufficient pam_succeed_if.so uid < 500 + + Deny login to all nologin users. + auth requisite pam_succeed_if.so shell !~ nologin + +RECOGNIZED ARGUMENTS: + debug write debugging messages to syslog + use_uid perform checks on the account of the user under whose + UID the application is running instead of the user + being authenticated + quiet don't log failure or success to syslog + quiet_fail don't log failure to syslog + quiet_success don't log success to syslog + + +MODULE SERVICES PROVIDED: + authentication, account management + +AUTHOR: + Nalin Dahyabhai <nalin@redhat.com> diff --git a/Linux-PAM/modules/pam_succeed_if/pam_succeed_if.8 b/Linux-PAM/modules/pam_succeed_if/pam_succeed_if.8 new file mode 100644 index 00000000..da95a033 --- /dev/null +++ b/Linux-PAM/modules/pam_succeed_if/pam_succeed_if.8 @@ -0,0 +1,37 @@ +.\" Copyright 2003, 2004 Red Hat, Inc. +.\" Written by Nalin Dahyabhai <nalin@redhat.com> +.TH pam_succeed_if 8 2004/12/27 "Linux-PAM" "System Administrator's Manual" + +.SH NAME +pam_succeed_if \- succeed or fail based on account characteristics + +.SH SYNOPSIS +.B account sufficient pam_succeed_if.so uid < 500 + +.SH DESCRIPTION +pam_succeed_if.so is designed to succeed or fail authentication based on +characteristics of the account belonging to the user being authenticated. + +The module can be given one or more conditions as module arguments, and +authentication will succeed only if all of the conditions are met. + +.SH ARGUMENTS +.IP debug +Turns on debugging messages sent to syslog. +.IP use_uid +Evaluate conditions using the account of the user whose UID the application +is running under instead of the user being authenticated. +.IP quiet +Don't log failure or success to the system log. +.IP quiet_fail +Don't log failure to the system log. +.IP quiet_success +Don't log success to the system log. + + +.SH BUGS +Let's hope not, but if you find any, please report them via the "Bug Track" +link at http://bugzilla.redhat.com/bugzilla/ + +.SH AUTHOR +Nalin Dahyabhai <nalin@redhat.com> diff --git a/Linux-PAM/modules/pam_succeed_if/pam_succeed_if.c b/Linux-PAM/modules/pam_succeed_if/pam_succeed_if.c new file mode 100644 index 00000000..23974afa --- /dev/null +++ b/Linux-PAM/modules/pam_succeed_if/pam_succeed_if.c @@ -0,0 +1,470 @@ +/****************************************************************************** + * A simple user-attribute based module for PAM. + * + * Copyright (c) 2003 Red Hat, Inc. + * Written by Nalin Dahyabhai <nalin@redhat.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#define _GNU_SOURCE + +#include <sys/types.h> +#include <errno.h> +#include <fcntl.h> +#include <fnmatch.h> +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include <pwd.h> +#include <grp.h> +#include <security/pam_modules.h> +#include <security/_pam_modutil.h> + +#define MODULE "pam_succeed_if" + +static void +log_error(int priority, const char *fmt, ...) +{ + va_list va; + char *fmt2; + fmt2 = malloc(strlen(fmt) + strlen(MODULE) + 3); + va_start(va, fmt); + if (fmt2 == NULL) { + vsyslog(LOG_AUTHPRIV | priority, fmt, va); + } else { + snprintf(fmt2, strlen(fmt) + strlen(MODULE) + 3, + "%s: %s", MODULE, fmt); + vsyslog(LOG_AUTHPRIV | priority, fmt2, va); + free(fmt2); + } + va_end(va); +} + +/* Basically, run cmp(atol(left), atol(right)), returning PAM_SUCCESS if + * the function returns non-zero, PAM_AUTH_ERR if it returns zero, and + * PAM_SYSTEM_ERR if the arguments can't be parsed as numbers. */ +static int +evaluate_num(const char *left, const char *right, int (*cmp)(int, int)) +{ + long l, r; + char *p; + int ret = PAM_SUCCESS; + + errno = 0; + l = strtol(left, &p, 0); + if ((p == NULL) || (*p != '\0') || errno) { + log_error(LOG_INFO, "\"%s\" is not a number", left); + ret = PAM_SERVICE_ERR; + } + + r = strtol(right, &p, 0); + if ((p == NULL) || (*p != '\0') || errno) { + log_error(LOG_INFO, "\"%s\" is not a number", right); + ret = PAM_SERVICE_ERR; + } + + if (ret != PAM_SUCCESS) { + return ret; + } + + return cmp(l, r) ? PAM_SUCCESS : PAM_AUTH_ERR; +} + +/* Simple numeric comparison callbacks. */ +static int +eq(int i, int j) +{ + return i == j; +} +static int +ne(int i, int j) +{ + return i != j; +} +static int +lt(int i, int j) +{ + return i < j; +} +static int +le(int i, int j) +{ + return lt(i, j) || eq(i, j); +} +static int +gt(int i, int j) +{ + return i > j; +} +static int +ge(int i, int j) +{ + return gt(i, j) || eq(i, j); +} + +/* Test for numeric equality. */ +static int +evaluate_eqn(const char *left, const char *right) +{ + return evaluate_num(left, right, eq); +} +/* Test for string equality. */ +static int +evaluate_eqs(const char *left, const char *right) +{ + return (strcmp(left, right) == 0) ? PAM_SUCCESS : PAM_AUTH_ERR; +} +/* Test for numeric inequality. */ +static int +evaluate_nen(const char *left, const char *right) +{ + return evaluate_num(left, right, ne); +} +/* Test for string inequality. */ +static int +evaluate_nes(const char *left, const char *right) +{ + return (strcmp(left, right) != 0) ? PAM_SUCCESS : PAM_AUTH_ERR; +} +/* Test for numeric less-than-ness(?) */ +static int +evaluate_lt(const char *left, const char *right) +{ + return evaluate_num(left, right, lt); +} +/* Test for numeric less-than-or-equal-ness(?) */ +static int +evaluate_le(const char *left, const char *right) +{ + return evaluate_num(left, right, le); +} +/* Test for numeric greater-than-ness(?) */ +static int +evaluate_gt(const char *left, const char *right) +{ + return evaluate_num(left, right, gt); +} +/* Test for numeric greater-than-or-equal-ness(?) */ +static int +evaluate_ge(const char *left, const char *right) +{ + return evaluate_num(left, right, ge); +} +/* Check for file glob match. */ +static int +evaluate_glob(const char *left, const char *right) +{ + return (fnmatch(right, left, 0) == 0) ? PAM_SUCCESS : PAM_AUTH_ERR; +} +/* Check for file glob mismatch. */ +static int +evaluate_noglob(const char *left, const char *right) +{ + return (fnmatch(right, left, 0) != 0) ? PAM_SUCCESS : PAM_AUTH_ERR; +} +/* Return PAM_SUCCESS if the user is in the group. */ +static int +evaluate_ingroup(pam_handle_t *pamh, const char *user, const char *group) +{ + int ret; + ret = _pammodutil_user_in_group_nam_nam(pamh, user, group); + switch (ret) { + case 1: + return PAM_SUCCESS; + break; + default: + break; + } + return PAM_AUTH_ERR; +} +/* Return PAM_SUCCESS if the user is NOT in the group. */ +static int +evaluate_notingroup(pam_handle_t *pamh, const char *user, const char *group) +{ + int ret; + ret = _pammodutil_user_in_group_nam_nam(pamh, user, group); + switch (ret) { + case 0: + return PAM_SUCCESS; + break; + default: + break; + } + return PAM_AUTH_ERR; +} + +/* Match a triple. */ +static int +evaluate(pam_handle_t *pamh, int debug, + const char *left, const char *qual, const char *right, + struct passwd *pwd) +{ + char buf[LINE_MAX] = ""; + const char *attribute = left; + /* Figure out what we're evaluating here, and convert it to a string.*/ + if ((strcasecmp(left, "login") == 0) || + (strcasecmp(left, "name") == 0) || + (strcasecmp(left, "user") == 0)) { + snprintf(buf, sizeof(buf), "%s", pwd->pw_name); + left = buf; + } + if (strcasecmp(left, "uid") == 0) { + snprintf(buf, sizeof(buf), "%lu", (unsigned long) pwd->pw_uid); + left = buf; + } + if (strcasecmp(left, "gid") == 0) { + snprintf(buf, sizeof(buf), "%lu", (unsigned long) pwd->pw_gid); + left = buf; + } + if (strcasecmp(left, "shell") == 0) { + snprintf(buf, sizeof(buf), "%s", pwd->pw_shell); + left = buf; + } + if ((strcasecmp(left, "home") == 0) || + (strcasecmp(left, "dir") == 0) || + (strcasecmp(left, "homedir") == 0)) { + snprintf(buf, sizeof(buf), "%s", pwd->pw_dir); + left = buf; + } + /* If we have no idea what's going on, return an error. */ + if (left != buf) { + log_error(LOG_CRIT, "unknown attribute \"%s\"", left); + return PAM_SERVICE_ERR; + } + if (debug) { + log_error(LOG_DEBUG, "'%s' resolves to '%s'", attribute, left); + } + + /* Attribute value < some threshold. */ + if ((strcasecmp(qual, "<") == 0) || + (strcasecmp(qual, "lt") == 0)) { + return evaluate_lt(left, right); + } + /* Attribute value <= some threshold. */ + if ((strcasecmp(qual, "<=") == 0) || + (strcasecmp(qual, "le") == 0)) { + return evaluate_le(left, right); + } + /* Attribute value > some threshold. */ + if ((strcasecmp(qual, ">") == 0) || + (strcasecmp(qual, "gt") == 0)) { + return evaluate_gt(left, right); + } + /* Attribute value >= some threshold. */ + if ((strcasecmp(qual, ">=") == 0) || + (strcasecmp(qual, "ge") == 0)) { + return evaluate_ge(left, right); + } + /* Attribute value == some threshold. */ + if (strcasecmp(qual, "eq") == 0) { + return evaluate_eqn(left, right); + } + /* Attribute value = some string. */ + if (strcasecmp(qual, "=") == 0) { + return evaluate_eqs(left, right); + } + /* Attribute value != some threshold. */ + if (strcasecmp(qual, "ne") == 0) { + return evaluate_nen(left, right); + } + /* Attribute value != some string. */ + if (strcasecmp(qual, "!=") == 0) { + return evaluate_nes(left, right); + } + /* Attribute value matches some pattern. */ + if ((strcasecmp(qual, "=~") == 0) || + (strcasecmp(qual, "glob") == 0)) { + return evaluate_glob(left, right); + } + if ((strcasecmp(qual, "!~") == 0) || + (strcasecmp(qual, "noglob") == 0)) { + return evaluate_noglob(left, right); + } + /* User is in this group. */ + if (strcasecmp(qual, "ingroup") == 0) { + return evaluate_ingroup(pamh, pwd->pw_name, right); + } + /* User is not in this group. */ + if (strcasecmp(qual, "notingroup") == 0) { + return evaluate_notingroup(pamh, pwd->pw_name, right); + } + /* Fail closed. */ + return PAM_SERVICE_ERR; +} + +int +pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + const char *prompt; + const char *user; + struct passwd *pwd; + int ret, i, count, use_uid, debug; + const char *left, *right, *qual; + int quiet_fail, quiet_succ; + + /* Get the user prompt. */ + ret = pam_get_item(pamh, PAM_USER_PROMPT, (const void**) &prompt); + if ((ret != PAM_SUCCESS) || (prompt == NULL) || (strlen(prompt) == 0)) { + prompt = "login: "; + } + + quiet_fail = 0; + quiet_succ = 0; + for (use_uid = 0, debug = 0, i = 0; i < argc; i++) { + if (strcmp(argv[i], "debug") == 0) { + debug++; + } + if (strcmp(argv[i], "use_uid") == 0) { + use_uid++; + } + if (strcmp(argv[i], "quiet") == 0) { + quiet_fail++; + quiet_succ++; + } + if (strcmp(argv[i], "quiet_fail") == 0) { + quiet_fail++; + } + if (strcmp(argv[i], "quiet_success") == 0) { + quiet_succ++; + } + } + + if (use_uid) { + /* Get information about the user. */ + pwd = _pammodutil_getpwuid(pamh, getuid()); + if (pwd == NULL) { + log_error(LOG_CRIT, + "error retrieving information about user %ld", + (long)getuid()); + return PAM_SERVICE_ERR; + } + } else { + /* Get the user's name. */ + ret = pam_get_user(pamh, &user, prompt); + if ((ret != PAM_SUCCESS) || (user == NULL)) { + log_error(LOG_CRIT, "error retrieving user name: %s", + pam_strerror(pamh, ret)); + return ret; + } + + /* Get information about the user. */ + pwd = _pammodutil_getpwnam(pamh, user); + if (pwd == NULL) { + log_error(LOG_CRIT, + "error retrieving information about user %s", + user); + return PAM_SERVICE_ERR; + } + } + + /* Walk the argument list. */ + i = count = 0; + left = qual = right = NULL; + while (i <= argc) { + if ((left != NULL) && (qual != NULL) && (right != NULL)) { + ret = evaluate(pamh, debug, + left, qual, right, + pwd); + if (ret != PAM_SUCCESS) { + if(!quiet_fail) + log_error(LOG_INFO, + "requirement \"%s %s %s\" " + "not met by user \"%s\"", + left, qual, right, user); + break; + } + else + if(!quiet_succ) + log_error(LOG_INFO, + "requirement \"%s %s %s\" " + "was met by user \"%s\"", + left, qual, right, user); + left = qual = right = NULL; + } + if ((i < argc) && (strcmp(argv[i], "debug") == 0)) { + i++; + continue; + } + if ((i < argc) && (strcmp(argv[i], "use_uid") == 0)) { + i++; + continue; + } + if ((i < argc) && (strcmp(argv[i], "quiet") == 0)) { + i++; + continue; + } + if ((i < argc) && (strcmp(argv[i], "quiet_fail") == 0)) { + i++; + continue; + } + if ((i < argc) && (strcmp(argv[i], "quiet_success") == 0)) { + i++; + continue; + } + if ((i < argc) && (left == NULL)) { + left = argv[i++]; + count++; + continue; + } + if ((i < argc) && (qual == NULL)) { + qual = argv[i++]; + count++; + continue; + } + if ((i < argc) && (right == NULL)) { + right = argv[i++]; + count++; + continue; + } + i++; + } + + return ret; +} + +int +pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + return PAM_SUCCESS; +} + +int +pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + return pam_sm_authenticate(pamh, flags, argc, argv); +} diff --git a/Linux-PAM/modules/pam_tally/Makefile b/Linux-PAM/modules/pam_tally/Makefile index d173b080..40617a1a 100644 --- a/Linux-PAM/modules/pam_tally/Makefile +++ b/Linux-PAM/modules/pam_tally/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.2 2002/09/15 20:08:58 hartmans Exp $ +# $Id: Makefile,v 1.5 2004/09/24 13:13:21 kukuk Exp $ # # This Makefile controls a build process of $(TITLE) module and # application for Linux-PAM. You should not modify this Makefile @@ -44,6 +44,12 @@ endif APPLICATION = $(TITLE) APPMODE = 755 +LINK_PAMMODUTILS = -L../pammodutil -lpammodutil -L../../libpam -lpam +INCLUDE_PAMMODUTILS = -I../pammodutil/include + +LDFLAGS += $(LINK_PAMMODUTILS) +CFLAGS += $(INCLUDE_PAMMODUTILS) + ####################### don't edit below ####################### all: dirs $(LIBSHARED) $(LIBSTATIC) register $(APPLICATION) @@ -65,10 +71,10 @@ ifdef DYNAMIC $(LIBOBJD): $(LIBSRC) $(LIBSHARED): $(LIBOBJD) - $(LD_D) -o $@ $(LIBOBJD) + $(LD_D) -o $@ $(LIBOBJD) $(LDFLAGS) $(APPLICATION): $(APPOBJD) $(TITLE).c - $(CC) $(CFLAGS) -o $@ $(APPOBJD) $(LOADLIBES) + $(CC) $(CFLAGS) -o $@ $(APPOBJD) $(LDFLAGS) $(LOADLIBES) endif diff --git a/Linux-PAM/modules/pam_tally/README b/Linux-PAM/modules/pam_tally/README index 4c421648..c8b715bd 100644 --- a/Linux-PAM/modules/pam_tally/README +++ b/Linux-PAM/modules/pam_tally/README @@ -1,5 +1,5 @@ SUMMARY: - pam_tally: + pam_tally.so: Maintains a count of attempted accesses, can reset count on success, can deny access if too many attempts fail. @@ -9,43 +9,57 @@ SUMMARY: * onerr=[succeed|fail] (if something weird happens such as unable to open the file, what to do?) * file=/where/to/keep/counts (default /var/log/faillog) + * audit (will display the username typed if the user is not found) (auth) - Authentication phase increments attempted login counter. - * no_magic_root (root DOES increment counter. Use for - daemon-based stuff, like telnet/rsh/login) + Authentication phase first checks if user should be denied access + and if not it increments attempted login counter. Then on call to + pam_setcred it resets the attempts counter if the user is NOT + magic root. + * deny=n (deny access if tally for this user exceeds n) + + * lock_time=n (always deny for n seconds after failed attempt) + + * unlock_time=n (allow access after n seconds after the last + failed attempt with exceeded tally) - (account) - Account phase can deny access and/or reset attempts counter. - * deny=n (deny access if tally for this user exceeds n; - The presence of deny=n changes the default for - reset/no_reset to reset, unless the user trying to - gain access is root and the no_magic_root option - has NOT been specified.) - - * no_magic_root (access attempts by root DON'T ignore deny. - Use this for daemon-based stuff, like telnet/rsh/login) + * magic_root (access attempts by root as requesting user ignore + deny and don't change counter. + Use this for su and similar services.) + * even_deny_root_account (Root can become unavailable. BEWARE. Note that magic root trying to gain root bypasses this, but normal users can be locked out.) - * reset (reset count to 0 on successful entry, even for - magic root) - * no_reset (don't reset count on successful entry) - This is the default unless deny exists and the - user attempting access is NOT magic root. - * per_user (If /var/log/faillog contains a non-zero - .fail_max field for this user then use it - instead of deny=n parameter) + .fail_max/.fail_locktime field for this user then use it + instead of deny=n/lock_time=n parameter.) * no_lock_time (Don't use .fail_locktime filed in /var/log/faillog for this user) + * no_reset (don't reset count on successful entry, + only decrement) + + + (account) + Account phase resets attempts counter if the user is NOT magic root. + This phase can be used optionaly for services which don't call + pam_setcred correctly or if the reset should be done regardless + of the failure of the account phase of other modules. + + * magic_root (access attempts by root as requesting user + don't change counter. + Use this for su and similar services.) + + * no_reset (don't reset count on successful entry, + only decrement) + Also checks to make sure that the counts file is a plain file and not world writable. - Tim Baverstock <warwick@sable.demon.co.uk>, v0.1 5 March 1997 + - Tomas Mraz <tmraz@redhat.com>, v0.2 5 January 2005 LONGER: @@ -53,20 +67,20 @@ pam_tally comes in two parts: pam_tally.so and pam_tally. pam_tally.so sits in a pam config file, in the auth and account sections. -In the auth section, it increments a per-uid counter for each attempted -login, in the account section, it denies access if attempted logins -exceed some threashold and/or resets that counter to zero on successful -login. +In the auth section, it denies access if attempted logins exceed some +threshold and it increments a per-uid counter for each attempted login, +in the account section, it resets that counter to zero on successful +login. If the module isn't used in the account section it resets the counter +to zero on call to pam_setcred. Root is treated specially: -1. When a process already running as root tries to access some service, the -access is `magic', and bypasses pam_tally's checks: handy for `su'ing from -root into an account otherwise blocked. However, for services like telnet or -login which always effectively run from the root account, root (ie everyone) -shouldn't be granted this magic status, and the flag `no_magic_root' should -be set in this situation, as noted in the summary above. [This option may -be obsolete, with `sufficient root' processing.] +1. When a process already running as root tries to access some service and the +'magic_root' flag is set, the access is `magic', and bypasses pam_tally's +checks: handy for `su'ing from root into an account otherwise blocked. +NOTE: This was changed from the previous version of pam_tally where the default +was to treat root as magic and there were the 'no_magic_root' flag. However +for most of services the current default make sense. 2. Normally, failed attempts to access root will NOT cause the root account to become blocked, to prevent denial-of-service: if your users aren't @@ -93,3 +107,10 @@ The (4.0 Redhat) utilities seem to do funny things with uid, and I'm not wholly sure I understood what I should have been doing anyway so the `keep a count of current logins' bit has been #ifdef'd out and you can only reset the counter on successful authentication, for now. + +IMPORTANT NOTICE: +In the original version of pam_tally there was a bug where the information +if the password was correct or not was leaked by returning error from +different pam management phases. This was solved by moving the denying +functionality to the auth phase. However it's necessary to update the pam +configuration by moving the required options (as deny=N) to the auth phase. diff --git a/Linux-PAM/modules/pam_tally/faillog.h b/Linux-PAM/modules/pam_tally/faillog.h index fa9c414f..0f16261b 100644 --- a/Linux-PAM/modules/pam_tally/faillog.h +++ b/Linux-PAM/modules/pam_tally/faillog.h @@ -30,7 +30,7 @@ /* * faillog.h - login failure logging file format * - * $Id: faillog.h,v 1.1.1.1 2001/04/29 04:17:35 hartmans Exp $ + * $Id: faillog.h,v 1.1.1.1 2000/06/20 22:11:59 agmorgan Exp $ * * The login failure file is maintained by login(1) and faillog(8) * Each record in the file represents a separate UID and the file diff --git a/Linux-PAM/modules/pam_tally/pam_tally.c b/Linux-PAM/modules/pam_tally/pam_tally.c index a2fed80b..1e48662e 100644 --- a/Linux-PAM/modules/pam_tally/pam_tally.c +++ b/Linux-PAM/modules/pam_tally/pam_tally.c @@ -1,7 +1,7 @@ /* * pam_tally.c * - * $Id: pam_tally.c,v 1.1.1.2 2002/09/15 20:08:59 hartmans Exp $ + * $Id: pam_tally.c,v 1.15 2005/01/24 14:04:17 t8m Exp $ */ @@ -9,6 +9,9 @@ * 5 March 1997 * * Stuff stolen from pam_rootok and pam_listfile + * + * Changes by Tomas Mraz <tmraz@redhat.com> 5 January 2005 + * Audit option added for Tomas patch by Sebastien Tricaud <toady@gscore.org> 13 January 2005 */ #include <security/_pam_aconf.h> @@ -49,18 +52,13 @@ /* #define PAM_SM_PASSWORD */ #include <security/pam_modules.h> +#include <security/_pam_modutil.h> /*---------------------------------------------------------------------*/ #define DEFAULT_LOGFILE "/var/log/faillog" #define MODULE_NAME "pam_tally" -enum TALLY_RESET { - TALLY_RESET_DEFAULT, - TALLY_RESET_RESET, - TALLY_RESET_NO_RESET -}; - #define tally_t unsigned short int #define TALLY_FMT "%hu" #define TALLY_HI ((tally_t)~0L) @@ -78,6 +76,28 @@ struct fail_s { #endif /* ndef MAIN */ }; +struct tally_options { + const char *filename; + tally_t deny; + long lock_time; + long unlock_time; + unsigned int ctrl; +}; + +#define PHASE_UNKNOWN 0 +#define PHASE_AUTH 1 +#define PHASE_ACCOUNT 2 +#define PHASE_SESSION 3 + +#define OPT_MAGIC_ROOT 01 +#define OPT_FAIL_ON_ERROR 02 +#define OPT_DENY_ROOT 04 +#define OPT_PER_USER 010 +#define OPT_NO_LOCK_TIME 020 +#define OPT_NO_RESET 040 +#define OPT_AUDIT 100 + + /*---------------------------------------------------------------------*/ /* some syslogging */ @@ -100,6 +120,94 @@ static void _pam_log(int err, const char *format, ...) /*---------------------------------------------------------------------*/ +/* --- Support function: parse arguments --- */ + +static void log_phase_no_auth( int phase, const char *argv ) +{ + if ( phase != PHASE_AUTH ) { + _pam_log(LOG_ERR, + MODULE_NAME ": option %s allowed in auth phase only", argv); + } +} + +static int tally_parse_args( struct tally_options *opts, int phase, + int argc, const char **argv ) +{ + memset(opts, 0, sizeof(*opts)); + opts->filename = DEFAULT_LOGFILE; + + for ( ; argc-- > 0; ++argv ) { + + if ( ! strncmp( *argv, "file=", 5 ) ) { + const char *from = *argv + 5; + if ( *from!='/' || strlen(from)>FILENAME_MAX-1 ) { + _pam_log(LOG_ERR, + MODULE_NAME ": filename not /rooted or too long; ", + *argv); + return PAM_AUTH_ERR; + } + opts->filename = from; + } + else if ( ! strcmp( *argv, "onerr=fail" ) ) { + opts->ctrl |= OPT_FAIL_ON_ERROR; + } + else if ( ! strcmp( *argv, "onerr=succeed" ) ) { + opts->ctrl &= ~OPT_FAIL_ON_ERROR; + } + else if ( ! strcmp( *argv, "magic_root" ) ) { + opts->ctrl |= OPT_MAGIC_ROOT; + } + else if ( ! strcmp( *argv, "even_deny_root_account" ) ) { + log_phase_no_auth(phase, *argv); + opts->ctrl |= OPT_DENY_ROOT; + } + else if ( ! strncmp( *argv, "deny=", 5 ) ) { + log_phase_no_auth(phase, *argv); + if ( sscanf((*argv)+5,TALLY_FMT,&opts->deny) != 1 ) { + _pam_log(LOG_ERR,"bad number supplied; %s",*argv); + return PAM_AUTH_ERR; + } + } + else if ( ! strncmp( *argv, "lock_time=", 10 ) ) { + log_phase_no_auth(phase, *argv); + if ( sscanf((*argv)+10,"%ld",&opts->lock_time) != 1 ) { + _pam_log(LOG_ERR,"bad number supplied; %s",*argv); + return PAM_AUTH_ERR; + } + } + else if ( ! strncmp( *argv, "unlock_time=", 12 ) ) { + log_phase_no_auth(phase, *argv); + if ( sscanf((*argv)+12,"%ld",&opts->unlock_time) != 1 ) { + _pam_log(LOG_ERR,"bad number supplied; %s",*argv); + return PAM_AUTH_ERR; + } + } + else if ( ! strcmp( *argv, "per_user" ) ) + { + log_phase_no_auth(phase, *argv); + opts->ctrl |= OPT_PER_USER; + } + else if ( ! strcmp( *argv, "no_lock_time") ) + { + log_phase_no_auth(phase, *argv); + opts->ctrl |= OPT_NO_LOCK_TIME; + } + else if ( ! strcmp( *argv, "no_reset" ) ) { + opts->ctrl |= OPT_NO_RESET; + } + else if ( ! strcmp ( *argv, "audit") ) { + opts->ctrl |= OPT_AUDIT; + } + else { + _pam_log(LOG_ERR, MODULE_NAME ": unknown option; %s",*argv); + } + } + + return PAM_SUCCESS; +} + +/*---------------------------------------------------------------------*/ + /* --- Support function: get uid (and optionally username) from PAM or cline_user --- */ @@ -107,9 +215,9 @@ static void _pam_log(int err, const char *format, ...) static char *cline_user=0; /* cline_user is used in the administration prog */ #endif -static int pam_get_uid( pam_handle_t *pamh, uid_t *uid, const char **userp ) +static int pam_get_uid( pam_handle_t *pamh, uid_t *uid, const char **userp, struct tally_options *opts) { - const char *user; + const char *user = NULL; struct passwd *pw; #ifdef MAIN @@ -123,8 +231,10 @@ static int pam_get_uid( pam_handle_t *pamh, uid_t *uid, const char **userp ) return PAM_AUTH_ERR; } - if ( ! ( pw = getpwnam( user ) ) ) { - _pam_log(LOG_ERR,MODULE_NAME ": pam_get_uid; no such user %s",user); + if ( ! ( pw = _pammodutil_getpwnam( pamh, user ) ) ) { + opts->ctrl & OPT_AUDIT ? + _pam_log(LOG_ERR,MODULE_NAME ": pam_get_uid; no such user %s",user) : + _pam_log(LOG_ERR,MODULE_NAME ": pam_get_uid; no such user"); return PAM_USER_UNKNOWN; } @@ -135,6 +245,42 @@ static int pam_get_uid( pam_handle_t *pamh, uid_t *uid, const char **userp ) /*---------------------------------------------------------------------*/ +/* --- Support functions: set/get tally data --- */ + +static void _cleanup( pam_handle_t *pamh, void *data, int error_status ) + { + free(data); + } + +static void tally_set_data( pam_handle_t *pamh, time_t oldtime ) + { + time_t *data; + + if ( (data=malloc(sizeof(time_t))) != NULL ) { + *data = oldtime; + pam_set_data(pamh, MODULE_NAME, (void *)data, _cleanup); + } + } + +static int tally_get_data( pam_handle_t *pamh, time_t *oldtime ) + { + int rv; + const void *data; + + rv = pam_get_data(pamh, MODULE_NAME, &data); + if ( rv == PAM_SUCCESS && oldtime != NULL ) { + *oldtime = *(const time_t *)data; + pam_set_data(pamh, MODULE_NAME, NULL, NULL); + } + else { + rv = -1; + *oldtime = 0; + } + return rv; + } + +/*---------------------------------------------------------------------*/ + /* --- Support function: open/create tallyfile and return tally for uid --- */ /* If on entry *tally==TALLY_HI, tallyfile is opened READONLY */ @@ -189,7 +335,8 @@ static int get_tally( tally_t *tally, if ( fseek( *TALLY, uid * sizeof(struct faillog), SEEK_SET ) ) { _pam_log(LOG_ALERT, "fseek failed %s", filename); - return PAM_AUTH_ERR; + fclose(*TALLY); + return PAM_AUTH_ERR; } if ( fileinfo.st_size <= uid * sizeof(struct faillog) ) { @@ -253,82 +400,42 @@ static int set_tally( tally_t tally, #define PAM_FUNCTION(name) \ PAM_EXTERN int name (pam_handle_t *pamh,int flags,int argc,const char **argv) -#define RETURN_ERROR(i) return ((fail_on_error)?(i):(PAM_SUCCESS)) +#define RETURN_ERROR(i) return ((opts->ctrl & OPT_FAIL_ON_ERROR)?(i):(PAM_SUCCESS)) /*---------------------------------------------------------------------*/ /* --- tally bump function: bump tally for uid by (signed) inc --- */ -static int tally_bump (int inc, +static int tally_bump (int inc, time_t *oldtime, pam_handle_t *pamh, - int flags, - int argc, - const char **argv) { - uid_t uid; - - int - fail_on_error = FALSE; + uid_t uid, + const char *user, + struct tally_options *opts) { tally_t tally = 0; /* !TALLY_HI --> Log opened for update */ - char - no_magic_root = FALSE; - - char - filename[ FILENAME_MAX ] = DEFAULT_LOGFILE; - - /* Should probably decode the parameters before anything else. */ - - { - for ( ; argc-- > 0; ++argv ) { - - /* generic options.. um, ignored. :] */ - - if ( ! strcmp( *argv, "no_magic_root" ) ) { - no_magic_root = TRUE; - } - else if ( ! strncmp( *argv, "file=", 5 ) ) { - char const - *from = (*argv)+5; - char - *to = filename; - if ( *from!='/' || strlen(from)>FILENAME_MAX-1 ) { - _pam_log(LOG_ERR, - MODULE_NAME ": filename not /rooted or too long; ", - *argv); - RETURN_ERROR( PAM_AUTH_ERR ); - } - while ( ( *to++ = *from++ ) ); - } - else if ( ! strcmp( *argv, "onerr=fail" ) ) { - fail_on_error=TRUE; - } - else if ( ! strcmp( *argv, "onerr=succeed" ) ) { - fail_on_error=FALSE; - } - else { - _pam_log(LOG_ERR, MODULE_NAME ": unknown option; %s",*argv); - } - } /* for() */ - } - - { FILE *TALLY = NULL; const char - *user = NULL, *remote_host = NULL, *cur_tty = NULL; struct fail_s fs, *fsp = &fs; + int i; - int i=pam_get_uid(pamh, &uid, &user); - if ( i != PAM_SUCCESS ) RETURN_ERROR( i ); - - i=get_tally( &tally, uid, filename, &TALLY, fsp ); + i=get_tally( &tally, uid, opts->filename, &TALLY, fsp ); /* to remember old fail time (for locktime) */ fsp->fs_fail_time = fsp->fs_faillog.fail_time; - fsp->fs_faillog.fail_time = time(NULL); + if ( inc > 0 ) { + if ( oldtime ) { + *oldtime = fsp->fs_faillog.fail_time; + } + fsp->fs_faillog.fail_time = time(NULL); + } else { + if ( oldtime ) { + fsp->fs_faillog.fail_time = *oldtime; + } + } (void) pam_get_item(pamh, PAM_RHOST, (const void **)&remote_host); if (!remote_host) { @@ -350,7 +457,7 @@ static int tally_bump (int inc, } if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } - if ( no_magic_root || getuid() ) { /* no_magic_root kills uid test */ + if ( !(opts->ctrl & OPT_MAGIC_ROOT) || getuid() ) { /* magic_root doesn't change tally */ tally+=inc; @@ -361,213 +468,215 @@ static int tally_bump (int inc, } } - i=set_tally( tally, uid, filename, &TALLY, fsp ); + i=set_tally( tally, uid, opts->filename, &TALLY, fsp ); if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } - } - return PAM_SUCCESS; + return PAM_SUCCESS; } -/*---------------------------------------------------------------------*/ - -/* --- authentication management functions (only) --- */ - -#ifdef PAM_SM_AUTH - -PAM_FUNCTION( pam_sm_authenticate ) { - return tally_bump( 1, pamh, flags, argc, argv); -} - -/* --- Seems to need this function. Ho hum. --- */ - -PAM_FUNCTION( pam_sm_setcred ) { return PAM_SUCCESS; } - -#endif - -/*---------------------------------------------------------------------*/ - -/* --- session management functions (only) --- */ - -/* - * Unavailable until .so files can be suid - */ - -#ifdef PAM_SM_SESSION - -/* To maintain a balance-tally of successful login/outs */ - -PAM_FUNCTION( pam_sm_open_session ) { - return tally_bump( 1, pamh, flags, argc, argv); -} - -PAM_FUNCTION( pam_sm_close_session ) { - return tally_bump(-1, pamh, flags, argc, argv); -} - -#endif - -/*---------------------------------------------------------------------*/ - -/* --- authentication management functions (only) --- */ - -#ifdef PAM_SM_AUTH - -/* To lock out a user with an unacceptably high tally */ - -PAM_FUNCTION( pam_sm_acct_mgmt ) { - uid_t - uid; - - int - fail_on_error = FALSE; +static int tally_check (time_t oldtime, + pam_handle_t *pamh, + uid_t uid, + const char *user, + struct tally_options *opts) { tally_t - deny = 0; + deny = opts->deny; tally_t tally = 0; /* !TALLY_HI --> Log opened for update */ + long + lock_time = opts->lock_time; - char - no_magic_root = FALSE, - even_deny_root_account = FALSE; - char per_user = FALSE; /* if true then deny=.fail_max for user */ - char no_lock_time = FALSE; /* if true then don't use .fail_locktime */ - - const char - *user = NULL; - - enum TALLY_RESET - reset = TALLY_RESET_DEFAULT; - - char - filename[ FILENAME_MAX ] = DEFAULT_LOGFILE; - - /* Should probably decode the parameters before anything else. */ - - { - for ( ; argc-- > 0; ++argv ) { - - /* generic options.. um, ignored. :] */ - - if ( ! strcmp( *argv, "no_magic_root" ) ) { - no_magic_root = TRUE; - } - else if ( ! strcmp( *argv, "even_deny_root_account" ) ) { - even_deny_root_account = TRUE; - } - else if ( ! strcmp( *argv, "reset" ) ) { - reset = TALLY_RESET_RESET; - } - else if ( ! strcmp( *argv, "no_reset" ) ) { - reset = TALLY_RESET_NO_RESET; - } - else if ( ! strncmp( *argv, "file=", 5 ) ) { - char const - *from = (*argv)+5; - char - *to = filename; - if ( *from != '/' || strlen(from) > FILENAME_MAX-1 ) { - _pam_log(LOG_ERR, - MODULE_NAME ": filename not /rooted or too long; ", - *argv); - RETURN_ERROR( PAM_AUTH_ERR ); - } - while ( ( *to++ = *from++ ) ); - } - else if ( ! strncmp( *argv, "deny=", 5 ) ) { - if ( sscanf((*argv)+5,TALLY_FMT,&deny) != 1 ) { - _pam_log(LOG_ERR,"bad number supplied; %s",*argv); - RETURN_ERROR( PAM_AUTH_ERR ); - } - } - else if ( ! strcmp( *argv, "onerr=fail" ) ) { - fail_on_error=TRUE; - } - else if ( ! strcmp( *argv, "onerr=succeed" ) ) { - fail_on_error=FALSE; - } - else if ( ! strcmp( *argv, "per_user" ) ) - { - per_user = TRUE; - } - else if ( ! strcmp( *argv, "no_lock_time") ) - { - no_lock_time = TRUE; - } - else { - _pam_log(LOG_ERR, MODULE_NAME ": unknown option; %s",*argv); - } - } /* for() */ - } - - { struct fail_s fs, *fsp = &fs; FILE *TALLY=0; - int i=pam_get_uid(pamh, &uid, &user); - if ( i != PAM_SUCCESS ) RETURN_ERROR( i ); + int i; - i=get_tally( &tally, uid, filename, &TALLY, fsp ); - if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } + i=get_tally( &tally, uid, opts->filename, &TALLY, fsp ); + if (TALLY) fclose(TALLY); + if ( i != PAM_SUCCESS ) { RETURN_ERROR( i ); } - if ( no_magic_root || getuid() ) { /* no_magic_root kills uid test */ + if ( !(opts->ctrl & OPT_MAGIC_ROOT) || getuid() ) { /* magic_root skips tally check */ /* To deny or not to deny; that is the question */ /* if there's .fail_max entry and per_user=TRUE then deny=.fail_max */ - if ( (fsp->fs_faillog.fail_max) && (per_user) ) { + if ( (fsp->fs_faillog.fail_max) && (opts->ctrl & OPT_PER_USER) ) { deny = fsp->fs_faillog.fail_max; } - if (fsp->fs_faillog.fail_locktime && fsp->fs_fail_time - && (!no_lock_time) ) + if ( (fsp->fs_faillog.fail_locktime) && (opts->ctrl & OPT_PER_USER) ) { + lock_time = fsp->fs_faillog.fail_locktime; + } + if (lock_time && oldtime + && !(opts->ctrl & OPT_NO_LOCK_TIME) ) { - if ( (fsp->fs_faillog.fail_locktime + fsp->fs_fail_time) > time(NULL) ) + if ( lock_time + oldtime > time(NULL) ) { _pam_log(LOG_NOTICE, "user %s ("UID_FMT") has time limit [%lds left]" " since last failure.", user,uid, - fsp->fs_fail_time+fsp->fs_faillog.fail_locktime + oldtime+lock_time -time(NULL)); return PAM_AUTH_ERR; } } + if (opts->unlock_time && oldtime) + { + if ( opts->unlock_time + oldtime <= time(NULL) ) + { /* ignore deny check after unlock_time elapsed */ + return PAM_SUCCESS; + } + } if ( ( deny != 0 ) && /* deny==0 means no deny */ ( tally > deny ) && /* tally>deny means exceeded */ - ( even_deny_root_account || uid ) /* even_deny stops uid check */ + ( ((opts->ctrl & OPT_DENY_ROOT) || uid) ) /* even_deny stops uid check */ ) { _pam_log(LOG_NOTICE,"user %s ("UID_FMT") tally "TALLY_FMT", deny "TALLY_FMT, user, uid, tally, deny); return PAM_AUTH_ERR; /* Only unconditional failure */ } - - /* resets for explicit reset - * or by default if deny exists and not magic-root - */ - - if ( ( reset == TALLY_RESET_RESET ) || - ( reset == TALLY_RESET_DEFAULT && deny ) ) { tally=0; } } - else /* is magic root */ { - /* Magic root skips deny test... */ + return PAM_SUCCESS; +} + +static int tally_reset (pam_handle_t *pamh, + uid_t uid, + const char *user, + struct tally_options *opts) { + tally_t + tally = 0; /* !TALLY_HI --> Log opened for update */ + + struct fail_s fs, *fsp = &fs; + FILE *TALLY=0; + int i; + + i=get_tally( &tally, uid, opts->filename, &TALLY, fsp ); + if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } + + /* resets if not magic root + */ - /* Magic root only resets on explicit reset, regardless of deny */ + if ( (!(opts->ctrl & OPT_MAGIC_ROOT) || getuid()) + && !(opts->ctrl & OPT_NO_RESET) ) + { tally=0; } - if ( reset == TALLY_RESET_RESET ) { tally=0; } - } if (tally == 0) { fsp->fs_faillog.fail_time = (time_t) 0; strcpy(fsp->fs_faillog.fail_line, ""); } - i=set_tally( tally, uid, filename, &TALLY, fsp ); + + i=set_tally( tally, uid, opts->filename, &TALLY, fsp ); if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } - } - return PAM_SUCCESS; + return PAM_SUCCESS; +} + +/*---------------------------------------------------------------------*/ + +/* --- authentication management functions (only) --- */ + +#ifdef PAM_SM_AUTH + +PAM_FUNCTION( pam_sm_authenticate ) { + int + rvcheck, rvbump; + time_t + oldtime = 0; + struct tally_options + options, *opts = &options; + uid_t + uid; + const char + *user; + + rvcheck = tally_parse_args(opts, PHASE_AUTH, argc, argv); + if ( rvcheck != PAM_SUCCESS ) + RETURN_ERROR( rvcheck ); + + rvcheck = pam_get_uid(pamh, &uid, &user, opts); + if ( rvcheck != PAM_SUCCESS ) + RETURN_ERROR( rvcheck ); + + rvbump = tally_bump(1, &oldtime, pamh, uid, user, opts); + rvcheck = tally_check(oldtime, pamh, uid, user, opts); + + tally_set_data(pamh, oldtime); + + return rvcheck != PAM_SUCCESS ? rvcheck : rvbump; +} + +PAM_FUNCTION( pam_sm_setcred ) { + int + rv; + time_t + oldtime = 0; + struct tally_options + options, *opts = &options; + uid_t + uid; + const char + *user; + + rv = tally_parse_args(opts, PHASE_AUTH, argc, argv); + if ( rv != PAM_SUCCESS ) + RETURN_ERROR( rv ); + + rv = pam_get_uid(pamh, &uid, &user, opts); + if ( rv != PAM_SUCCESS ) + RETURN_ERROR( rv ); + + if ( tally_get_data(pamh, &oldtime) != 0 ) + /* no data found */ + return PAM_SUCCESS; + + if ( (rv=tally_bump(-1, &oldtime, pamh, uid, user, opts)) != PAM_SUCCESS ) + return rv; + return tally_reset(pamh, uid, user, opts); +} + +#endif + +/*---------------------------------------------------------------------*/ + +/* --- authentication management functions (only) --- */ + +#ifdef PAM_SM_ACCOUNT + +/* To reset failcount of user on successfull login */ + +PAM_FUNCTION( pam_sm_acct_mgmt ) { + int + rv; + time_t + oldtime = 0; + struct tally_options + options, *opts = &options; + uid_t + uid; + const char + *user; + + rv = tally_parse_args(opts, PHASE_ACCOUNT, argc, argv); + if ( rv != PAM_SUCCESS ) + RETURN_ERROR( rv ); + + rv = pam_get_uid(pamh, &uid, &user, opts); + if ( rv != PAM_SUCCESS ) + RETURN_ERROR( rv ); + + if ( tally_get_data(pamh, &oldtime) != 0 ) + /* no data found */ + return PAM_SUCCESS; + + if ( (rv=tally_bump(-1, &oldtime, pamh, uid, user, opts)) != PAM_SUCCESS ) + return rv; + return tally_reset(pamh, uid, user, opts); } -#endif /* #ifdef PAM_SM_AUTH */ +#endif /* #ifdef PAM_SM_ACCOUNT */ /*-----------------------------------------------------------------------*/ @@ -589,18 +698,9 @@ struct pam_module _pam_tally_modstruct = { #else NULL, #endif -#ifdef PAM_SM_SESSION - pam_sm_open_session, - pam_sm_close_session, -#else NULL, NULL, -#endif -#ifdef PAM_SM_PASSWORD - pam_sm_chauthtok, -#else NULL, -#endif }; #endif /* #ifdef PAM_STATIC */ @@ -670,7 +770,12 @@ int main ( int argc, char **argv ) { uid_t uid; tally_t tally=cline_reset; FILE *TALLY=0; - int i=pam_get_uid( NULL, &uid, NULL); + struct tally_options opts; + int i; + + memset(&opts, 0, sizeof(opts)); + opts.ctrl = OPT_AUDIT; + i=pam_get_uid( NULL, &uid, NULL, &opts); if ( i != PAM_SUCCESS ) { fprintf(stderr,"%s: %s\n",*argv,pam_errors(i)); exit(0); diff --git a/Linux-PAM/modules/pam_time/Makefile b/Linux-PAM/modules/pam_time/Makefile index 647d3081..4aa4e276 100644 --- a/Linux-PAM/modules/pam_time/Makefile +++ b/Linux-PAM/modules/pam_time/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:35 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:05 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_time/README b/Linux-PAM/modules/pam_time/README index 4ef51531..0228b907 100644 --- a/Linux-PAM/modules/pam_time/README +++ b/Linux-PAM/modules/pam_time/README @@ -1,4 +1,4 @@ -$Id: README,v 1.1.1.1 2001/04/29 04:17:35 hartmans Exp $ +$Id: README,v 1.2 2000/12/04 19:02:35 baggins Exp $ This is a help file for the pam_time module. It explains the need for pam_time and also the syntax of the /etc/security/time.conf file. diff --git a/Linux-PAM/modules/pam_time/pam_time.c b/Linux-PAM/modules/pam_time/pam_time.c index 5757a557..c04180f2 100644 --- a/Linux-PAM/modules/pam_time/pam_time.c +++ b/Linux-PAM/modules/pam_time/pam_time.c @@ -1,15 +1,15 @@ /* pam_time module */ /* - * $Id: pam_time.c,v 1.1.1.2 2002/09/15 20:08:59 hartmans Exp $ + * $Id: pam_time.c,v 1.5 2004/09/22 09:37:50 kukuk Exp $ * * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/6/22 * (File syntax and much other inspiration from the shadow package * shadow-960129) */ -const static char rcsid[] = -"$Id: pam_time.c,v 1.1.1.2 2002/09/15 20:08:59 hartmans Exp $;\n" +static const char rcsid[] = +"$Id: pam_time.c,v 1.5 2004/09/22 09:37:50 kukuk Exp $;\n" "\t\tVersion 0.22 for Linux-PAM\n" "Copyright (C) Andrew G. Morgan 1996 <morgan@linux.kernel.org>\n"; @@ -127,6 +127,7 @@ static int read_field(int fd, char **buf, int *from, int *to) i = read(fd, *to + *buf, PAM_TIME_BUFLEN - *to); if (i < 0) { _log_err("error reading " PAM_TIME_CONF); + close(fd); return -1; } else if (!i) { close(fd); @@ -166,6 +167,7 @@ static int read_field(int fd, char **buf, int *from, int *to) } else { _log_err("internal error in " __FILE__ " at line %d", __LINE__ ); + close(fd); return -1; } break; diff --git a/Linux-PAM/modules/pam_unix/CHANGELOG b/Linux-PAM/modules/pam_unix/CHANGELOG index 206d30dd..509ce0a3 100644 --- a/Linux-PAM/modules/pam_unix/CHANGELOG +++ b/Linux-PAM/modules/pam_unix/CHANGELOG @@ -1,4 +1,4 @@ -$Id: CHANGELOG,v 1.1.1.1 2001/04/29 04:17:36 hartmans Exp $ +$Id: CHANGELOG,v 1.1.1.1 2000/06/20 22:12:01 agmorgan Exp $ * Mon Aug 16 1999 Jan Rêkorajski <baggins@pld.org.pl> - fixed reentrancy problems diff --git a/Linux-PAM/modules/pam_unix/Makefile b/Linux-PAM/modules/pam_unix/Makefile index 03374512..7f32e073 100644 --- a/Linux-PAM/modules/pam_unix/Makefile +++ b/Linux-PAM/modules/pam_unix/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:36 hartmans Exp $ +# $Id: Makefile,v 1.8 2004/11/08 08:58:37 kukuk Exp $ # # This Makefile controls a build process of the pam_unix modules # for Linux-PAM. You should not modify this Makefile. @@ -18,6 +18,19 @@ include ../../Make.Rules #USE_CRACKLIB=-D"USE_CRACKLIB" #endif +ifeq ($(shell if [ -f /usr/lib/cracklib_dict.hwm ]; then echo yes ; fi),yes) + CRACKLIB_DICTPATH=/usr/lib/cracklib_dict +else + CRACKLIB_DICTPATH=/usr/share/dict/cracklib_dict +endif +EXTRAS += -DCRACKLIB_DICTS=\"$(CRACKLIB_DICTPATH)\" + +ifeq ($(HAVE_LIBCRYPT),yes) + EXTRALS += -lcrypt +endif +ifeq ($(HAVE_LIBNSL),yes) + EXTRALS += -lnsl +endif # do you want to use lckpwdf? ifeq ($(WITH_LCKPWDF),yes) USE_LCKPWDF=-D"USE_LCKPWDF" @@ -37,12 +50,19 @@ endif CHKPWD=unix_chkpwd +BIGCRYPT=bigcrypt + EXTRAS += -DCHKPWD_HELPER=\"$(SUPLEMENTED)/$(CHKPWD)\" +LINK_PAMMODUTILS = -L../pammodutil -lpammodutil +INCLUDE_PAMMODUTILS = -I../pammodutil/include + ######################################################################## -CFLAGS += $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF) $(EXTRAS) -LDLIBS = $(EXTRALS) +CFLAGS += $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF) $(EXTRAS) \ + $(INCLUDE_PAMMODUTILS) + +LDLIBS = $(EXTRALS) $(LINK_PAMMODUTILS) ifdef USE_CRACKLIB CRACKLIB = -lcrack @@ -69,7 +89,8 @@ endif ########################### don't edit below ####################### -all: dirs info $(PLUS) $(LIBSHARED) $(LIBSTATIC) $(CHKPWD) register +all: dirs info $(PLUS) $(LIBSHARED) $(LIBSTATIC) $(CHKPWD) $(BIGCRYPT) \ + register dynamic/%.o : %.c $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ @@ -107,7 +128,7 @@ ifdef DYNAMIC $(LIBOBJD): $(LIBSRC) $(LIBSHARED): $(LIBOBJD) - $(LD_D) -o $@ $(LIBOBJD) $(PLUS) $(CRACKLIB) $(LDLIBS) $(LIBNSL) $(LIBCRYPT) + $(LD_D) -o $@ $(LIBOBJD) $(PLUS) $(CRACKLIB) $(LDLIBS) $(LIBNSL) $(LIBCRYPT) $(NEED_LINK_LIB_C) -L../../libpam -lpam endif ifdef STATIC @@ -120,7 +141,10 @@ endif $(CHKPWD): unix_chkpwd.o md5_good.o md5_broken.o \ md5_crypt_good.o md5_crypt_broken.o \ bigcrypt.o - $(CC) -o $(CHKPWD) $^ $(LDLIBS) $(LIBCRYPT) + $(CC) $(CFLAGS) -o $(CHKPWD) $^ $(LDLIBS) $(LIBCRYPT) + +$(BIGCRYPT): bigcrypt_main.o bigcrypt.o + $(CC) -o $(BIGCRYPT) $^ $(LDLIBS) $(LIBCRYPT) unix_chkpwd.o: unix_chkpwd.c $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ @@ -158,7 +182,7 @@ remove: rm -f $(FAKEROOT)$(SUPLEMENTED)/$(CHKPWD) clean: - rm -f $(LIBOBJD) $(LIBOBJS) $(CHKPWD) *.o *.so core + rm -f $(LIBOBJD) $(LIBOBJS) $(CHKPWD) $(BIGCRYPT) *.o *.so core rm -f *~ *.a *.out *.bak rm -rf dynamic static diff --git a/Linux-PAM/modules/pam_unix/README b/Linux-PAM/modules/pam_unix/README index d6b1f395..afeee3da 100644 --- a/Linux-PAM/modules/pam_unix/README +++ b/Linux-PAM/modules/pam_unix/README @@ -31,5 +31,7 @@ The following options are recognized: nis - use NIS RPC for setting new password remember=X - remember X old passwords, they are kept in /etc/security/opasswd in MD5 crypted form + broken_shadow - ignore errors reading shadow information for + users in the account management module invalid arguments are logged to syslog. diff --git a/Linux-PAM/modules/pam_unix/bigcrypt_main.c b/Linux-PAM/modules/pam_unix/bigcrypt_main.c new file mode 100644 index 00000000..70819072 --- /dev/null +++ b/Linux-PAM/modules/pam_unix/bigcrypt_main.c @@ -0,0 +1,18 @@ +#include <stdio.h> +#include <string.h> + +extern const char *bigcrypt(const char *password, const char *salt); + +int +main(int argc, char **argv) +{ + if (argc < 3) { + fprintf(stderr, "Usage: %s password salt\n", + strchr(argv[0], '/') ? + (strchr(argv[0], '/') + 1) : + argv[0]); + return 0; + } + fprintf(stdout, "%s\n", bigcrypt(argv[1], argv[2])); + return 0; +} diff --git a/Linux-PAM/modules/pam_unix/md5.c b/Linux-PAM/modules/pam_unix/md5.c index 3fb50137..7ee9ed00 100644 --- a/Linux-PAM/modules/pam_unix/md5.c +++ b/Linux-PAM/modules/pam_unix/md5.c @@ -1,5 +1,5 @@ /* - * $Id: md5.c,v 1.1.1.1 2001/04/29 04:17:37 hartmans Exp $ + * $Id: md5.c,v 1.1.1.1 2000/06/20 22:12:03 agmorgan Exp $ * * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was diff --git a/Linux-PAM/modules/pam_unix/md5_crypt.c b/Linux-PAM/modules/pam_unix/md5_crypt.c index 8ae84588..8b7bc66b 100644 --- a/Linux-PAM/modules/pam_unix/md5_crypt.c +++ b/Linux-PAM/modules/pam_unix/md5_crypt.c @@ -1,5 +1,5 @@ /* - * $Id: md5_crypt.c,v 1.1.1.2 2002/09/15 20:09:01 hartmans Exp $ + * $Id: md5_crypt.c,v 1.2 2001/07/10 20:24:16 vorlon Exp $ * * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): diff --git a/Linux-PAM/modules/pam_unix/pam_unix_acct.c b/Linux-PAM/modules/pam_unix/pam_unix_acct.c index 178b6037..02e07ba6 100644 --- a/Linux-PAM/modules/pam_unix/pam_unix_acct.c +++ b/Linux-PAM/modules/pam_unix/pam_unix_acct.c @@ -53,6 +53,7 @@ #define PAM_SM_ACCOUNT #include <security/pam_modules.h> +#include <security/_pam_modutil.h> #ifndef LINUX_PAM #include <security/pam_appl.h> @@ -89,7 +90,7 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, return PAM_USER_UNKNOWN; } - pwent = getpwnam(uname); + pwent = _pammodutil_getpwnam(pamh, uname); if (!pwent) { _log_err(LOG_ALERT, pamh ,"could not identify user (from getpwnam(%s))" @@ -113,7 +114,7 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, return PAM_CRED_INSUFFICIENT; } } - spent = getspnam( uname ); + spent = _pammodutil_getspnam (pamh, uname); if (save_uid == pwent->pw_uid) setreuid( save_uid, save_euid ); else { @@ -122,19 +123,21 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, setreuid( -1, save_euid ); } - } else if (!strcmp( pwent->pw_passwd, "x" )) { - spent = getspnam(uname); - } else { + } else if (_unix_shadowed (pwent)) + spent = _pammodutil_getspnam (pamh, uname); + else return PAM_SUCCESS; - } + + if (!spent) + if (on(UNIX_BROKEN_SHADOW,ctrl)) + return PAM_SUCCESS; if (!spent) return PAM_AUTHINFO_UNAVAIL; /* Couldn't get username from shadow */ curdays = time(NULL) / (60 * 60 * 24); D(("today is %d, last change %d", curdays, spent->sp_lstchg)); - if ((curdays > spent->sp_expire) && (spent->sp_expire != -1) - && (spent->sp_lstchg != 0)) { + if ((curdays > spent->sp_expire) && (spent->sp_expire != -1)) { _log_err(LOG_NOTICE, pamh ,"account %s has expired (account expired)" ,uname); @@ -143,18 +146,6 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, D(("account expired")); return PAM_ACCT_EXPIRED; } - if ((curdays > (spent->sp_lstchg + spent->sp_max + spent->sp_inact)) - && (spent->sp_max != -1) && (spent->sp_inact != -1) - && (spent->sp_lstchg != 0)) { - _log_err(LOG_NOTICE, pamh - ,"account %s has expired (failed to change password)" - ,uname); - _make_remark(pamh, ctrl, PAM_ERROR_MSG, - "Your account has expired; please contact your system administrator"); - D(("account expired 2")); - return PAM_ACCT_EXPIRED; - } - D(("when was the last change")); if (spent->sp_lstchg == 0) { _log_err(LOG_NOTICE, pamh ,"expired password for user %s (root enforced)" @@ -164,7 +155,25 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, D(("need a new password")); return PAM_NEW_AUTHTOK_REQD; } - if (((spent->sp_lstchg + spent->sp_max) < curdays) && (spent->sp_max != -1)) { + if (curdays < spent->sp_lstchg) { + _log_err(LOG_DEBUG, pamh + ,"account %s has password changed in future" + ,uname); + return PAM_SUCCESS; + } + if ((curdays - spent->sp_lstchg > spent->sp_max) + && (curdays - spent->sp_lstchg > spent->sp_inact) + && (curdays - spent->sp_lstchg > spent->sp_max + spent->sp_inact) + && (spent->sp_max != -1) && (spent->sp_inact != -1)) { + _log_err(LOG_NOTICE, pamh + ,"account %s has expired (failed to change password)" + ,uname); + _make_remark(pamh, ctrl, PAM_ERROR_MSG, + "Your account has expired; please contact your system administrator"); + D(("account expired 2")); + return PAM_ACCT_EXPIRED; + } + if ((curdays - spent->sp_lstchg > spent->sp_max) && (spent->sp_max != -1)) { _log_err(LOG_DEBUG, pamh ,"expired password for user %s (password aged)" ,uname); @@ -173,7 +182,7 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, D(("need a new password 2")); return PAM_NEW_AUTHTOK_REQD; } - if ((curdays > (spent->sp_lstchg + spent->sp_max - spent->sp_warn)) + if ((curdays - spent->sp_lstchg > spent->sp_max - spent->sp_warn) && (spent->sp_max != -1) && (spent->sp_warn != -1)) { daysleft = (spent->sp_lstchg + spent->sp_max) - curdays; _log_err(LOG_DEBUG, pamh diff --git a/Linux-PAM/modules/pam_unix/pam_unix_auth.c b/Linux-PAM/modules/pam_unix/pam_unix_auth.c index 67497e06..39e0cde5 100644 --- a/Linux-PAM/modules/pam_unix/pam_unix_auth.c +++ b/Linux-PAM/modules/pam_unix/pam_unix_auth.c @@ -15,13 +15,13 @@ * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. - * + * * ALTERNATIVELY, this product may be distributed under the terms of * the GNU Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) - * + * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -88,7 +88,8 @@ do { \ *ret_data = retval; \ pam_set_data(pamh, "unix_setcred_return", \ (void *) ret_data, setcred_free); \ - } \ + } else if (ret_data) \ + free (ret_data); \ D(("done. [%s]", pam_strerror(pamh, retval))); \ return retval; \ } while (0) @@ -148,7 +149,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags /* if this user does not have a password... */ - if (_unix_blankpasswd(ctrl, name)) { + if (_unix_blankpasswd(pamh, ctrl, name)) { D(("user '%s' has blank passwd", name)); name = NULL; retval = PAM_SUCCESS; @@ -183,7 +184,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags } -/* +/* * The only thing _pam_set_credentials_unix() does is initialization of * UNIX group IDs. * @@ -203,7 +204,7 @@ PAM_EXTERN int pam_sm_setcred(pam_handle_t * pamh, int flags retval = PAM_SUCCESS; D(("recovering return code from auth call")); - /* We will only find something here if UNIX_LIKE_AUTH is set -- + /* We will only find something here if UNIX_LIKE_AUTH is set -- don't worry about an explicit check of argv. */ pam_get_data(pamh, "unix_setcred_return", (const void **) &pretval); if(pretval) { diff --git a/Linux-PAM/modules/pam_unix/pam_unix_passwd.c b/Linux-PAM/modules/pam_unix/pam_unix_passwd.c index 6b51a6b2..2ea57cc6 100644 --- a/Linux-PAM/modules/pam_unix/pam_unix_passwd.c +++ b/Linux-PAM/modules/pam_unix/pam_unix_passwd.c @@ -1,5 +1,5 @@ /* - * Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software. + * Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software. * Copyright (C) 1996. * Copyright (c) Jan Rêkorajski, 1999. * @@ -73,6 +73,8 @@ #include <security/pam_appl.h> #endif /* LINUX_PAM */ +#include <security/_pam_modutil.h> + #include "yppasswd.h" #include "md5.h" #include "support.h" @@ -88,7 +90,7 @@ extern int getrpcport(const char *host, unsigned long prognum, */ #ifdef NEED_LCKPWDF -#include "./lckpwdf.-c" +# include "./lckpwdf.-c" #endif extern char *bigcrypt(const char *key, const char *salt); @@ -114,7 +116,9 @@ extern char *bigcrypt(const char *key, const char *salt); #define MAX_PASSWD_TRIES 3 #define PW_TMPFILE "/etc/npasswd" #define SH_TMPFILE "/etc/nshadow" +#ifndef CRACKLIB_DICTS #define CRACKLIB_DICTS "/usr/share/dict/cracklib_dict" +#endif #define OPW_TMPFILE "/etc/security/nopasswd" #define OLD_PASSWORDS_FILE "/etc/security/opasswd" @@ -215,7 +219,7 @@ static int check_old_password(const char *forwho, const char *newpass) opwfile = fopen(OLD_PASSWORDS_FILE, "r"); if (opwfile == NULL) - return PAM_AUTHTOK_ERR; + return PAM_ABORT; while (fgets(buf, 16380, opwfile)) { if (!strncmp(buf, forwho, strlen(forwho))) { @@ -242,7 +246,8 @@ static int check_old_password(const char *forwho, const char *newpass) return retval; } -static int save_old_password(const char *forwho, const char *oldpass, +static int save_old_password(pam_handle_t *pamh, + const char *forwho, const char *oldpass, int howmany) { static char buf[16384]; @@ -254,6 +259,7 @@ static int save_old_password(const char *forwho, const char *oldpass, int oldmask; int found = 0; struct passwd *pwd = NULL; + struct stat st; if (howmany < 0) { return PAM_SUCCESS; @@ -276,8 +282,25 @@ static int save_old_password(const char *forwho, const char *oldpass, return PAM_AUTHTOK_ERR; } - chown(OPW_TMPFILE, 0, 0); - chmod(OPW_TMPFILE, 0600); + if (fstat (fileno (opwfile), &st) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } + + if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } + if (fchmod (fileno (pwfile), st.st_mode) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } while (fgets(buf, 16380, opwfile)) { if (!strncmp(buf, forwho, strlen(forwho))) { @@ -314,7 +337,7 @@ static int save_old_password(const char *forwho, const char *oldpass, fclose(opwfile); if (!found) { - pwd = getpwnam(forwho); + pwd = _pammodutil_getpwnam(pamh, forwho); if (pwd == NULL) { err = 1; } else { @@ -335,18 +358,20 @@ static int save_old_password(const char *forwho, const char *oldpass, } if (!err) { - rename(OPW_TMPFILE, OLD_PASSWORDS_FILE); - return PAM_SUCCESS; - } else { - unlink(OPW_TMPFILE); - return PAM_AUTHTOK_ERR; + if (!rename(OPW_TMPFILE, OLD_PASSWORDS_FILE)) { + return PAM_SUCCESS; + } } + + unlink(OPW_TMPFILE); + return PAM_AUTHTOK_ERR; } static int _update_passwd(pam_handle_t *pamh, const char *forwho, const char *towhat) { struct passwd *tmpent = NULL; + struct stat st; FILE *pwfile, *opwfile; int err = 1; int oldmask; @@ -364,9 +389,26 @@ static int _update_passwd(pam_handle_t *pamh, return PAM_AUTHTOK_ERR; } - chown(PW_TMPFILE, 0, 0); - chmod(PW_TMPFILE, 0644); - tmpent = fgetpwent(opwfile); + if (fstat (fileno (opwfile), &st) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } + + if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } + if (fchmod (fileno (pwfile), st.st_mode) == -1) + { + fclose (opwfile); + fclose (pwfile); + } + + tmpent = fgetpwent (opwfile); while (tmpent) { if (!strcmp(tmpent->pw_name, forwho)) { /* To shut gcc up */ @@ -375,7 +417,7 @@ static int _update_passwd(pam_handle_t *pamh, char *charp; } assigned_passwd; assigned_passwd.const_charp = towhat; - + tmpent->pw_passwd = assigned_passwd.charp; err = 0; } @@ -394,18 +436,20 @@ static int _update_passwd(pam_handle_t *pamh, } if (!err) { - rename(PW_TMPFILE, "/etc/passwd"); - _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho); - return PAM_SUCCESS; - } else { - unlink(PW_TMPFILE); - return PAM_AUTHTOK_ERR; + if (!rename(PW_TMPFILE, "/etc/passwd")) { + _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho); + return PAM_SUCCESS; + } } + + unlink(PW_TMPFILE); + return PAM_AUTHTOK_ERR; } -static int _update_shadow(const char *forwho, char *towhat) +static int _update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat) { struct spwd *spwdent = NULL, *stmpent = NULL; + struct stat st; FILE *pwfile, *opwfile; int err = 1; int oldmask; @@ -427,8 +471,26 @@ static int _update_shadow(const char *forwho, char *towhat) return PAM_AUTHTOK_ERR; } - chown(SH_TMPFILE, 0, 0); - chmod(SH_TMPFILE, 0600); + if (fstat (fileno (opwfile), &st) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } + + if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } + if (fchmod (fileno (pwfile), st.st_mode) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } + stmpent = fgetspent(opwfile); while (stmpent) { @@ -455,12 +517,14 @@ static int _update_shadow(const char *forwho, char *towhat) } if (!err) { - rename(SH_TMPFILE, "/etc/shadow"); - return PAM_SUCCESS; - } else { - unlink(SH_TMPFILE); - return PAM_AUTHTOK_ERR; + if (!rename(SH_TMPFILE, "/etc/shadow")) { + _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho); + return PAM_SUCCESS; + } } + + unlink(SH_TMPFILE); + return PAM_AUTHTOK_ERR; } static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, @@ -471,14 +535,28 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, D(("called")); - setpwent(); pwd = getpwnam(forwho); - endpwent(); - if (pwd == NULL) - return PAM_AUTHTOK_ERR; + if (pwd == NULL) { + retval = PAM_AUTHTOK_ERR; + goto done; + } - if (on(UNIX_NIS, ctrl)) { + if (_unix_comesfromsource(pamh, forwho, 1, 0)) { + /* first, save old password */ + if (save_old_password(pamh, forwho, fromwhat, remember)) { + retval = PAM_AUTHTOK_ERR; + goto done; + } + if (on(UNIX_SHADOW, ctrl) || _unix_shadowed(pwd)) { + retval = _update_shadow(pamh, forwho, towhat); + if (retval == PAM_SUCCESS) + if (!_unix_shadowed(pwd)) + retval = _update_passwd(pamh, forwho, "x"); + } else { + retval = _update_passwd(pamh, forwho, towhat); + } + } else if (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, forwho, 0, 1)) { struct timeval timeout; struct yppasswd yppwd; CLIENT *clnt; @@ -486,6 +564,10 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, int status; int err = 0; + /* Unlock passwd file to avoid deadlock */ +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif /* Make RPC call to NIS server */ if ((master = getNISserver(pamh)) == NULL) return PAM_TRY_AGAIN; @@ -498,7 +580,7 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, yppwd.newpw.pw_gecos = pwd->pw_gecos; yppwd.newpw.pw_dir = pwd->pw_dir; yppwd.newpw.pw_shell = pwd->pw_shell; - yppwd.oldpass = fromwhat; + yppwd.oldpass = fromwhat ? fromwhat : ""; yppwd.newpw.pw_passwd = towhat; D(("Set password %s for %s", yppwd.newpw.pw_passwd, forwho)); @@ -540,17 +622,11 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, #endif return retval; } - /* first, save old password */ - if (save_old_password(forwho, fromwhat, remember)) { - return PAM_AUTHTOK_ERR; - } - if (on(UNIX_SHADOW, ctrl) || (strcmp(pwd->pw_passwd, "x") == 0)) { - retval = _update_shadow(forwho, towhat); - if (retval == PAM_SUCCESS) - retval = _update_passwd(pamh, forwho, "x"); - } else { - retval = _update_passwd(pamh, forwho, towhat); - } + +done: +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif return retval; } @@ -563,13 +639,11 @@ static int _unix_verify_shadow(const char *user, unsigned int ctrl) int retval = PAM_SUCCESS; /* UNIX passwords area */ - setpwent(); pwd = getpwnam(user); /* Get password file entry... */ - endpwent(); if (pwd == NULL) return PAM_AUTHINFO_UNAVAIL; /* We don't need to do the rest... */ - if (strcmp(pwd->pw_passwd, "x") == 0) { + if (_unix_shadowed(pwd)) { /* ...and shadow password file entry for this user, if shadowing is enabled */ setspent(); @@ -579,7 +653,7 @@ static int _unix_verify_shadow(const char *user, unsigned int ctrl) if (spwdent == NULL) return PAM_AUTHINFO_UNAVAIL; } else { - if (strcmp(pwd->pw_passwd,"*NP*") == 0) { /* NIS+ */ + if (strcmp(pwd->pw_passwd,"*NP*") == 0) { /* NIS+ */ uid_t save_uid; save_uid = geteuid(); @@ -661,11 +735,17 @@ static int _pam_unix_approve_pass(pam_handle_t * pamh #else if (strlen(pass_new) < 6) remark = "You must choose a longer password"; - D(("lenth check [%s]", remark)); + D(("length check [%s]", remark)); #endif - if (on(UNIX_REMEMBER_PASSWD, ctrl)) - if ((retval = check_old_password(user, pass_new)) != PAM_SUCCESS) + if (on(UNIX_REMEMBER_PASSWD, ctrl)) { + if ((retval = check_old_password(user, pass_new)) == PAM_AUTHTOK_ERR) remark = "Password has been already used. Choose another."; + if (retval == PAM_ABORT) { + _log_err(LOG_ERR, pamh, "can't open %s file to check old passwords", + OLD_PASSWORDS_FILE); + return retval; + } + } } if (remark) { _make_remark(pamh, ctrl, PAM_ERROR_MSG, remark); @@ -689,33 +769,12 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, D(("called.")); -#ifdef USE_LCKPWDF - /* our current locking system requires that we lock the - entire password database. This avoids both livelock - and deadlock. */ - /* These values for the number of attempts and the sleep time - are, of course, completely arbitrary. - My reading of the PAM docs is that, once pam_chauthtok() has been - called with PAM_UPDATE_AUTHTOK, we are obliged to take any - reasonable steps to make sure the token is updated; so retrying - for 1/10 sec. isn't overdoing it. - The other possibility is to call lckpwdf() on the first - pam_chauthtok() pass, and hold the lock until released in the - second pass--but is this guaranteed to work? -SRL */ - i=0; - while((retval = lckpwdf()) != 0 && i < 100) { - usleep(1000); - } - if(retval != 0) { - return PAM_AUTHTOK_LOCK_BUSY; - } -#endif ctrl = _set_ctrl(pamh, flags, &remember, argc, argv); /* * First get the name of a user */ - retval = pam_get_user(pamh, &user, "Username: "); + retval = pam_get_user(pamh, &user, NULL); if (retval == PAM_SUCCESS) { /* * Various libraries at various times have had bugs related to @@ -725,9 +784,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, */ if (user == NULL || !isalnum(*user)) { _log_err(LOG_ERR, pamh, "bad username [%s]", user); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return PAM_USER_UNKNOWN; } if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl)) @@ -737,15 +793,42 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (on(UNIX_DEBUG, ctrl)) _log_err(LOG_DEBUG, pamh, "password - could not identify user"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } D(("Got username of %s", user)); /* + * Before we do anything else, check to make sure that the user's + * info is in one of the databases we can modify from this module, + * which currently is 'files' and 'nis'. We have to do this because + * getpwnam() doesn't tell you *where* the information it gives you + * came from, nor should it. That's our job. + */ + if (_unix_comesfromsource(pamh, user, 1, 1) == 0) { + _log_err(LOG_DEBUG, pamh, + "user \"%s\" does not exist in /etc/passwd or NIS", + user); + return PAM_USER_UNKNOWN; + } else { + struct passwd *pwd; + _unix_getpwnam(pamh, user, 1, 1, &pwd); + if (pwd == NULL) { + _log_err(LOG_DEBUG, pamh, + "user \"%s\" has corrupted passwd entry", + user); + return PAM_USER_UNKNOWN; + } + if (!_unix_shadowed(pwd) && + (strchr(pwd->pw_passwd, '*') != NULL)) { + _log_err(LOG_DEBUG, pamh, + "user \"%s\" does not have modifiable password", + user); + return PAM_USER_UNKNOWN; + } + } + + /* * This is not an AUTH module! */ if (on(UNIX__NONULL, ctrl)) @@ -760,10 +843,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, D(("prelim check")); - if (_unix_blankpasswd(ctrl, user)) { -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif + if (_unix_blankpasswd(pamh, ctrl, user)) { return PAM_SUCCESS; } else if (off(UNIX__IAMROOT, ctrl)) { @@ -773,9 +853,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (Announce == NULL) { _log_err(LOG_CRIT, pamh, "password - out of memory"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return PAM_BUF_ERR; } (void) strcpy(Announce, greeting); @@ -795,9 +872,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, pamh ,"password - (old) token not obtained"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } /* verify that this is the password for this user */ @@ -812,9 +886,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (retval != PAM_SUCCESS) { D(("Authentication failed")); pass_old = NULL; -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old); @@ -867,19 +938,9 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, pamh, "user not authenticated"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - return retval; - } - retval = _unix_verify_shadow(user, ctrl); - if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, pamh, "user not authenticated 2"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } + D(("get new password now")); lctrl = ctrl; @@ -908,9 +969,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, ,"password - new password not obtained"); } pass_old = NULL; /* tidy up */ -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } D(("returned to _unix_chauthtok")); @@ -931,11 +989,56 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, _log_err(LOG_NOTICE, pamh, "new password not acceptable"); pass_new = pass_old = NULL; /* tidy up */ + return retval; + } +#ifdef USE_LCKPWDF + /* These values for the number of attempts and the sleep time + are, of course, completely arbitrary. + My reading of the PAM docs is that, once pam_chauthtok() has been + called with PAM_UPDATE_AUTHTOK, we are obliged to take any + reasonable steps to make sure the token is updated; so retrying + for 1/10 sec. isn't overdoing it. */ + i=0; + while((retval = lckpwdf()) != 0 && i < 100) { + usleep(1000); + i++; + } + if(retval != 0) { + return PAM_AUTHTOK_LOCK_BUSY; + } +#endif + + if (pass_old) { + retval = _unix_verify_password(pamh, user, pass_old, ctrl); + if (retval != PAM_SUCCESS) { + _log_err(LOG_NOTICE, pamh, "user password changed by another process"); +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return retval; + } + } + + retval = _unix_verify_shadow(user, ctrl); + if (retval != PAM_SUCCESS) { + _log_err(LOG_NOTICE, pamh, "user not authenticated 2"); #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } + + retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new); + if (retval != PAM_SUCCESS) { + _log_err(LOG_NOTICE, pamh, + "new password not acceptable 2"); + pass_new = pass_old = NULL; /* tidy up */ +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return retval; + } + /* * By reaching here we have approved the passwords and must now * rebuild the password database file. @@ -962,7 +1065,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, salt[2] = '\0'; if (off(UNIX_BIGCRYPT, ctrl) && strlen(pass_new) > 8) { - /* + /* * to avoid using the _extensions_ of the bigcrypt() * function we truncate the newly entered password * [Problems that followed from this are fixed as per @@ -998,6 +1101,8 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, retval = _do_setpass(pamh, user, pass_old, tpass, ctrl, remember); + /* _do_setpass has called ulckpwdf for us */ + _pam_delete(tpass); pass_old = pass_new = NULL; } else { /* something has broken with the module */ @@ -1008,9 +1113,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, D(("retval was %d", retval)); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } @@ -1027,4 +1129,3 @@ struct pam_module _pam_unix_passwd_modstruct = { pam_sm_chauthtok, }; #endif - diff --git a/Linux-PAM/modules/pam_unix/pam_unix_sess.c b/Linux-PAM/modules/pam_unix/pam_unix_sess.c index 0784bff8..a29a7085 100644 --- a/Linux-PAM/modules/pam_unix/pam_unix_sess.c +++ b/Linux-PAM/modules/pam_unix/pam_unix_sess.c @@ -1,5 +1,5 @@ /* - * $Id: pam_unix_sess.c,v 1.1.1.1 2001/04/29 04:17:39 hartmans Exp $ + * $Id: pam_unix_sess.c,v 1.5 2005/03/23 14:35:21 t8m Exp $ * * Copyright Alexander O. Yuriev, 1996. All rights reserved. * Copyright Jan Rêkorajski, 1999. All rights reserved. @@ -53,6 +53,7 @@ #include <security/_pam_macros.h> #include <security/pam_modules.h> +#include <security/_pam_modutil.h> #ifndef LINUX_PAM #include <security/pam_appl.h> @@ -71,27 +72,31 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t * pamh, int flags, char *user_name, *service; unsigned int ctrl; int retval; + const char *login_name; D(("called.")); ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); retval = pam_get_item(pamh, PAM_USER, (void *) &user_name); - if (user_name == NULL || retval != PAM_SUCCESS) { + if (user_name == NULL || *user_name == '\0' || retval != PAM_SUCCESS) { _log_err(LOG_CRIT, pamh, "open_session - error recovering username"); return PAM_SESSION_ERR; /* How did we get authenticated with no username?! */ } retval = pam_get_item(pamh, PAM_SERVICE, (void *) &service); - if (service == NULL || retval != PAM_SUCCESS) { + if (service == NULL || *service == '\0' || retval != PAM_SUCCESS) { _log_err(LOG_CRIT, pamh, "open_session - error recovering service"); return PAM_SESSION_ERR; } - _log_err(LOG_INFO, pamh, "session opened for user %s by %s(uid=%d)" - ,user_name - ,PAM_getlogin() == NULL ? "" : PAM_getlogin(), getuid()); + login_name = _pammodutil_getlogin(pamh); + if (login_name == NULL) { + login_name = ""; + } + _log_err(LOG_INFO, pamh, "session opened for user %s by %s(uid=%d)", + user_name, login_name, getuid()); return PAM_SUCCESS; } @@ -108,14 +113,14 @@ PAM_EXTERN int pam_sm_close_session(pam_handle_t * pamh, int flags, ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); retval = pam_get_item(pamh, PAM_USER, (void *) &user_name); - if (user_name == NULL || retval != PAM_SUCCESS) { + if (user_name == NULL || *user_name == '\0' || retval != PAM_SUCCESS) { _log_err(LOG_CRIT, pamh, "close_session - error recovering username"); return PAM_SESSION_ERR; /* How did we get authenticated with no username?! */ } retval = pam_get_item(pamh, PAM_SERVICE, (void *) &service); - if (service == NULL || retval != PAM_SUCCESS) { + if (service == NULL || *service == '\0' || retval != PAM_SUCCESS) { _log_err(LOG_CRIT, pamh, "close_session - error recovering service"); return PAM_SESSION_ERR; diff --git a/Linux-PAM/modules/pam_unix/support.c b/Linux-PAM/modules/pam_unix/support.c index 15861af6..1584f2f1 100644 --- a/Linux-PAM/modules/pam_unix/support.c +++ b/Linux-PAM/modules/pam_unix/support.c @@ -1,5 +1,5 @@ /* - * $Id: support.c,v 1.1.1.2 2002/09/15 20:09:02 hartmans Exp $ + * $Id: support.c,v 1.25 2005/01/10 09:45:37 kukuk Exp $ * * Copyright information at end of file. */ @@ -9,6 +9,7 @@ #include <stdlib.h> #include <unistd.h> #include <stdarg.h> +#include <stdio.h> #include <string.h> #include <malloc.h> #include <pwd.h> @@ -16,9 +17,13 @@ #include <limits.h> #include <utmp.h> #include <errno.h> +#include <signal.h> +#include <ctype.h> +#include <rpcsvc/ypclnt.h> #include <security/_pam_macros.h> #include <security/pam_modules.h> +#include <security/_pam_modutil.h> #include "md5.h" #include "support.h" @@ -106,36 +111,6 @@ int _make_remark(pam_handle_t * pamh, unsigned int ctrl return retval; } - /* - * Beacause getlogin() is braindead and sometimes it just - * doesn't work, we reimplement it here. - */ -char *PAM_getlogin(void) -{ - struct utmp *ut, line; - char *curr_tty, *retval; - static char curr_user[sizeof(ut->ut_user) + 4]; - - retval = NULL; - - curr_tty = ttyname(0); - if (curr_tty != NULL) { - D(("PAM_getlogin ttyname: %s", curr_tty)); - curr_tty += 5; - setutent(); - strncpy(line.ut_line, curr_tty, sizeof(line.ut_line)); - if ((ut = getutline(&line)) != NULL) { - strncpy(curr_user, ut->ut_user, sizeof(ut->ut_user)); - curr_user[sizeof(curr_user) - 1] = '\0'; - retval = curr_user; - } - endutent(); - } - D(("PAM_getlogin retval: %s", retval)); - - return retval; -} - /* * set the control flags for the UNIX module. */ @@ -163,10 +138,6 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int argc, D(("PRELIM_CHECK")); set(UNIX__PRELIM, ctrl); } - if (flags & PAM_DISALLOW_NULL_AUTHTOK) { - D(("DISALLOW_NULL_AUTHTOK")); - set(UNIX__NONULL, ctrl); - } if (flags & PAM_SILENT) { D(("SILENT")); set(UNIX__QUIET, ctrl); @@ -195,7 +166,7 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int argc, if (remember != NULL) { if (j == UNIX_REMEMBER_PASSWD) { *remember = strtol(*argv + 9, NULL, 10); - if ((*remember == LONG_MIN) || (*remember == LONG_MAX)) + if ((*remember == INT_MIN) || (*remember == INT_MAX)) *remember = -1; if (*remember > 400) *remember = 400; @@ -206,6 +177,11 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int argc, ++argv; /* step to next argument */ } + if (flags & PAM_DISALLOW_NULL_AUTHTOK) { + D(("DISALLOW_NULL_AUTHTOK")); + set(UNIX__NONULL, ctrl); + } + /* auditing is a more sensitive version of debug */ if (on(UNIX_AUDIT, ctrl)) { @@ -304,25 +280,178 @@ static void _cleanup_failures(pam_handle_t * pamh, void *fl, int err) } /* + * _unix_getpwnam() searches only /etc/passwd and NIS to find user information + */ +static void _unix_cleanup(pam_handle_t *pamh, void *data, int error_status) +{ + free(data); +} + +int _unix_getpwnam(pam_handle_t *pamh, const char *name, + int files, int nis, struct passwd **ret) +{ + FILE *passwd; + char buf[16384]; + int matched = 0, buflen; + char *slogin, *spasswd, *suid, *sgid, *sgecos, *shome, *sshell, *p; + + memset(buf, 0, sizeof(buf)); + + if (!matched && files) { + int userlen = strlen(name); + passwd = fopen("/etc/passwd", "r"); + if (passwd != NULL) { + while (fgets(buf, sizeof(buf), passwd) != NULL) { + if ((buf[userlen] == ':') && + (strncmp(name, buf, userlen) == 0)) { + p = buf + strlen(buf) - 1; + while (isspace(*p) && (p >= buf)) { + *p-- = '\0'; + } + matched = 1; + break; + } + } + fclose(passwd); + } + } + + if (!matched && nis) { + char *userinfo = NULL, *domain = NULL; + int len = 0, i; + len = yp_get_default_domain(&domain); + if (len == YPERR_SUCCESS) { + len = yp_bind(domain); + } + if (len == YPERR_SUCCESS) { + i = yp_match(domain, "passwd.byname", name, + strlen(name), &userinfo, &len); + yp_unbind(domain); + if ((i == YPERR_SUCCESS) && (len < sizeof(buf))) { + strncpy(buf, userinfo, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + matched = 1; + } + } + } + + if (matched && (ret != NULL)) { + *ret = NULL; + + slogin = buf; + + spasswd = strchr(slogin, ':'); + if (spasswd == NULL) { + return matched; + } + *spasswd++ = '\0'; + + suid = strchr(spasswd, ':'); + if (suid == NULL) { + return matched; + } + *suid++ = '\0'; + + sgid = strchr(suid, ':'); + if (sgid == NULL) { + return matched; + } + *sgid++ = '\0'; + + sgecos = strchr(sgid, ':'); + if (sgecos == NULL) { + return matched; + } + *sgecos++ = '\0'; + + shome = strchr(sgecos, ':'); + if (shome == NULL) { + return matched; + } + *shome++ = '\0'; + + sshell = strchr(shome, ':'); + if (sshell == NULL) { + return matched; + } + *sshell++ = '\0'; + + buflen = sizeof(struct passwd) + + strlen(slogin) + 1 + + strlen(spasswd) + 1 + + strlen(suid) + 1 + + strlen(sgid) + 1 + + strlen(sgecos) + 1 + + strlen(shome) + 1 + + strlen(sshell) + 1; + *ret = malloc(buflen); + if (*ret == NULL) { + return matched; + } + memset(*ret, '\0', buflen); + + (*ret)->pw_uid = strtol(suid, &p, 10); + if ((strlen(sgid) == 0) || (*p != '\0')) { + free(*ret); + *ret = NULL; + return matched; + } + + (*ret)->pw_gid = strtol(sgid, &p, 10); + if ((strlen(sgid) == 0) || (*p != '\0')) { + free(*ret); + *ret = NULL; + return matched; + } + + p = ((char*)(*ret)) + sizeof(struct passwd); + (*ret)->pw_name = strcpy(p, slogin); + p += strlen(p) + 1; + (*ret)->pw_passwd = strcpy(p, spasswd); + p += strlen(p) + 1; + (*ret)->pw_gecos = strcpy(p, sgecos); + p += strlen(p) + 1; + (*ret)->pw_dir = strcpy(p, shome); + p += strlen(p) + 1; + (*ret)->pw_shell = strcpy(p, sshell); + + snprintf(buf, sizeof(buf), "_pam_unix_getpwnam_%s", name); + + if (pam_set_data(pamh, buf, + *ret, _unix_cleanup) != PAM_SUCCESS) { + free(*ret); + *ret = NULL; + } + } + + return matched; +} + +/* + * _unix_comsefromsource() is a quick check to see if information about a given + * user comes from a particular source (just files and nis for now) + * + */ +int _unix_comesfromsource(pam_handle_t *pamh, + const char *name, int files, int nis) +{ + return _unix_getpwnam(pamh, name, files, nis, NULL); +} + +/* * _unix_blankpasswd() is a quick check for a blank password * * returns TRUE if user does not have a password * - to avoid prompting for one in such cases (CG) */ -int _unix_blankpasswd(unsigned int ctrl, const char *name) +int +_unix_blankpasswd (pam_handle_t *pamh, unsigned int ctrl, const char *name) { struct passwd *pwd = NULL; struct spwd *spwdent = NULL; char *salt = NULL; int retval; -#if HAVE_GETPWNAM_R - char *buf = NULL; - int bufsize = 0; - struct passwd pwd_buf; - - pwd = &pwd_buf; -#endif D(("called")); @@ -338,23 +467,7 @@ int _unix_blankpasswd(unsigned int ctrl, const char *name) /* UNIX passwords area */ /* Get password file entry... */ -#if HAVE_GETPWNAM_R - bufsize = 1024; - buf = malloc(bufsize); - - if ((retval = getpwnam_r(name, pwd, buf, bufsize, &pwd))) { - pwd = NULL; - } - while (retval == ERANGE) { - bufsize += 1024; - buf = realloc(buf, bufsize); - if ((retval = getpwnam_r(name, pwd, buf, bufsize, &pwd))) { - pwd = NULL; - } - } -#else - pwd = getpwnam(name); -#endif + pwd = _pammodutil_getpwnam (pamh, name); if (pwd != NULL) { if (strcmp( pwd->pw_passwd, "*NP*" ) == 0) @@ -372,28 +485,24 @@ int _unix_blankpasswd(unsigned int ctrl, const char *name) setreuid( 0, -1 ); if(setreuid( -1, pwd->pw_uid ) == -1) /* Will fail elsewhere. */ -#if HAVE_GETPWNAM_R - if (buf) - free(buf); -#endif return 0; } } - spwdent = getspnam( name ); + spwdent = _pammodutil_getspnam (pamh, name); if (save_uid == pwd->pw_uid) setreuid( save_uid, save_euid ); else { if (setreuid( -1, 0 ) == -1) - setreuid( save_uid, -1 ); + setreuid( save_uid, -1 ); setreuid( -1, save_euid ); } - } else if (strcmp(pwd->pw_passwd, "x") == 0) { + } else if (_unix_shadowed(pwd)) { /* * ...and shadow password file entry for this user, * if shadowing is enabled */ - spwdent = getspnam(name); + spwdent = _pammodutil_getspnam(pamh, name); } if (spwdent) salt = x_strdup(spwdent->sp_pwdp); @@ -415,11 +524,6 @@ int _unix_blankpasswd(unsigned int ctrl, const char *name) if (salt) _pam_delete(salt); -#if HAVE_GETPWNAM_R - if (buf) - free(buf); -#endif - return retval; } @@ -434,6 +538,7 @@ static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd, unsigned int ctrl, const char *user) { int retval, child, fds[2]; + void (*sighandler)(int) = NULL; D(("called.")); /* create a pipe for the password */ @@ -442,6 +547,18 @@ static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd, return PAM_AUTH_ERR; } + if (off(UNIX_NOREAP, ctrl)) { + /* + * This code arranges that the demise of the child does not cause + * the application to receive a signal it is not expecting - which + * may kill the application or worse. + * + * The "noreap" module argument is provided so that the admin can + * override this behavior. + */ + sighandler = signal(SIGCHLD, SIG_DFL); + } + /* fork */ child = fork(); if (child == 0) { @@ -486,6 +603,10 @@ static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd, retval = PAM_AUTH_ERR; } + if (sighandler != NULL) { + (void) signal(SIGCHLD, sighandler); /* restore old signal handler */ + } + D(("returning %d", retval)); return retval; } @@ -514,7 +635,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name D(("locating user's record")); /* UNIX passwords area */ - pwd = getpwnam(name); /* Get password file entry... */ + pwd = _pammodutil_getpwnam (pamh, name); /* Get password file entry... */ if (pwd != NULL) { if (strcmp( pwd->pw_passwd, "*NP*" ) == 0) @@ -535,7 +656,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name } } - spwdent = getspnam( name ); + spwdent = _pammodutil_getspnam (pamh, name); if (save_uid == pwd->pw_uid) setreuid( save_uid, save_euid ); else { @@ -543,12 +664,12 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name setreuid( save_uid, -1 ); setreuid( -1, save_euid ); } - } else if (strcmp(pwd->pw_passwd, "x") == 0) { + } else if (_unix_shadowed(pwd)) { /* * ...and shadow password file entry for this user, * if shadowing is enabled */ - spwdent = getspnam(name); + spwdent = _pammodutil_getspnam (pamh, name); } if (spwdent) salt = x_strdup(spwdent->sp_pwdp); @@ -565,7 +686,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name } retval = PAM_SUCCESS; - if (pwd == NULL || salt == NULL || !strcmp(salt, "x")) { + if (pwd == NULL || salt == NULL || !strcmp(salt, "x") || ((salt[0] == '#') && (salt[1] == '#') && !strcmp(salt + 2, name))) { if (geteuid()) { /* we are not root perhaps this is the reason? Run helper */ D(("running helper binary")); @@ -577,6 +698,11 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name } } else { D(("user's record unavailable")); + p = NULL; + if (pwd == NULL) + retval = PAM_USER_UNKNOWN; + else + retval = PAM_AUTHINFO_UNAVAIL; if (on(UNIX_AUDIT, ctrl)) { /* this might be a typo and the user has given a password instead of a username. Careful with this. */ @@ -584,54 +710,58 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name "check pass; user (%s) unknown", name); } else { name = NULL; - _log_err(LOG_ALERT, pamh, - "check pass; user unknown"); + if (on(UNIX_DEBUG, ctrl) || pwd == NULL) { + _log_err(LOG_ALERT, pamh, + "check pass; user unknown"); + } else { + /* don't log failure as another pam module can succeed */ + goto cleanup; + } } - p = NULL; - retval = PAM_AUTHINFO_UNAVAIL; } } else { - if (!strlen(salt)) { - /* the stored password is NULL */ - if (off(UNIX__NONULL, ctrl)) { /* this means we've succeeded */ - D(("user has empty password - access granted")); - retval = PAM_SUCCESS; - } else { - D(("user has empty password - access denied")); - retval = PAM_AUTH_ERR; - } - } else if (!p) { - retval = PAM_AUTH_ERR; + int salt_len = strlen(salt); + if (!salt_len) { + /* the stored password is NULL */ + if (off(UNIX__NONULL, ctrl)) {/* this means we've succeeded */ + D(("user has empty password - access granted")); + retval = PAM_SUCCESS; } else { - if (!strncmp(salt, "$1$", 3)) { - pp = Goodcrypt_md5(p, salt); - if (strcmp(pp, salt) != 0) { - _pam_delete(pp); - pp = Brokencrypt_md5(p, salt); - } - } else { - pp = bigcrypt(p, salt); - } - p = NULL; /* no longer needed here */ + D(("user has empty password - access denied")); + retval = PAM_AUTH_ERR; + } + } else if (!p || (*salt == '*') || (salt_len < 13)) { + retval = PAM_AUTH_ERR; + } else { + if (!strncmp(salt, "$1$", 3)) { + pp = Goodcrypt_md5(p, salt); + if (strcmp(pp, salt) != 0) { + _pam_delete(pp); + pp = Brokencrypt_md5(p, salt); + } + } else { + pp = bigcrypt(p, salt); + } + p = NULL; /* no longer needed here */ - /* the moment of truth -- do we agree with the password? */ - D(("comparing state of pp[%s] and salt[%s]", pp, salt)); + /* the moment of truth -- do we agree with the password? */ + D(("comparing state of pp[%s] and salt[%s]", pp, salt)); - /* - * Note, we are comparing the bigcrypt of the password with - * the contents of the password field. If the latter was - * encrypted with regular crypt (and not bigcrypt) it will - * have been truncated for storage relative to the output - * of bigcrypt here. As such we need to compare only the - * stored string with the subset of bigcrypt's result. - * Bug 521314: The strncmp comparison is for legacy support. - */ - if (strncmp(pp, salt, strlen(salt)) == 0) { - retval = PAM_SUCCESS; - } else { - retval = PAM_AUTH_ERR; - } + /* + * Note, we are comparing the bigcrypt of the password with + * the contents of the password field. If the latter was + * encrypted with regular crypt (and not bigcrypt) it will + * have been truncated for storage relative to the output + * of bigcrypt here. As such we need to compare only the + * stored string with the subset of bigcrypt's result. + * Bug 521314: The strncmp comparison is for legacy support. + */ + if (strncmp(pp, salt, salt_len) == 0) { + retval = PAM_SUCCESS; + } else { + retval = PAM_AUTH_ERR; } + } } if (retval == PAM_SUCCESS) { @@ -649,10 +779,17 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name if (new != NULL) { - new->user = x_strdup(name ? name : ""); + const char *login_name; + + login_name = _pammodutil_getlogin(pamh); + if (login_name == NULL) { + login_name = ""; + } + + new->user = x_strdup(name ? name : ""); new->uid = getuid(); new->euid = geteuid(); - new->name = x_strdup(PAM_getlogin()? PAM_getlogin() : ""); + new->name = x_strdup(login_name); /* any previous failures for this user ? */ pam_get_data(pamh, data_name, (const void **) &old); @@ -702,6 +839,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name } } +cleanup: if (data_name) _pam_delete(data_name); if (salt) @@ -762,7 +900,7 @@ int _unix_read_password(pam_handle_t * pamh return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */ } else if (on(UNIX_USE_AUTHTOK, ctrl) && off(UNIX__OLD_PASSWD, ctrl)) { - return PAM_AUTHTOK_RECOVER_ERR; + return PAM_AUTHTOK_ERR; } } /* @@ -884,6 +1022,21 @@ int _unix_read_password(pam_handle_t * pamh return PAM_SUCCESS; } +int _unix_shadowed(const struct passwd *pwd) +{ + if (pwd != NULL) { + if (strcmp(pwd->pw_passwd, "x") == 0) { + return 1; + } + if ((pwd->pw_passwd[0] == '#') && + (pwd->pw_passwd[1] == '#') && + (strcmp(pwd->pw_name, pwd->pw_passwd + 2) == 0)) { + return 1; + } + } + return 0; +} + /* ****************************************************************** * * Copyright (c) Jan Rêkorajski 1999. * Copyright (c) Andrew G. Morgan 1996-8. diff --git a/Linux-PAM/modules/pam_unix/support.h b/Linux-PAM/modules/pam_unix/support.h index 368a4e8f..39abadd5 100644 --- a/Linux-PAM/modules/pam_unix/support.h +++ b/Linux-PAM/modules/pam_unix/support.h @@ -1,10 +1,11 @@ /* - * $Id: support.h,v 1.1.1.1 2001/04/29 04:17:41 hartmans Exp $ + * $Id: support.h,v 1.8 2004/10/06 13:42:36 kukuk Exp $ */ #ifndef _PAM_UNIX_SUPPORT_H #define _PAM_UNIX_SUPPORT_H +#include <pwd.h> /* * here is the string to inform the user that the new passwords they @@ -80,8 +81,11 @@ typedef struct { #define UNIX_BIGCRYPT 18 /* use DEC-C2 crypt()^x function */ #define UNIX_LIKE_AUTH 19 /* need to auth for setcred to work */ #define UNIX_REMEMBER_PASSWD 20 /* Remember N previous passwords */ +#define UNIX_NOREAP 21 /* don't reap child process */ +#define UNIX_BROKEN_SHADOW 22 /* ignore errors reading password aging + * information during acct management */ /* -------------- */ -#define UNIX_CTRLS_ 21 /* number of ctrl arguments defined */ +#define UNIX_CTRLS_ 23 /* number of ctrl arguments defined */ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = @@ -110,6 +114,8 @@ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = /* UNIX_BIGCRYPT */ {"bigcrypt", _ALL_ON_^(020000), 0400000}, /* UNIX_LIKE_AUTH */ {"likeauth", _ALL_ON_, 01000000}, /* UNIX_REMEMBER_PASSWD */ {"remember=", _ALL_ON_, 02000000}, +/* UNIX_NOREAP */ {"noreap", _ALL_ON_, 04000000}, +/* UNIX_BROKEN_SHADOW */ {"broken_shadow", _ALL_ON_, 010000000}, }; #define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag) @@ -123,13 +129,18 @@ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = _pam_drop(xx); \ } -extern char *PAM_getlogin(void); extern void _log_err(int err, pam_handle_t *pamh, const char *format,...); extern int _make_remark(pam_handle_t * pamh, unsigned int ctrl ,int type, const char *text); extern int _set_ctrl(pam_handle_t * pamh, int flags, int *remember, int argc, const char **argv); -extern int _unix_blankpasswd(unsigned int ctrl, const char *name); +extern int _unix_getpwnam (pam_handle_t *pamh, + const char *name, int files, int nis, + struct passwd **ret); +extern int _unix_comesfromsource (pam_handle_t *pamh, + const char *name, int files, int nis); +extern int _unix_blankpasswd(pam_handle_t *pamh,unsigned int ctrl, + const char *name); extern int _unix_verify_password(pam_handle_t * pamh, const char *name ,const char *p, unsigned int ctrl); extern int _unix_read_password(pam_handle_t * pamh @@ -139,6 +150,6 @@ extern int _unix_read_password(pam_handle_t * pamh ,const char *prompt2 ,const char *data_name ,const char **pass); +extern int _unix_shadowed(const struct passwd *pwd); #endif /* _PAM_UNIX_SUPPORT_H */ - diff --git a/Linux-PAM/modules/pam_unix/unix_chkpwd.c b/Linux-PAM/modules/pam_unix/unix_chkpwd.c index 6188435f..be32348f 100644 --- a/Linux-PAM/modules/pam_unix/unix_chkpwd.c +++ b/Linux-PAM/modules/pam_unix/unix_chkpwd.c @@ -1,5 +1,5 @@ /* - * $Id: unix_chkpwd.c,v 1.1.1.2 2002/09/15 20:09:02 hartmans Exp $ + * $Id: unix_chkpwd.c,v 1.11 2004/11/16 14:27:42 toady Exp $ * * This program is designed to run setuid(root) or with sufficient * privilege to read all of the unix password databases. It is designed @@ -57,8 +57,31 @@ static void _log_err(int err, const char *format,...) closelog(); } +static int _unix_shadowed(const struct passwd *pwd) +{ + char hashpass[1024]; + if (pwd != NULL) { + if (strcmp(pwd->pw_passwd, "x") == 0) { + return 1; + } + if (strlen(pwd->pw_name) < sizeof(hashpass) - 2) { + strcpy(hashpass, "##"); + strcpy(hashpass + 2, pwd->pw_name); + if (strcmp(pwd->pw_passwd, hashpass) == 0) { + return 1; + } + } + } + return 0; +} + static void su_sighandler(int sig) { +#ifndef SA_RESETHAND + /* emulate the behaviour of the SA_RESETHAND flag */ + if ( sig == SIGILL || sig == SIGTRAP || sig == SIGBUS || sig = SIGSERV ) + signal(sig, SIG_DFL); +#endif if (sig > 0) { _log_err(LOG_NOTICE, "caught signal %d.", sig); exit(sig); @@ -74,7 +97,9 @@ static void setup_signals(void) */ (void) memset((void *) &action, 0, sizeof(action)); action.sa_handler = su_sighandler; +#ifdef SA_RESETHAND action.sa_flags = SA_RESETHAND; +#endif (void) sigaction(SIGILL, &action, NULL); (void) sigaction(SIGTRAP, &action, NULL); (void) sigaction(SIGBUS, &action, NULL); @@ -87,20 +112,21 @@ static void setup_signals(void) (void) sigaction(SIGQUIT, &action, NULL); } -static int _unix_verify_password(const char *name, const char *p, int opt) +static int _unix_verify_password(const char *name, const char *p, int nullok) { struct passwd *pwd = NULL; struct spwd *spwdent = NULL; char *salt = NULL; char *pp = NULL; int retval = UNIX_FAILED; + int salt_len; /* UNIX passwords area */ setpwent(); pwd = getpwnam(name); /* Get password file entry... */ endpwent(); if (pwd != NULL) { - if (strcmp(pwd->pw_passwd, "x") == 0) { + if (_unix_shadowed(pwd)) { /* * ...and shadow password file entry for this user, * if shadowing is enabled @@ -133,8 +159,11 @@ static int _unix_verify_password(const char *name, const char *p, int opt) return retval; } - if (strlen(salt) == 0) - return (opt == 0) ? UNIX_FAILED : UNIX_PASSED; + salt_len = strlen(salt); + if (salt_len == 0) + return (nullok == 0) ? UNIX_FAILED : UNIX_PASSED; + else if (p == NULL || strlen(p) == 0) + return UNIX_FAILED; /* the moment of truth -- do we agree with the password? */ retval = UNIX_FAILED; @@ -147,6 +176,8 @@ static int _unix_verify_password(const char *name, const char *p, int opt) if (strcmp(pp, salt) == 0) retval = UNIX_PASSED; } + } else if ((*salt == '*') || (salt_len < 13)) { + retval = UNIX_FAILED; } else { pp = bigcrypt(p, salt); /* @@ -158,7 +189,7 @@ static int _unix_verify_password(const char *name, const char *p, int opt) * stored string with the subset of bigcrypt's result. * Bug 521314: the strncmp comparison is for legacy support. */ - if (strncmp(pp, salt, strlen(salt)) == 0) { + if (strncmp(pp, salt, salt_len) == 0) { retval = UNIX_PASSED; } } @@ -197,7 +228,7 @@ int main(int argc, char *argv[]) { char pass[MAXPASS + 1]; char option[8]; - int npass, opt; + int npass, nullok; int force_failure = 0; int retval = UNIX_FAILED; char *user; @@ -250,9 +281,9 @@ int main(int argc, char *argv[]) } else { option[7] = '\0'; if (strncmp(option, "nullok", 8) == 0) - opt = 1; + nullok = 1; else - opt = 0; + nullok = 0; } /* read the password from stdin (a pipe from the pam_unix module) */ @@ -271,13 +302,13 @@ int main(int argc, char *argv[]) if (npass == 0) { /* the password is NULL */ - retval = _unix_verify_password(user, NULL, opt); + retval = _unix_verify_password(user, NULL, nullok); } else { /* does pass agree with the official one? */ pass[npass] = '\0'; /* NUL terminate */ - retval = _unix_verify_password(user, pass, opt); + retval = _unix_verify_password(user, pass, nullok); } } diff --git a/Linux-PAM/modules/pam_userdb/Makefile b/Linux-PAM/modules/pam_userdb/Makefile index bb774ddb..4da7310d 100644 --- a/Linux-PAM/modules/pam_userdb/Makefile +++ b/Linux-PAM/modules/pam_userdb/Makefile @@ -3,7 +3,7 @@ # Linux-PAM. You should not modify this Makefile (unless you know # what you are doing!). -# $Id: Makefile,v 1.1.1.2 2002/09/15 20:09:02 hartmans Exp $ +# $Id: Makefile,v 1.6 2004/09/14 14:22:40 kukuk Exp $ # Created by Cristian Gafton <gafton@redhat.com> include ../../Make.Rules @@ -24,6 +24,10 @@ else endif endif +ifeq ($(HAVE_LIBCRYPT),yes) + MODULE_SIMPLE_EXTRALIBS += -lcrypt +endif + ifeq ($(WHICH_DB),none) include ../dont_makefile diff --git a/Linux-PAM/modules/pam_userdb/README b/Linux-PAM/modules/pam_userdb/README index f4423781..1cab7b74 100644 --- a/Linux-PAM/modules/pam_userdb/README +++ b/Linux-PAM/modules/pam_userdb/README @@ -1,6 +1,7 @@ pam_userdb: Look up users in a .db database and verify their password against - what is contained in that database. + what is contained in that database. The database will have been + created using db_load. RECOGNIZED ARGUMENTS: debug write a message to syslog indicating success or @@ -8,16 +9,46 @@ RECOGNIZED ARGUMENTS: db=[path] use the [path] database for performing lookup. There is no default; the module will return PAM_IGNORE if - no database is provided. + no database is provided. Some versions of DB will + automatically append ".db" to whatever pathname you + supply here. + crypt=[mode] indicates whether encrypted or plaintext passwords + are stored in the database. If [mode] is "crypt", + passwords should be stored in the database in + crypt(3) form. If [mode] is "none" or any other + value, passwords should be stored in the database in + plaintext. + icase make the password verification to be case insensitive (ie when working with registration numbers and such) + only works with plaintext password storage. dump dump all the entries in the database to the log (eek, don't do this by default!) + use_authtok use the authentication token previously obtained by + another module that did the conversation with the + application. If this token can not be obtained then + the module will try to converse again. This option can + be used for stacking different modules that need to + deal with the authentication tokens. + + unknown_ok do not return error when checking for a user that is + not in the database. This can be used to stack more + than one pam_userdb module that will check a + username/password pair in more than a database. + + key_only the username and password are concatenated together + in the database hash as 'username-password' with a + random value. if the concatenation of the username and + password with a dash in the middle returns any result, + the user is valid. this is useful in cases where + the username may not be unique but the username and + password pair are. + MODULE SERVICES PROVIDED: - auth _authetication and _setcred (blank) + auth _authentication and _setcred (blank) EXAMPLE USE: auth sufficient pam_userdb.so icase db=/tmp/dbtest.db @@ -27,4 +58,4 @@ AUTHOR: -$Id: README,v 1.1.1.1 2001/04/29 04:17:42 hartmans Exp $ +$Id: README,v 1.3 2004/09/28 13:48:47 kukuk Exp $ diff --git a/Linux-PAM/modules/pam_userdb/conv.c b/Linux-PAM/modules/pam_userdb/conv.c index 0f13d03a..de5d12f2 100644 --- a/Linux-PAM/modules/pam_userdb/conv.c +++ b/Linux-PAM/modules/pam_userdb/conv.c @@ -5,8 +5,6 @@ /* $Id */ /* Copyright at the end of the file */ -#define _BSD_SOURCE - #include <stdlib.h> #include <string.h> diff --git a/Linux-PAM/modules/pam_userdb/create.pl b/Linux-PAM/modules/pam_userdb/create.pl index 2668ef4a..28088102 100644 --- a/Linux-PAM/modules/pam_userdb/create.pl +++ b/Linux-PAM/modules/pam_userdb/create.pl @@ -2,12 +2,12 @@ # this program creates a database in ARGV[1] from pairs given on # stdandard input # -# $Id: create.pl,v 1.1.1.1 2001/04/29 04:17:42 hartmans Exp $ +# $Id: create.pl,v 1.2 2004/09/28 13:48:47 kukuk Exp $ use DB_File; my $database = $ARGV[0]; -die "Use: check,pl <database>\n" unless ($database); +die "Use: create.pl <database>\n" unless ($database); print "Using database: $database\n"; my %lusers = (); diff --git a/Linux-PAM/modules/pam_userdb/pam_userdb.c b/Linux-PAM/modules/pam_userdb/pam_userdb.c index 337d217b..86c7238b 100644 --- a/Linux-PAM/modules/pam_userdb/pam_userdb.c +++ b/Linux-PAM/modules/pam_userdb/pam_userdb.c @@ -1,13 +1,14 @@ /* pam_userdb module */ - + /* - * $Id: pam_userdb.c,v 1.1.1.2 2002/09/15 20:09:03 hartmans Exp $ + * $Id: pam_userdb.c,v 1.7 2004/09/28 13:48:47 kukuk Exp $ * Written by Cristian Gafton <gafton@redhat.com> 1996/09/10 * See the end of the file for Copyright Information */ #include <security/_pam_aconf.h> +#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> @@ -56,33 +57,53 @@ static void _pam_log(int err, const char *format, ...) closelog(); } -char * database = NULL; -static int ctrl = 0; - -static int _pam_parse(int argc, const char **argv) +static int +_pam_parse (int argc, const char **argv, + char **database, char **cryptmode) { - /* step through arguments */ - for (ctrl = 0; argc-- > 0; ++argv) { - - /* generic options */ - - if (!strcmp(*argv,"debug")) - ctrl |= PAM_DEBUG_ARG; - else if (!strcasecmp(*argv, "icase")) - ctrl |= PAM_ICASE_ARG; - else if (!strcasecmp(*argv, "dump")) - ctrl |= PAM_DUMP_ARG; - else if (!strncasecmp(*argv,"db=", 3)) { - database = strdup((*argv) + 3); - if (database == NULL) - _pam_log(LOG_ERR, "pam_parse: could not parse argument \"%s\"", - *argv); - } else { - _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv); - } - } + int ctrl; + + *database = NULL; + *cryptmode = NULL; + + /* step through arguments */ + for (ctrl = 0; argc-- > 0; ++argv) + { + /* generic options */ + + if (!strcmp(*argv,"debug")) + ctrl |= PAM_DEBUG_ARG; + else if (!strcasecmp(*argv, "icase")) + ctrl |= PAM_ICASE_ARG; + else if (!strcasecmp(*argv, "dump")) + ctrl |= PAM_DUMP_ARG; + else if (!strcasecmp(*argv, "unknown_ok")) + ctrl |= PAM_UNKNOWN_OK_ARG; + else if (!strcasecmp(*argv, "key_only")) + ctrl |= PAM_KEY_ONLY_ARG; + else if (!strncasecmp(*argv,"db=", 3)) + { + *database = strdup((*argv) + 3); + if ((*database == NULL) || (strlen (*database) == 0)) + _pam_log(LOG_ERR, + "pam_parse: could not parse argument \"%s\"", + *argv); + } + else if (!strncasecmp(*argv,"crypt=", 6)) + { + *cryptmode = strdup((*argv) + 6); + if ((*cryptmode == NULL) || (strlen (*cryptmode) == 0)) + _pam_log(LOG_ERR, + "pam_parse: could not parse argument \"%s\"", + *argv); + } + else + { + _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv); + } + } - return ctrl; + return ctrl; } @@ -95,7 +116,9 @@ static int _pam_parse(int argc, const char **argv) * -1 = Password incorrect * -2 = System error */ -static int user_lookup(const char *user, const char *pass) +static int +user_lookup (const char *database, const char *cryptmode, + const char *user, const char *pass, int ctrl) { DBM *dbm; datum key, data; @@ -108,7 +131,8 @@ static int user_lookup(const char *user, const char *pass) return -2; } - if (ctrl &PAM_DUMP_ARG) { + /* dump out the database contents for debugging */ + if (ctrl & PAM_DUMP_ARG) { _pam_log(LOG_INFO, "Database dump:"); for (key = dbm_firstkey(dbm); key.dptr != NULL; key = dbm_nextkey(dbm)) { @@ -116,14 +140,19 @@ static int user_lookup(const char *user, const char *pass) _pam_log(LOG_INFO, "key[len=%d] = `%s', data[len=%d] = `%s'", key.dsize, key.dptr, data.dsize, data.dptr); } - } - /* do some more init work */ + } + /* do some more init work */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); - key.dptr = x_strdup(user); - key.dsize = strlen(user); - user = NULL; + if (ctrl & PAM_KEY_ONLY_ARG) { + key.dptr = malloc(strlen(user) + 1 + strlen(pass) + 1); + sprintf(key.dptr, "%s-%s", user, pass); + key.dsize = strlen(key.dptr); + } else { + key.dptr = x_strdup(user); + key.dsize = strlen(user); + } if (key.dptr) { data = dbm_fetch(dbm, key); @@ -138,27 +167,121 @@ static int user_lookup(const char *user, const char *pass) if (data.dptr != NULL) { int compare = 0; - + + if (ctrl & PAM_KEY_ONLY_ARG) + { + dbm_close (dbm); + return 0; /* found it, data contents don't matter */ + } + + if (strncasecmp(cryptmode, "crypt", 5) == 0) { + + /* crypt(3) password storage */ + + char *cryptpw; + char salt[2]; + + if (data.dsize != 13) { + compare = -2; + } else if (ctrl & PAM_ICASE_ARG) { + compare = -2; + } else { + salt[0] = *data.dptr; + salt[1] = *(data.dptr + 1); + + cryptpw = crypt (pass, salt); + + if (cryptpw) { + compare = strncasecmp (data.dptr, cryptpw, data.dsize); + } else { + compare = -2; + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_INFO, "crypt() returned NULL"); + } + }; + + }; + + } else { + + /* Unknown password encryption method - + * default to plaintext password storage + */ + if (strlen(pass) != data.dsize) { - compare = 1; + compare = 1; /* wrong password len -> wrong password */ } else if (ctrl & PAM_ICASE_ARG) { compare = strncasecmp(data.dptr, pass, data.dsize); } else { compare = strncmp(data.dptr, pass, data.dsize); } + + if (strncasecmp(cryptmode, "none", 4) && ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_INFO, "invalid value for crypt parameter: %s", + cryptmode); + _pam_log(LOG_INFO, "defaulting to plaintext password mode"); + } + + } + dbm_close(dbm); if (compare == 0) return 0; /* match */ else return -1; /* wrong */ } else { - if (ctrl & PAM_DEBUG_ARG) { + int saw_user = 0; + + if (ctrl & PAM_DEBUG_ARG) { _pam_log(LOG_INFO, "error returned by dbm_fetch: %s", strerror(errno)); } - dbm_close(dbm); + /* probably we should check dbm_error() here */ - return 1; /* not found */ + + if ((ctrl & PAM_KEY_ONLY_ARG) == 0) { + dbm_close(dbm); + return 1; /* not key_only, so no entry => no entry for the user */ + } + + /* now handle the key_only case */ + for (key = dbm_firstkey(dbm); + key.dptr != NULL; + key = dbm_nextkey(dbm)) { + int compare; + /* first compare the user portion (case sensitive) */ + compare = strncmp(key.dptr, user, strlen(user)); + if (compare == 0) { + /* assume failure */ + compare = -1; + /* if we have the divider where we expect it to be... */ + if (key.dptr[strlen(user)] == '-') { + saw_user = 1; + if (key.dsize == strlen(user) + 1 + strlen(pass)) { + if (ctrl & PAM_ICASE_ARG) { + /* compare the password portion (case insensitive)*/ + compare = strncasecmp(key.dptr + strlen(user) + 1, + pass, + strlen(pass)); + } else { + /* compare the password portion (case sensitive) */ + compare = strncmp(key.dptr + strlen(user) + 1, + pass, + strlen(pass)); + } + } + } + if (compare == 0) { + dbm_close(dbm); + return 0; /* match */ + } + } + } + dbm_close(dbm); + if (saw_user) + return -1; /* saw the user, but password mismatch */ + else + return 1; /* not found */ } /* NOT REACHED */ @@ -173,10 +296,17 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, { const char *username; const char *password; - int retval = PAM_AUTH_ERR; - + char *database = NULL; + char *cryptmode = NULL; + int retval = PAM_AUTH_ERR, ctrl; + /* parse arguments */ - ctrl = _pam_parse(argc, argv); + ctrl = _pam_parse(argc, argv, &database, &cryptmode); + if ((database == NULL) || (strlen(database) == 0)) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG,"can not get the database name"); + return PAM_SERVICE_ERR; + } /* Get the username */ retval = pam_get_user(pamh, &username, NULL); @@ -185,32 +315,47 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, _pam_log(LOG_DEBUG,"can not get the username"); return PAM_SERVICE_ERR; } - - /* Converse just to be sure we have the password */ + + /* Converse just to be sure we have a password */ retval = conversation(pamh); if (retval != PAM_SUCCESS) { _pam_log(LOG_ERR, "could not obtain password for `%s'", username); - return -2; + return PAM_CONV_ERR; } - + + /* Check if we got a password. The docs say that if we didn't have one, + * and use_authtok was specified as an argument, that we converse with the + * user anyway, so check for one and handle a failure for that case. If + * use_authtok wasn't specified, then we've already asked once and needn't + * do so again. */ + retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &password); + if ((retval != PAM_SUCCESS) && ((ctrl & PAM_USE_AUTHTOK_ARG) != 0)) { + retval = conversation(pamh); + if (retval != PAM_SUCCESS) { + _pam_log(LOG_ERR, "could not obtain password for `%s'", + username); + return PAM_CONV_ERR; + } + } + /* Get the password */ retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&password); if (retval != PAM_SUCCESS) { - _pam_log(LOG_ERR, "Could not retrive user's password"); + _pam_log(LOG_ERR, "Could not retrieve user's password"); return -2; } - + if (ctrl & PAM_DEBUG_ARG) _pam_log(LOG_INFO, "Verify user `%s' with password `%s'", username, password); - + /* Now use the username to look up password in the database file */ - retval = user_lookup(username, password); + retval = user_lookup(database, cryptmode, username, password, ctrl); switch (retval) { case -2: /* some sort of system error. The log was already printed */ - return PAM_SERVICE_ERR; + return PAM_SERVICE_ERR; case -1: /* incorrect password */ _pam_log(LOG_WARNING, @@ -247,9 +392,47 @@ int pam_sm_setcred(pam_handle_t *pamh, int flags, } PAM_EXTERN -int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, - int argc, const char **argv) +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { + const char *username; + char *database = NULL; + char *cryptmode = NULL; + int retval = PAM_AUTH_ERR, ctrl; + + /* parse arguments */ + ctrl = _pam_parse(argc, argv, &database, &cryptmode); + + /* Get the username */ + retval = pam_get_user(pamh, &username, NULL); + if ((retval != PAM_SUCCESS) || (!username)) { + if (ctrl & PAM_DEBUG_ARG) + _pam_log(LOG_DEBUG,"can not get the username"); + return PAM_SERVICE_ERR; + } + + /* Now use the username to look up password in the database file */ + retval = user_lookup(database, cryptmode, username, "", ctrl); + switch (retval) { + case -2: + /* some sort of system error. The log was already printed */ + return PAM_SERVICE_ERR; + case -1: + /* incorrect password, but we don't care */ + /* FALL THROUGH */ + case 0: + /* authentication succeeded. dumbest password ever. */ + return PAM_SUCCESS; + case 1: + /* the user does not exist in the database */ + return PAM_USER_UNKNOWN; + default: + /* we don't know anything about this return value */ + _pam_log(LOG_ERR, + "internal module error (retval = %d, user = `%s'", + retval, username); + return PAM_SERVICE_ERR; + } + return PAM_SUCCESS; } @@ -262,7 +445,7 @@ struct pam_module _pam_userdb_modstruct = { "pam_userdb", pam_sm_authenticate, pam_sm_setcred, - NULL, + pam_sm_acct_mgmt, NULL, NULL, NULL, diff --git a/Linux-PAM/modules/pam_userdb/pam_userdb.h b/Linux-PAM/modules/pam_userdb/pam_userdb.h index 88a93f0d..af03676b 100644 --- a/Linux-PAM/modules/pam_userdb/pam_userdb.h +++ b/Linux-PAM/modules/pam_userdb/pam_userdb.h @@ -1,7 +1,7 @@ #ifndef _PAM_USERSDB_H #define _PAM_USERSDB_H -/* $Id: pam_userdb.h,v 1.1.1.1 2001/04/29 04:17:42 hartmans Exp $ */ +/* $Id: pam_userdb.h,v 1.2 2004/09/28 13:48:47 kukuk Exp $ */ /* Header files */ #include <security/pam_appl.h> @@ -10,6 +10,9 @@ #define PAM_DEBUG_ARG 0x0001 #define PAM_ICASE_ARG 0x0002 #define PAM_DUMP_ARG 0x0004 +#define PAM_USE_AUTHTOK_ARG 0x0008 +#define PAM_UNKNOWN_OK_ARG 0x0010 +#define PAM_KEY_ONLY_ARG 0x0020 /* Useful macros */ #define x_strdup(s) ( (s) ? strdup(s):NULL ) diff --git a/Linux-PAM/modules/pam_warn/Makefile b/Linux-PAM/modules/pam_warn/Makefile index 657570e6..b1420538 100644 --- a/Linux-PAM/modules/pam_warn/Makefile +++ b/Linux-PAM/modules/pam_warn/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:43 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:06 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_warn/README b/Linux-PAM/modules/pam_warn/README index ab128179..3c4bde8a 100644 --- a/Linux-PAM/modules/pam_warn/README +++ b/Linux-PAM/modules/pam_warn/README @@ -1,4 +1,4 @@ -# $Id: README,v 1.1.1.1 2001/04/29 04:17:43 hartmans Exp $ +# $Id: README,v 1.1.1.1 2000/06/20 22:12:10 agmorgan Exp $ # This module is an authentication module that does not authenticate. diff --git a/Linux-PAM/modules/pam_warn/pam_warn.c b/Linux-PAM/modules/pam_warn/pam_warn.c index f84490e8..90170c01 100644 --- a/Linux-PAM/modules/pam_warn/pam_warn.c +++ b/Linux-PAM/modules/pam_warn/pam_warn.c @@ -1,7 +1,7 @@ /* pam_warn module */ /* - * $Id: pam_warn.c,v 1.1.1.2 2002/09/15 20:09:04 hartmans Exp $ + * $Id: pam_warn.c,v 1.2 2002/05/29 04:44:43 agmorgan Exp $ * * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 */ diff --git a/Linux-PAM/modules/pam_wheel/Makefile b/Linux-PAM/modules/pam_wheel/Makefile index e4f8a450..67947f81 100644 --- a/Linux-PAM/modules/pam_wheel/Makefile +++ b/Linux-PAM/modules/pam_wheel/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:43 hartmans Exp $ +# $Id: Makefile,v 1.2 2000/11/19 23:54:06 agmorgan Exp $ # # This Makefile controls a build process of $(TITLE) module for # Linux-PAM. You should not modify this Makefile (unless you know diff --git a/Linux-PAM/modules/pam_wheel/README b/Linux-PAM/modules/pam_wheel/README index 336bb31e..2cd156c0 100644 --- a/Linux-PAM/modules/pam_wheel/README +++ b/Linux-PAM/modules/pam_wheel/README @@ -1,17 +1,17 @@ pam_wheel: - only permit root authentication too members of wheel group + only permit root authentication to members of wheel group RECOGNIZED ARGUMENTS: - debug write a message to syslog indicating success or + debug Write a message to syslog indicating success or failure. - use_uid the check for wheel membership will be done against + use_uid The check for wheel membership will be done against the current uid instead of the original one (useful when jumping with su from one account to - another for example) - - trust the pam_wheel module will return PAM_SUCCESS instead + another for example). + + trust The pam_wheel module will return PAM_SUCCESS instead of PAM_IGNORE if the user is a member of the wheel group (thus with a little play stacking the modules the wheel members may be able to su to root without @@ -21,13 +21,19 @@ RECOGNIZED ARGUMENTS: is trying to get UID 0 access and is a member of the wheel group, deny access (well, kind of nonsense, but for use in conjunction with 'group' argument... :-) + Conversely, if the user is not in the group, return + PAM_IGNORE (unless 'trust' was also specified, in + which case we return PAM_SUCCESS). + + group=xxxx Instead of checking the wheel or GID 0 groups, use + the xxxx group to perform the authentification. - group=xxxx Instead of checking the GID 0 group, use the xxxx - group to perform the authentification. + root_only The check for wheel membership is done only + if the uid of requested account is 0. MODULE SERVICES PROVIDED: - auth _authetication and _setcred (blank) + auth _authentication, _setcred (blank) and _acct_mgmt AUTHOR: - Cristian Gafton <gafton@sorosis.ro> + Cristian Gafton <gafton@redhat.com> diff --git a/Linux-PAM/modules/pam_wheel/pam_wheel.c b/Linux-PAM/modules/pam_wheel/pam_wheel.c index d629819f..92cd44b9 100644 --- a/Linux-PAM/modules/pam_wheel/pam_wheel.c +++ b/Linux-PAM/modules/pam_wheel/pam_wheel.c @@ -40,8 +40,10 @@ */ #define PAM_SM_AUTH +#define PAM_SM_ACCOUNT #include <security/pam_modules.h> +#include <security/_pam_modutil.h> /* some syslogging */ @@ -60,7 +62,7 @@ static void _pam_log(int err, const char *format, ...) static int is_on_list(char * const *list, const char *member) { - while (*list) { + while (list && *list) { if (strcmp(*list, member) == 0) return 1; list++; @@ -73,7 +75,8 @@ static int is_on_list(char * const *list, const char *member) #define PAM_DEBUG_ARG 0x0001 #define PAM_USE_UID_ARG 0x0002 #define PAM_TRUST_ARG 0x0004 -#define PAM_DENY_ARG 0x0010 +#define PAM_DENY_ARG 0x0010 +#define PAM_ROOT_ONLY_ARG 0x0020 static int _pam_parse(int argc, const char **argv, char *use_group, size_t group_length) @@ -95,6 +98,8 @@ static int _pam_parse(int argc, const char **argv, char *use_group, ctrl |= PAM_TRUST_ARG; else if (!strcmp(*argv,"deny")) ctrl |= PAM_DENY_ARG; + else if (!strcmp(*argv,"root_only")) + ctrl |= PAM_ROOT_ONLY_ARG; else if (!strncmp(*argv,"group=",6)) strncpy(use_group,*argv+6,group_length-1); else { @@ -105,139 +110,185 @@ static int _pam_parse(int argc, const char **argv, char *use_group, return ctrl; } - -/* --- authentication management functions (only) --- */ - -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc - ,const char **argv) +static int perform_check(pam_handle_t *pamh, int flags, int ctrl, + const char *use_group) { - int ctrl; - const char *username; - char *fromsu; - struct passwd *pwd, *tpwd; - struct group *grp; - int retval = PAM_AUTH_ERR; - char use_group[BUFSIZ]; - - /* Init the optional group */ - bzero(use_group,BUFSIZ); - - ctrl = _pam_parse(argc, argv, use_group, sizeof(use_group)); - retval = pam_get_user(pamh, &username, NULL); - if ((retval != PAM_SUCCESS) || (!username)) { - if (ctrl & PAM_DEBUG_ARG) + const char *username = NULL; + const char *fromsu; + struct passwd *pwd, *tpwd = NULL; + struct group *grp; + int retval = PAM_AUTH_ERR; + + retval = pam_get_user(pamh, &username, NULL); + if ((retval != PAM_SUCCESS) || (!username)) { + if (ctrl & PAM_DEBUG_ARG) { _pam_log(LOG_DEBUG,"can not get the username"); + } return PAM_SERVICE_ERR; - } + } - /* su to a uid 0 account ? */ - pwd = getpwnam(username); - if (!pwd) { - if (ctrl & PAM_DEBUG_ARG) + pwd = _pammodutil_getpwnam (pamh, username); + if (!pwd) { + if (ctrl & PAM_DEBUG_ARG) { _pam_log(LOG_NOTICE,"unknown user %s",username); + } return PAM_USER_UNKNOWN; - } + } + if (ctrl & PAM_ROOT_ONLY_ARG) { + /* su to a non uid 0 account ? */ + if (pwd->pw_uid != 0) { + return PAM_IGNORE; + } + } - /* Now we know that the username exists, pass on to other modules... - * the call to pam_get_user made this obsolete, so is commented out - * - * pam_set_item(pamh,PAM_USER,(const void *)username); - */ - - /* is this user an UID 0 account ? */ - if(pwd->pw_uid) { - /* no need to check for wheel */ - return PAM_IGNORE; - } + if (ctrl & PAM_USE_UID_ARG) { + tpwd = _pammodutil_getpwuid (pamh, getuid()); + if (!tpwd) { + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_NOTICE, "who is running me ?!"); + } + return PAM_SERVICE_ERR; + } + fromsu = tpwd->pw_name; + } else { + fromsu = _pammodutil_getlogin(pamh); + if (fromsu) { + tpwd = _pammodutil_getpwnam (pamh, fromsu); + } + if (!fromsu || !tpwd) { + if (ctrl & PAM_DEBUG_ARG) { + _pam_log(LOG_NOTICE, "who is running me ?!"); + } + return PAM_SERVICE_ERR; + } + } + + /* + * At this point fromsu = username-of-invoker; tpwd = pwd ptr for fromsu + */ - if (ctrl & PAM_USE_UID_ARG) { - tpwd = getpwuid(getuid()); - if (!tpwd) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_NOTICE,"who is running me ?!"); - return PAM_SERVICE_ERR; - } - fromsu = tpwd->pw_name; - } else { - fromsu = getlogin(); - if (!fromsu) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_NOTICE,"who is running me ?!"); - return PAM_SERVICE_ERR; - } - } + if (!use_group[0]) { + if ((grp = _pammodutil_getgrnam (pamh, "wheel")) == NULL) { + grp = _pammodutil_getgrgid (pamh, 0); + } + } else { + grp = _pammodutil_getgrnam (pamh, use_group); + } + + if (!grp || (!grp->gr_mem && (tpwd->pw_gid != grp->gr_gid))) { + if (ctrl & PAM_DEBUG_ARG) { + if (!use_group[0]) { + _pam_log(LOG_NOTICE,"no members in a GID 0 group"); + } else { + _pam_log(LOG_NOTICE,"no members in '%s' group", use_group); + } + } + if (ctrl & PAM_DENY_ARG) { + /* if this was meant to deny access to the members + * of this group and the group does not exist, allow + * access + */ + return PAM_IGNORE; + } else { + return PAM_AUTH_ERR; + } + } - if (!use_group[0]) { - if ((grp = getgrnam("wheel")) == NULL) { - grp = getgrgid(0); - } - } else - grp = getgrnam(use_group); - - if (!grp || !grp->gr_mem) { - if (ctrl & PAM_DEBUG_ARG) { - if (!use_group[0]) - _pam_log(LOG_NOTICE,"no members in a GID 0 group"); - else - _pam_log(LOG_NOTICE,"no members in '%s' group",use_group); - } - if (ctrl & PAM_DENY_ARG) - /* if this was meant to deny access to the members - * of this group and the group does not exist, allow - * access - */ - return PAM_IGNORE; - else - return PAM_AUTH_ERR; - } - - if (is_on_list(grp->gr_mem, fromsu)) { - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_NOTICE,"Access %s to '%s' for '%s'", - (ctrl & PAM_DENY_ARG)?"denied":"granted", - fromsu,username); - if (ctrl & PAM_DENY_ARG) - return PAM_PERM_DENIED; - else - if (ctrl & PAM_TRUST_ARG) - return PAM_SUCCESS; - else - return PAM_IGNORE; - } + /* + * test if the user is a member of the group, or if the + * user has the "wheel" (sic) group as its primary group. + */ + + if (is_on_list(grp->gr_mem, fromsu) || (tpwd->pw_gid == grp->gr_gid)) { + + if (ctrl & PAM_DENY_ARG) { + retval = PAM_PERM_DENIED; + + } else if (ctrl & PAM_TRUST_ARG) { + retval = PAM_SUCCESS; /* this can be a sufficient check */ + + } else { + retval = PAM_IGNORE; + } + + } else { + + if (ctrl & PAM_DENY_ARG) { + + if (ctrl & PAM_TRUST_ARG) { + retval = PAM_SUCCESS; /* this can be a sufficient check */ + } else { + retval = PAM_IGNORE; + } + + } else { + retval = PAM_PERM_DENIED; + } + } + + if (ctrl & PAM_DEBUG_ARG) { + if (retval == PAM_IGNORE) { + _pam_log(LOG_NOTICE, "Ignoring access request '%s' for '%s'", + fromsu, username); + } else { + _pam_log(LOG_NOTICE, "Access %s to '%s' for '%s'", + (retval != PAM_SUCCESS) ? "denied":"granted", + fromsu, username); + } + } - if (ctrl & PAM_DEBUG_ARG) - _pam_log(LOG_NOTICE,"Access %s for '%s' to '%s'", - (ctrl & PAM_DENY_ARG)?"granted":"denied",fromsu,username); - if (ctrl & PAM_DENY_ARG) - return PAM_SUCCESS; - else - return PAM_PERM_DENIED; + return retval; +} + +/* --- authentication management functions --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + char use_group[BUFSIZ]; + int ctrl; + + ctrl = _pam_parse(argc, argv, use_group, sizeof(use_group)); + + return perform_check(pamh, flags, ctrl, use_group); } PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc ,const char **argv) { - return PAM_SUCCESS; + return PAM_SUCCESS; } +PAM_EXTERN +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + char use_group[BUFSIZ]; + int ctrl; + + ctrl = _pam_parse(argc, argv, use_group, sizeof(use_group)); + + return perform_check(pamh, flags, ctrl, use_group); +} #ifdef PAM_STATIC /* static module data */ struct pam_module _pam_wheel_modstruct = { - "pam_wheel", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - NULL, - NULL, - NULL, + "pam_wheel", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + NULL, + NULL, + NULL, + NULL, }; -#endif +#endif /* PAM_STATIC */ /* * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1996, 1997 diff --git a/Linux-PAM/modules/pam_xauth/Makefile b/Linux-PAM/modules/pam_xauth/Makefile new file mode 100644 index 00000000..385466a2 --- /dev/null +++ b/Linux-PAM/modules/pam_xauth/Makefile @@ -0,0 +1,12 @@ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# + +include ../../Make.Rules + +TITLE=pam_xauth +MAN8=pam_xauth.8 + +include ../Simple.Rules diff --git a/Linux-PAM/modules/pam_xauth/README b/Linux-PAM/modules/pam_xauth/README new file mode 100644 index 00000000..dd65292f --- /dev/null +++ b/Linux-PAM/modules/pam_xauth/README @@ -0,0 +1,41 @@ +pam_xauth: + Forward xauth cookies from user to user, normally used by su, sudo, or + userhelper. + + Primitive access control is provided by ~/.xauth/export in the invoking + user's home directory and ~/.xauth/import in the target user's home + directory. + + If a user has a ~/.xauth/import file, the user will only receive cookies + from users listed in the file. If there is no ~/.xauth/import file, + the user will accept cookies from any other user. + + If a user has a .xauth/export file, the user will only forward cookies + to users listed in the file. If there is no ~/.xauth/export file, and + the invoking user is not "root", the user will forward cookies to + any other user. If there is no ~/.xauth/export file, and the invoking + user is "root", the user will NOT forward cookies to other users. + + Both the import and export files support wildcards (such as "*"). Both + the import and export files can be empty, signifying that no users are + allowed. + +RECOGNIZED ARGUMENTS: + debug write debugging messages to syslog + xauthpath= the path to the xauth program, by default + /usr/X11R6/bin/xauth + systemuser= highest user id assigned to system users, defaults + to 499 (pam_xauth will refuse to forward creds to + target users with id equal to or below this number, + except for root and possibly another specified user) + targetuser= a target user id which is excepted from the systemuser + checks + + +MODULE SERVICES PROVIDED: + session open session copies xauth cookie to new user + close session deletes copied xauth cookie + +AUTHOR: + Nalin Dahyabhai <nalin@redhat.com>, based on original version by + Michael K. Johnson <johnsonm@redhat.com> diff --git a/Linux-PAM/modules/pam_xauth/pam_xauth.8 b/Linux-PAM/modules/pam_xauth/pam_xauth.8 new file mode 100644 index 00000000..9acb7249 --- /dev/null +++ b/Linux-PAM/modules/pam_xauth/pam_xauth.8 @@ -0,0 +1,82 @@ +.\" Copyright 2001,2003 Red Hat, Inc. +.\" Written by Nalin Dahyabhai <nalin@redhat.com>, based on the original +.\" version by Michael K. Johnson +.TH pam_xauth 8 2003/7/24 "Red Hat Linux" "System Administrator's Manual" +.SH NAME +pam_xauth \- forward xauth keys between users +.SH SYNOPSIS +.B session optional /lib/security/pam_xauth.so \fIarguments\fP +.SH DESCRIPTION +pam_xauth.so is designed to forward xauth keys (sometimes referred +to as "cookies") between users. + +Without pam_xauth, when xauth is enabled and a user uses the \fBsu\fP command +to assume another user's priviledges, that user is no longer able to access +the original user's X display because the new user does not have the key +needed to access the display. pam_xauth solves the problem by forwarding the +key from the user running su (the source user) to the user whose +identity the source user is assuming (the target user) when the session +is created, and destroying the key when the session is torn down. + +This means, for example, that when you run \fBsu\fP from an xterm sesssion, +you will be able to run X programs without explicitly dealing with the +xauth command or ~/.Xauthority files. + +pam_xauth will only forward keys if xauth can list a key connected +to the $DISPLAY environment variable. + +Primitive access control is provided by \fB~/.xauth/export\fP in the invoking +user's home directory and \fB~/.xauth/import\fP in the target user's home +directory. + +If a user has a \fB~/.xauth/import\fP file, the user will only receive cookies +from users listed in the file. If there is no \fB~/.xauth/import\fP file, +the user will accept cookies from any other user. + +If a user has a \fB.xauth/export\fP file, the user will only forward cookies +to users listed in the file. If there is no \fB~/.xauth/export\fP file, and +the invoking user is not \fBroot\fP, the user will forward cookies to +any other user. If there is no \fB~/.xauth/export\fP file, and the invoking +user is \fBroot\fP, the user will \fInot\fP forward cookies to other users. + +Both the import and export files support wildcards (such as \fI*\fP). Both +the import and export files can be empty, signifying that no users are allowed. + +.SH ARGUMENTS +.IP debug +Turns on debugging messages sent to syslog. +.IP xauthpath=\fI/usr/X11R6/bin/xauth\fP +Specify the path the xauth program (the default is /usr/X11R6/bin/xauth). +.IP systemuser=\fInumber\fP +Specify the highest UID which will be assumed to belong to a "system" user. +pam_xauth will refuse to forward credentials to users with UID less than or +equal to this number, except for root and the "targetuser", if specified. +.IP targetuser=\fInumber\fP +Specify a single target UID which is exempt from the systemuser check. +.SH "IMPLEMENTATION DETAILS" +pam_xauth will work \fIonly\fP if it is used from a setuid application +in which the getuid() call returns the id of the user running the +application, and for which PAM can supply the name of the account that +the user is attempting to assume. The typical application of this +type is \fBsu\fP. The application must call both pam_open_session() and +pam_close_session() with the ruid set to the uid of the calling user +and the euid set to root, and must have provided as the PAM_USER item +the name of the target user. + +pam_xauth calls \fBxauth\fP as the source user to extract the key for +$DISPLAY, then calls xauth as the target user to merge the key +into the a temporary database and later remove the database. + +pam_xauth cannot be told not to remove the keys when the session +is closed. +.SH "SEE ALSO" +\fI/usr/share/doc/pam*/html/index.html\fP +.SH FILES +\fI~/.xauth/import\fP +\fI~/.xauth/export\fP +.SH BUGS +Let's hope not, but if you find any, please report them via the "Bug Track" +link at http://bugzilla.redhat.com/bugzilla/ +.SH AUTHOR +Nalin Dahyabhai <nalin@redhat.com>, based on original version by +Michael K. Johnson <johnsonm@redhat.com> diff --git a/Linux-PAM/modules/pam_xauth/pam_xauth.c b/Linux-PAM/modules/pam_xauth/pam_xauth.c new file mode 100644 index 00000000..2bf72eb6 --- /dev/null +++ b/Linux-PAM/modules/pam_xauth/pam_xauth.c @@ -0,0 +1,641 @@ +/* + * Copyright 2001-2003 Red Hat, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* "$Id: pam_xauth.c,v 1.4 2005/03/14 09:42:28 kukuk Exp $" */ + +#include "../../_pam_aconf.h" +#include <sys/types.h> +#include <sys/fsuid.h> +#include <sys/wait.h> +#include <errno.h> +#include <fnmatch.h> +#include <grp.h> +#include <limits.h> +#include <netdb.h> +#include <pwd.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> + +#include <security/pam_modules.h> +#include <security/_pam_macros.h> +#include <security/_pam_modutil.h> + +#define DATANAME "pam_xauth_cookie_file" +#define XAUTHBIN "/usr/X11R6/bin/xauth" +#define XAUTHENV "XAUTHORITY" +#define HOMEENV "HOME" +#define XAUTHDEF ".Xauthority" +#define XAUTHTMP ".xauthXXXXXX" + +/* Run a given command (with a NULL-terminated argument list), feeding it the + * given input on stdin, and storing any output it generates. */ +static int +run_coprocess(const char *input, char **output, + uid_t uid, gid_t gid, const char *command, ...) +{ + int ipipe[2], opipe[2], i; + char buf[LINE_MAX]; + pid_t child; + char *buffer = NULL; + size_t buffer_size = 0; + va_list ap; + + *output = NULL; + + /* Create stdio pipery. */ + if (pipe(ipipe) == -1) { + return -1; + } + if (pipe(opipe) == -1) { + close(ipipe[0]); + close(ipipe[1]); + return -1; + } + + /* Fork off a child. */ + child = fork(); + if (child == -1) { + close(ipipe[0]); + close(ipipe[1]); + close(opipe[0]); + close(opipe[1]); + return -1; + } + + if (child == 0) { + /* We're the child. */ + char *args[10]; + const char *tmp; + /* Drop privileges. */ + setgid(gid); + setgroups(0, NULL); + setuid(uid); + /* Initialize the argument list. */ + memset(args, 0, sizeof(args)); + /* Set the pipe descriptors up as stdin and stdout, and close + * everything else, including the original values for the + * descriptors. */ + dup2(ipipe[0], STDIN_FILENO); + dup2(opipe[1], STDOUT_FILENO); + for (i = 0; i < sysconf(_SC_OPEN_MAX); i++) { + if ((i != STDIN_FILENO) && (i != STDOUT_FILENO)) { + close(i); + } + } + /* Convert the varargs list into a regular array of strings. */ + va_start(ap, command); + args[0] = strdup(command); + for (i = 1; i < ((sizeof(args) / sizeof(args[0])) - 1); i++) { + tmp = va_arg(ap, const char*); + if (tmp == NULL) { + break; + } + args[i] = strdup(tmp); + } + /* Run the command. */ + execvp(command, args); + /* Never reached. */ + exit(1); + } + + /* We're the parent, so close the other ends of the pipes. */ + close(ipipe[0]); + close(opipe[1]); + /* Send input to the process (if we have any), then send an EOF. */ + if (input) { + (void)_pammodutil_write(ipipe[1], input, strlen(input)); + } + close(ipipe[1]); + + /* Read data output until we run out of stuff to read. */ + i = _pammodutil_read(opipe[0], buf, sizeof(buf)); + while ((i != 0) && (i != -1)) { + char *tmp; + /* Resize the buffer to hold the data. */ + tmp = realloc(buffer, buffer_size + i + 1); + if (tmp == NULL) { + /* Uh-oh, bail. */ + if (buffer != NULL) { + free(buffer); + } + close(opipe[0]); + waitpid(child, NULL, 0); + return -1; + } + /* Save the new buffer location, copy the newly-read data into + * the buffer, and make sure the result will be + * nul-terminated. */ + buffer = tmp; + memcpy(buffer + buffer_size, buf, i); + buffer[buffer_size + i] = '\0'; + buffer_size += i; + /* Try to read again. */ + i = _pammodutil_read(opipe[0], buf, sizeof(buf)); + } + /* No more data. Clean up and return data. */ + close(opipe[0]); + *output = buffer; + waitpid(child, NULL, 0); + return 0; +} + +/* Free a data item. */ +static void +cleanup(pam_handle_t *pamh, void *data, int err) +{ + free(data); +} + +/* Check if we want to allow export to the other user, or import from the + * other user. */ +static int +check_acl(pam_handle_t *pamh, + const char *sense, const char *this_user, const char *other_user, + int noent_code, int debug) +{ + char path[PATH_MAX]; + struct passwd *pwd; + FILE *fp; + int i; + uid_t euid; + /* Check this user's <sense> file. */ + pwd = _pammodutil_getpwnam(pamh, this_user); + if (pwd == NULL) { + syslog(LOG_ERR, "pam_xauth: error determining " + "home directory for '%s'", this_user); + return PAM_SESSION_ERR; + } + /* Figure out what that file is really named. */ + i = snprintf(path, sizeof(path), "%s/.xauth/%s", pwd->pw_dir, sense); + if ((i >= sizeof(path)) || (i < 0)) { + syslog(LOG_ERR, "pam_xauth: name of user's home directory " + "is too long"); + return PAM_SESSION_ERR; + } + euid = geteuid(); + setfsuid(pwd->pw_uid); + fp = fopen(path, "r"); + setfsuid(euid); + if (fp != NULL) { + char buf[LINE_MAX], *tmp; + /* Scan the file for a list of specs of users to "trust". */ + while (fgets(buf, sizeof(buf), fp) != NULL) { + tmp = memchr(buf, '\r', sizeof(buf)); + if (tmp != NULL) { + *tmp = '\0'; + } + tmp = memchr(buf, '\n', sizeof(buf)); + if (tmp != NULL) { + *tmp = '\0'; + } + if (fnmatch(buf, other_user, 0) == 0) { + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: %s %s " + "allowed by %s", + other_user, sense, path); + } + fclose(fp); + return PAM_SUCCESS; + } + } + /* If there's no match in the file, we fail. */ + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: %s not listed in %s", + other_user, path); + } + fclose(fp); + return PAM_PERM_DENIED; + } else { + /* Default to okay if the file doesn't exist. */ + switch (errno) { + case ENOENT: + if (noent_code == PAM_SUCCESS) { + if (debug) { + syslog(LOG_DEBUG, "%s does not exist, " + "ignoring", path); + } + } else { + if (debug) { + syslog(LOG_DEBUG, "%s does not exist, " + "failing", path); + } + } + return noent_code; + default: + if (debug) { + syslog(LOG_ERR, "%s opening %s", + strerror(errno), path); + } + return PAM_PERM_DENIED; + } + } +} + +int +pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + char xauthpath[] = XAUTHBIN; + char *cookiefile = NULL, *xauthority = NULL, + *cookie = NULL, *display = NULL, *tmp = NULL; + const char *user, *xauth = xauthpath; + struct passwd *tpwd, *rpwd; + int fd, i, debug = 0; + uid_t systemuser = 499, targetuser = 0, euid; + + /* Parse arguments. We don't understand many, so no sense in breaking + * this into a separate function. */ + for (i = 0; i < argc; i++) { + if (strcmp(argv[i], "debug") == 0) { + debug = 1; + continue; + } + if (strncmp(argv[i], "xauthpath=", 10) == 0) { + xauth = argv[i] + 10; + continue; + } + if (strncmp(argv[i], "targetuser=", 11) == 0) { + long l = strtol(argv[i] + 11, &tmp, 10); + if ((strlen(argv[i] + 11) > 0) && (*tmp == '\0')) { + targetuser = l; + } else { + syslog(LOG_WARNING, "pam_xauth: invalid value " + "for targetuser (`%s')", argv[i] + 11); + } + continue; + } + if (strncmp(argv[i], "systemuser=", 11) == 0) { + long l = strtol(argv[i] + 11, &tmp, 10); + if ((strlen(argv[i] + 11) > 0) && (*tmp == '\0')) { + systemuser = l; + } else { + syslog(LOG_WARNING, "pam_xauth: invalid value " + "for systemuser (`%s')", argv[i] + 11); + } + continue; + } + syslog(LOG_WARNING, "pam_xauth: unrecognized option `%s'", + argv[i]); + } + + /* If DISPLAY isn't set, we don't really care, now do we? */ + if ((display = getenv("DISPLAY")) == NULL) { + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: user has no DISPLAY," + " doing nothing"); + } + return PAM_SUCCESS; + } + + /* Read the target user's name. */ + if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_xauth: error determining target " + "user's name"); + return PAM_SESSION_ERR; + } + rpwd = _pammodutil_getpwuid(pamh, getuid()); + if (rpwd == NULL) { + syslog(LOG_ERR, "pam_xauth: error determining invoking " + "user's name"); + return PAM_SESSION_ERR; + } + + /* Get the target user's UID and primary GID, which we'll need to set + * on the xauthority file we create later on. */ + tpwd = _pammodutil_getpwnam(pamh, user); + if (tpwd == NULL) { + syslog(LOG_ERR, "pam_xauth: error determining target " + "user's UID"); + return PAM_SESSION_ERR; + } + + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: requesting user %lu/%lu, " + "target user %lu/%lu", + (unsigned long) rpwd->pw_uid, + (unsigned long) rpwd->pw_gid, + (unsigned long) tpwd->pw_uid, + (unsigned long) tpwd->pw_gid); + } + + /* If the UID is a system account (and not the superuser), forget + * about forwarding keys. */ + if ((tpwd->pw_uid != 0) && + (tpwd->pw_uid != targetuser) && + (tpwd->pw_uid <= systemuser)) { + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: not forwarding cookies " + "to user ID %ld", (long) tpwd->pw_uid); + } + return PAM_SESSION_ERR; + } + + /* Check that both users are amenable to this. By default, this + * boils down to this policy: + * export(ruser=root): only if <user> is listed in .xauth/export + * export(ruser=*) if <user> is listed in .xauth/export, or + * if .xauth/export does not exist + * import(user=*): if <ruser> is listed in .xauth/import, or + * if .xauth/import does not exist */ + i = (getuid() != 0) ? PAM_SUCCESS : PAM_PERM_DENIED; + i = check_acl(pamh, "export", rpwd->pw_name, user, i, debug); + if (i != PAM_SUCCESS) { + return PAM_SESSION_ERR; + } + i = PAM_SUCCESS; + i = check_acl(pamh, "import", user, rpwd->pw_name, i, debug); + if (i != PAM_SUCCESS) { + return PAM_SESSION_ERR; + } + + /* Figure out where the source user's .Xauthority file is. */ + if (getenv(XAUTHENV) != NULL) { + cookiefile = strdup(getenv(XAUTHENV)); + } else { + cookiefile = malloc(strlen(rpwd->pw_dir) + 1 + + strlen(XAUTHDEF) + 1); + if (cookiefile == NULL) { + return PAM_SESSION_ERR; + } + strcpy(cookiefile, rpwd->pw_dir); + strcat(cookiefile, "/"); + strcat(cookiefile, XAUTHDEF); + } + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: reading keys from `%s'", + cookiefile); + } + + /* Read the user's .Xauthority file. Because the current UID is + * the original user's UID, this will only fail if something has + * gone wrong, or we have no cookies. */ + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: running \"%s %s %s %s %s\" as " + "%lu/%lu", + xauth, + "-f", + cookiefile, + "nlist", + display, + (unsigned long) getuid(), + (unsigned long) getgid()); + } + if (run_coprocess(NULL, &cookie, + getuid(), getgid(), + xauth, "-f", cookiefile, "nlist", display, + NULL) == 0) { + /* Check that we got a cookie. If not, we get creative. */ + if (((cookie == NULL) || (strlen(cookie) == 0)) && + ((strncmp(display, "localhost:", 10) == 0) || + (strncmp(display, "localhost/unix:", 15) == 0))) { + char *t, *screen; + size_t tlen, slen; + /* Free the useless cookie string. */ + if (cookie != NULL) { + free(cookie); + cookie = NULL; + } + /* Allocate enough space to hold an adjusted name. */ + tlen = strlen(display) + LINE_MAX + 1; + t = malloc(tlen); + if (t != NULL) { + memset(t, 0, tlen); + if (gethostname(t, tlen - 1) != -1) { + /* Append the protocol and then the + * screen number. */ + if (strlen(t) < tlen - 6) { + strcat(t, "/unix:"); + } + screen = strchr(display, ':'); + if (screen != NULL) { + screen++; + slen = strlen(screen); + if (strlen(t) + slen < tlen) { + strcat(t, screen); + } + } + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: " + "no key for `%s', trying" + " `%s'", display, t); + } + /* Read the cookie for this display. */ + if (debug) { + syslog(LOG_DEBUG, + "pam_xauth: running " + "\"%s %s %s %s %s\" as " + "%lu/%lu", + xauth, + "-f", + cookiefile, + "nlist", + t, + (unsigned long) getuid(), + (unsigned long) getgid()); + } + run_coprocess(NULL, &cookie, + getuid(), getgid(), + xauth, "-f", cookiefile, + "nlist", t, NULL); + } + free(t); + t = NULL; + } + } + + /* Check that we got a cookie, this time for real. */ + if ((cookie == NULL) || (strlen(cookie) == 0)) { + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: no key"); + } + return PAM_SESSION_ERR; + } + + /* Generate the environment variable + * "XAUTHORITY=<homedir>/filename". */ + xauthority = malloc(strlen(XAUTHENV) + 1 + + strlen(tpwd->pw_dir) + 1 + + strlen(XAUTHTMP) + 1); + if (xauthority == NULL) { + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: no free memory"); + } + free(cookiefile); + free(cookie); + return PAM_SESSION_ERR; + } + strcpy(xauthority, XAUTHENV); + strcat(xauthority, "="); + strcat(xauthority, tpwd->pw_dir); + strcat(xauthority, "/"); + strcat(xauthority, XAUTHTMP); + + /* Generate a new file to hold the data. */ + euid = geteuid(); + setfsuid(tpwd->pw_uid); + fd = mkstemp(xauthority + strlen(XAUTHENV) + 1); + setfsuid(euid); + if (fd == -1) { + syslog(LOG_ERR, "pam_xauth: error creating " + "temporary file `%s': %s", + xauthority + strlen(XAUTHENV) + 1, + strerror(errno)); + free(cookiefile); + free(cookie); + free(xauthority); + return PAM_SESSION_ERR; + } + /* Set permissions on the new file and dispose of the + * descriptor. */ + fchown(fd, tpwd->pw_uid, tpwd->pw_gid); + close(fd); + + /* Get a copy of the filename to save as a data item for + * removal at session-close time. */ + free(cookiefile); + cookiefile = strdup(xauthority + strlen(XAUTHENV) + 1); + + /* Save the filename. */ + if (pam_set_data(pamh, DATANAME, cookiefile, cleanup) != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_xauth: error saving name of " + "temporary file `%s'", cookiefile); + unlink(cookiefile); + free(xauthority); + free(cookiefile); + free(cookie); + return PAM_SESSION_ERR; + } + + /* Unset any old XAUTHORITY variable in the environment. */ + if (getenv (XAUTHENV)) + unsetenv (XAUTHENV); + + /* Set the new variable in the environment. */ + if (pam_putenv (pamh, xauthority) != PAM_SUCCESS) + syslog (LOG_DEBUG, "pam_xauth: can't set environment variable '%s'", + xauthority); + putenv (xauthority); /* The environment owns this string now. */ + + /* set $DISPLAY in pam handle to make su - work */ + { + char *d = (char *) malloc (strlen ("DISPLAY=") + + strlen (display) + 1); + if (d == NULL) + { + syslog (LOG_DEBUG, "pam_xauth: memory exhausted\n"); + return PAM_SESSION_ERR; + } + strcpy (d, "DISPLAY="); + strcat (d, display); + + if (pam_putenv (pamh, d) != PAM_SUCCESS) + syslog (LOG_DEBUG, + "pam_xauth: can't set environment variable '%s'", + d); + free (d); + } + + /* Merge the cookie we read before into the new file. */ + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: writing key `%s' to " + "temporary file `%s'", cookie, cookiefile); + } + if (debug) { + syslog(LOG_DEBUG, + "pam_xauth: running \"%s %s %s %s %s\" as " + "%lu/%lu", + xauth, + "-f", + cookiefile, + "nmerge", + "-", + (unsigned long) tpwd->pw_uid, + (unsigned long) tpwd->pw_gid); + } + run_coprocess(cookie, &tmp, + tpwd->pw_uid, tpwd->pw_gid, + xauth, "-f", cookiefile, "nmerge", "-", NULL); + + /* We don't need to keep a copy of these around any more. */ + free(cookie); + cookie = NULL; + } + return PAM_SUCCESS; +} + +int +pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + void *cookiefile; + int i, debug = 0; + + /* Parse arguments. We don't understand many, so no sense in breaking + * this into a separate function. */ + for (i = 0; i < argc; i++) { + if (strcmp(argv[i], "debug") == 0) { + debug = 1; + continue; + } + if (strncmp(argv[i], "xauthpath=", 10) == 0) { + continue; + } + if (strncmp(argv[i], "systemuser=", 11) == 0) { + continue; + } + if (strncmp(argv[i], "targetuser=", 11) == 0) { + continue; + } + syslog(LOG_WARNING, "pam_xauth: unrecognized option `%s'", + argv[i]); + } + + /* Try to retrieve the name of a file we created when the session was + * opened. */ + if (pam_get_data(pamh, DATANAME, (const void**) &cookiefile) == PAM_SUCCESS) { + /* We'll only try to remove the file once. */ + if (strlen((char*)cookiefile) > 0) { + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: removing `%s'", + (char*)cookiefile); + } + unlink((char*)cookiefile); + *((char*)cookiefile) = '\0'; + } + } + return PAM_SUCCESS; +} diff --git a/Linux-PAM/modules/pammodutil/Makefile b/Linux-PAM/modules/pammodutil/Makefile index 03334326..bad1bf62 100644 --- a/Linux-PAM/modules/pammodutil/Makefile +++ b/Linux-PAM/modules/pammodutil/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $ +# $Id: Makefile,v 1.4 2004/09/24 13:13:22 kukuk Exp $ # # @@ -18,7 +18,9 @@ CFLAGS += $(PIC) $(STATIC) $(MOREFLAGS) \ -DLIBPAM_VERSION_MINOR=$(MINOR_REL) # all the object files we care about -LIBOBJECTS = modutil_cleanup.o modutil_getpwnam.o modutil_getpwuid.o +LIBOBJECTS = modutil_cleanup.o modutil_getpwnam.o modutil_getpwuid.o \ + modutil_getspnam.o modutil_getgrnam.o modutil_getgrgid.o \ + modutil_ingroup.o modutil_getlogin.o modutil_ioloop.o # static library name LIBSTATIC = $(LIBNAME).a diff --git a/Linux-PAM/modules/pammodutil/README b/Linux-PAM/modules/pammodutil/README index bd957247..ea44f310 100644 --- a/Linux-PAM/modules/pammodutil/README +++ b/Linux-PAM/modules/pammodutil/README @@ -1,4 +1,4 @@ -$Id: README,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $ +$Id: README,v 1.1 2001/12/09 22:15:12 agmorgan Exp $ This is a libarary of routines for use by modules. The routines seem to have a common use for modules, but are not part of libpam and never diff --git a/Linux-PAM/modules/pammodutil/include/security/_pam_modutil.h b/Linux-PAM/modules/pammodutil/include/security/_pam_modutil.h index d36fcfa0..ec0c8964 100644 --- a/Linux-PAM/modules/pammodutil/include/security/_pam_modutil.h +++ b/Linux-PAM/modules/pammodutil/include/security/_pam_modutil.h @@ -2,7 +2,7 @@ #define _PAM_MODUTIL_H /* - * $Id: _pam_modutil.h,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $ + * $Id: _pam_modutil.h,v 1.4 2004/09/24 13:13:22 kukuk Exp $ * * This file is a list of handy libc wrappers that attempt to provide some * thread-safe and other convenient functionality to modules in a form that @@ -15,10 +15,12 @@ * On systems that simply can't support thread safe programming, these * functions don't support it either - sorry. * - * Copyright (c) 2001 Andrew Morgan <morgan@kernel.org> + * Copyright (c) 2001-2002 Andrew Morgan <morgan@kernel.org> */ #include <pwd.h> +#include <grp.h> +#include <shadow.h> #include <sys/types.h> extern struct passwd *_pammodutil_getpwnam(pam_handle_t *pamh, @@ -27,7 +29,38 @@ extern struct passwd *_pammodutil_getpwnam(pam_handle_t *pamh, extern struct passwd *_pammodutil_getpwuid(pam_handle_t *pamh, uid_t uid); +extern struct group *_pammodutil_getgrnam(pam_handle_t *pamh, + const char *group); + +extern struct group *_pammodutil_getgrgid(pam_handle_t *pamh, + gid_t gid); + +extern struct spwd *_pammodutil_getspnam(pam_handle_t *pamh, + const char *user); + +extern int _pammodutil_user_in_group_nam_nam(pam_handle_t *pamh, + const char *user, + const char *group); + +extern int _pammodutil_user_in_group_nam_gid(pam_handle_t *pamh, + const char *user, + gid_t group); + +extern int _pammodutil_user_in_group_uid_nam(pam_handle_t *pamh, + uid_t user, + const char *group); + +extern int _pammodutil_user_in_group_uid_gid(pam_handle_t *pamh, + uid_t user, + gid_t group); + extern void _pammodutil_cleanup(pam_handle_t *pamh, void *data, int error_status); +extern const char *_pammodutil_getlogin(pam_handle_t *pamh); + +extern int _pammodutil_read(int fd, char *buffer, int count); + +extern int _pammodutil_write(int fd, const char *buffer, int count); + #endif /* _PAM_MODUTIL_H */ diff --git a/Linux-PAM/modules/pammodutil/modutil_cleanup.c b/Linux-PAM/modules/pammodutil/modutil_cleanup.c index 76662133..5477481f 100644 --- a/Linux-PAM/modules/pammodutil/modutil_cleanup.c +++ b/Linux-PAM/modules/pammodutil/modutil_cleanup.c @@ -1,5 +1,5 @@ /* - * $Id: modutil_cleanup.c,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $ + * $Id: modutil_cleanup.c,v 1.1 2001/12/09 22:15:12 agmorgan Exp $ * * This function provides a common pam_set_data() friendly version of free(). */ diff --git a/Linux-PAM/modules/pammodutil/modutil_getgrgid.c b/Linux-PAM/modules/pammodutil/modutil_getgrgid.c new file mode 100644 index 00000000..f97a9239 --- /dev/null +++ b/Linux-PAM/modules/pammodutil/modutil_getgrgid.c @@ -0,0 +1,150 @@ +/* + * $Id: modutil_getgrgid.c,v 1.3 2005/03/30 14:59:41 kukuk Exp $ + * + * This function provides a thread safer version of getgrgid() for use + * with PAM modules that care about this sort of thing. + * + * XXX - or at least it should provide a thread-safe alternative. + */ + +#include "pammodutil.h" + +#include <errno.h> +#include <limits.h> +#include <grp.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +static pthread_mutex_t _pammodutil_mutex = PTHREAD_MUTEX_INITIALIZER; +static void _pammodutil_lock(void) +{ + pthread_mutex_lock(&_pammodutil_mutex); +} +static void _pammodutil_unlock(void) +{ + pthread_mutex_unlock(&_pammodutil_mutex); +} + +static int intlen(int number) +{ + int len = 2; + while (number != 0) { + number /= 10; + len++; + } + return len; +} + +static int longlen(long number) +{ + int len = 2; + while (number != 0) { + number /= 10; + len++; + } + return len; +} + +struct group *_pammodutil_getgrgid(pam_handle_t *pamh, gid_t gid) +{ +#ifdef HAVE_GETGRGID_R + + void *buffer=NULL; + size_t length = PWD_INITIAL_LENGTH; + + do { + int status; + void *new_buffer; + struct group *result = NULL; + + new_buffer = realloc(buffer, sizeof(struct group) + length); + if (new_buffer == NULL) { + + D(("out of memory")); + + /* no memory for the user - so delete the memory */ + if (buffer) { + free(buffer); + } + return NULL; + } + buffer = new_buffer; + + /* make the re-entrant call to get the grp structure */ + errno = 0; + status = getgrgid_r(gid, buffer, + sizeof(struct group) + (char *) buffer, + length, &result); + if (!status && (result == buffer)) { + char *data_name; + const void *ignore; + int i; + + data_name = malloc(strlen("_pammodutil_getgrgid") + 1 + + longlen((long)gid) + 1 + intlen(INT_MAX) + 1); + if ((pamh != NULL) && (data_name == NULL)) { + D(("was unable to register the data item [%s]", + pam_strerror(pamh, status))); + free(buffer); + return NULL; + } + + if (pamh != NULL) { + for (i = 0; i < INT_MAX; i++) { + sprintf(data_name, "_pammodutil_getgrgid_%ld_%d", + (long) gid, i); + _pammodutil_lock(); + status = PAM_NO_MODULE_DATA; + if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) { + status = pam_set_data(pamh, data_name, + result, _pammodutil_cleanup); + } + _pammodutil_unlock(); + if (status == PAM_SUCCESS) { + break; + } + } + } else { + status = PAM_SUCCESS; + } + + free(data_name); + + if (status == PAM_SUCCESS) { + D(("success")); + return result; + } + + D(("was unable to register the data item [%s]", + pam_strerror(pamh, status))); + + free(buffer); + return NULL; + + } else if (errno != ERANGE && errno != EINTR) { + /* no sense in repeating the call */ + break; + } + + length <<= 2; + + } while (length < PWD_ABSURD_PWD_LENGTH); + + D(("grp structure took %u bytes or so of memory", + length+sizeof(struct group))); + + free(buffer); + return NULL; + +#else /* ie. ifndef HAVE_GETGRGID_R */ + + /* + * Sorry, there does not appear to be a reentrant version of + * getgrgid(). So, we use the standard libc function. + */ + + return getgrgid(gid); + +#endif /* def HAVE_GETGRGID_R */ +} diff --git a/Linux-PAM/modules/pammodutil/modutil_getgrnam.c b/Linux-PAM/modules/pammodutil/modutil_getgrnam.c new file mode 100644 index 00000000..0727618c --- /dev/null +++ b/Linux-PAM/modules/pammodutil/modutil_getgrnam.c @@ -0,0 +1,139 @@ +/* + * $Id: modutil_getgrnam.c,v 1.3 2005/03/30 14:59:41 kukuk Exp $ + * + * This function provides a thread safer version of getgrnam() for use + * with PAM modules that care about this sort of thing. + * + * XXX - or at least it should provide a thread-safe alternative. + */ + +#include "pammodutil.h" + +#include <errno.h> +#include <limits.h> +#include <grp.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +static pthread_mutex_t _pammodutil_mutex = PTHREAD_MUTEX_INITIALIZER; +static void _pammodutil_lock(void) +{ + pthread_mutex_lock(&_pammodutil_mutex); +} +static void _pammodutil_unlock(void) +{ + pthread_mutex_unlock(&_pammodutil_mutex); +} + +static int intlen(int number) +{ + int len = 2; + while (number != 0) { + number /= 10; + len++; + } + return len; +} + +struct group *_pammodutil_getgrnam(pam_handle_t *pamh, const char *group) +{ +#ifdef HAVE_GETGRNAM_R + + void *buffer=NULL; + size_t length = PWD_INITIAL_LENGTH; + + do { + int status; + void *new_buffer; + struct group *result = NULL; + + new_buffer = realloc(buffer, sizeof(struct group) + length); + if (new_buffer == NULL) { + + D(("out of memory")); + + /* no memory for the group - so delete the memory */ + if (buffer) { + free(buffer); + } + return NULL; + } + buffer = new_buffer; + + /* make the re-entrant call to get the grp structure */ + errno = 0; + status = getgrnam_r(group, buffer, + sizeof(struct group) + (char *) buffer, + length, &result); + if (!status && (result == buffer)) { + char *data_name; + const void *ignore; + int i; + + data_name = malloc(strlen("_pammodutil_getgrnam") + 1 + + strlen(group) + 1 + intlen(INT_MAX) + 1); + if ((pamh != NULL) && (data_name == NULL)) { + D(("was unable to register the data item [%s]", + pam_strerror(pamh, status))); + free(buffer); + return NULL; + } + + if (pamh != NULL) { + for (i = 0; i < INT_MAX; i++) { + sprintf(data_name, "_pammodutil_getgrnam_%s_%d", group, i); + _pammodutil_lock(); + status = PAM_NO_MODULE_DATA; + if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) { + status = pam_set_data(pamh, data_name, + result, _pammodutil_cleanup); + } + _pammodutil_unlock(); + if (status == PAM_SUCCESS) { + break; + } + } + } else { + status = PAM_SUCCESS; + } + + free(data_name); + + if (status == PAM_SUCCESS) { + D(("success")); + return result; + } + + D(("was unable to register the data item [%s]", + pam_strerror(pamh, status))); + + free(buffer); + return NULL; + + } else if (errno != ERANGE && errno != EINTR) { + /* no sense in repeating the call */ + break; + } + + length <<= 2; + + } while (length < PWD_ABSURD_PWD_LENGTH); + + D(("grp structure took %u bytes or so of memory", + length+sizeof(struct group))); + + free(buffer); + return NULL; + +#else /* ie. ifndef HAVE_GETGRNAM_R */ + + /* + * Sorry, there does not appear to be a reentrant version of + * getgrnam(). So, we use the standard libc function. + */ + + return getgrnam(group); + +#endif /* def HAVE_GETGRNAM_R */ +} diff --git a/Linux-PAM/modules/pammodutil/modutil_getlogin.c b/Linux-PAM/modules/pammodutil/modutil_getlogin.c new file mode 100644 index 00000000..0e4a48d8 --- /dev/null +++ b/Linux-PAM/modules/pammodutil/modutil_getlogin.c @@ -0,0 +1,72 @@ +/* + * $Id: modutil_getlogin.c,v 1.4 2004/11/08 10:57:15 t8m Exp $ + * + * A central point for invoking getlogin(). Hopefully, this is a + * little harder to spoof than all the other versions that are out + * there. + */ + +#include "pammodutil.h" + +#include <stdlib.h> +#include <unistd.h> +#include <utmp.h> + +#define _PAMMODUTIL_GETLOGIN "_pammodutil_getlogin" + +const char *_pammodutil_getlogin(pam_handle_t *pamh) +{ + int status; + char *logname; + const char *curr_tty; + char *curr_user; + struct utmp *ut, line; + + status = pam_get_data(pamh, _PAMMODUTIL_GETLOGIN, + (const void **) &logname); + if (status == PAM_SUCCESS) { + return logname; + } + + status = pam_get_item(pamh, PAM_TTY, (const void **) &curr_tty); + if ((status != PAM_SUCCESS) || (curr_tty == NULL)) { + curr_tty = ttyname(0); + } + + if ((curr_tty == NULL) || memcmp(curr_tty, "/dev/", 5)) { + return NULL; + } + + curr_tty += 5; /* strlen("/dev/") */ + logname = NULL; + + setutent(); + strncpy(line.ut_line, curr_tty, sizeof(line.ut_line)); + + if ((ut = getutline(&line)) == NULL) { + goto clean_up_and_go_home; + } + + curr_user = calloc(sizeof(line.ut_user)+1, 1); + if (curr_user == NULL) { + goto clean_up_and_go_home; + } + + strncpy(curr_user, ut->ut_user, sizeof(ut->ut_user)); + /* calloc already zeroed the memory */ + + status = pam_set_data(pamh, _PAMMODUTIL_GETLOGIN, curr_user, + _pammodutil_cleanup); + if (status != PAM_SUCCESS) { + free(curr_user); + goto clean_up_and_go_home; + } + + logname = curr_user; + +clean_up_and_go_home: + + endutent(); + + return logname; +} diff --git a/Linux-PAM/modules/pammodutil/modutil_getpwnam.c b/Linux-PAM/modules/pammodutil/modutil_getpwnam.c index e3a8f270..eb359544 100644 --- a/Linux-PAM/modules/pammodutil/modutil_getpwnam.c +++ b/Linux-PAM/modules/pammodutil/modutil_getpwnam.c @@ -1,5 +1,5 @@ /* - * $Id: modutil_getpwnam.c,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $ + * $Id: modutil_getpwnam.c,v 1.4 2005/03/30 14:59:41 kukuk Exp $ * * This function provides a thread safer version of getpwnam() for use * with PAM modules that care about this sort of thing. @@ -9,9 +9,33 @@ #include "pammodutil.h" +#include <errno.h> +#include <limits.h> +#include <pthread.h> #include <pwd.h> +#include <stdio.h> #include <stdlib.h> +static pthread_mutex_t _pammodutil_mutex = PTHREAD_MUTEX_INITIALIZER; +static void _pammodutil_lock(void) +{ + pthread_mutex_lock(&_pammodutil_mutex); +} +static void _pammodutil_unlock(void) +{ + pthread_mutex_unlock(&_pammodutil_mutex); +} + +static int intlen(int number) +{ + int len = 2; + while (number != 0) { + number /= 10; + len++; + } + return len; +} + struct passwd *_pammodutil_getpwnam(pam_handle_t *pamh, const char *user) { #ifdef HAVE_GETPWNAM_R @@ -38,12 +62,44 @@ struct passwd *_pammodutil_getpwnam(pam_handle_t *pamh, const char *user) buffer = new_buffer; /* make the re-entrant call to get the pwd structure */ + errno = 0; status = getpwnam_r(user, buffer, sizeof(struct passwd) + (char *) buffer, length, &result); - if (!status && result) { - status = pam_set_data(pamh, "_pammodutil_getpwnam", result, - _pammodutil_cleanup); + if (!status && (result == buffer)) { + char *data_name; + const void *ignore; + int i; + + data_name = malloc(strlen("_pammodutil_getpwnam") + 1 + + strlen(user) + 1 + intlen(INT_MAX) + 1); + if ((pamh != NULL) && (data_name == NULL)) { + D(("was unable to register the data item [%s]", + pam_strerror(pamh, status))); + free(buffer); + return NULL; + } + + if (pamh != NULL) { + for (i = 0; i < INT_MAX; i++) { + sprintf(data_name, "_pammodutil_getpwnam_%s_%d", user, i); + _pammodutil_lock(); + status = PAM_NO_MODULE_DATA; + if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) { + status = pam_set_data(pamh, data_name, + result, _pammodutil_cleanup); + } + _pammodutil_unlock(); + if (status == PAM_SUCCESS) { + break; + } + } + } else { + status = PAM_SUCCESS; + } + + free(data_name); + if (status == PAM_SUCCESS) { D(("success")); return result; @@ -55,9 +111,12 @@ struct passwd *_pammodutil_getpwnam(pam_handle_t *pamh, const char *user) free(buffer); return NULL; - } + } else if (errno != ERANGE && errno != EINTR) { + /* no sense in repeating the call */ + break; + } - length <<= 1; + length <<= 2; } while (length < PWD_ABSURD_PWD_LENGTH); diff --git a/Linux-PAM/modules/pammodutil/modutil_getpwuid.c b/Linux-PAM/modules/pammodutil/modutil_getpwuid.c index cd93ded4..8ba20d17 100644 --- a/Linux-PAM/modules/pammodutil/modutil_getpwuid.c +++ b/Linux-PAM/modules/pammodutil/modutil_getpwuid.c @@ -1,5 +1,5 @@ /* - * $Id: modutil_getpwuid.c,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $ + * $Id: modutil_getpwuid.c,v 1.4 2005/03/30 14:59:41 kukuk Exp $ * * This function provides a thread safer version of getpwuid() for use * with PAM modules that care about this sort of thing. @@ -9,12 +9,46 @@ #include "pammodutil.h" +#include <errno.h> +#include <limits.h> +#include <pthread.h> #include <pwd.h> +#include <stdio.h> #include <stdlib.h> +static pthread_mutex_t _pammodutil_mutex = PTHREAD_MUTEX_INITIALIZER; +static void _pammodutil_lock(void) +{ + pthread_mutex_lock(&_pammodutil_mutex); +} +static void _pammodutil_unlock(void) +{ + pthread_mutex_unlock(&_pammodutil_mutex); +} + +static int intlen(int number) +{ + int len = 2; + while (number != 0) { + number /= 10; + len++; + } + return len; +} + +static int longlen(long number) +{ + int len = 2; + while (number != 0) { + number /= 10; + len++; + } + return len; +} + struct passwd *_pammodutil_getpwuid(pam_handle_t *pamh, uid_t uid) { -#ifdef HAVE_GETPWNAM_R +#ifdef HAVE_GETPWUID_R void *buffer=NULL; size_t length = PWD_INITIAL_LENGTH; @@ -38,12 +72,45 @@ struct passwd *_pammodutil_getpwuid(pam_handle_t *pamh, uid_t uid) buffer = new_buffer; /* make the re-entrant call to get the pwd structure */ + errno = 0; status = getpwuid_r(uid, buffer, sizeof(struct passwd) + (char *) buffer, length, &result); - if (!status && result) { - status = pam_set_data(pamh, "_pammodutil_getpwuid", result, - _pammodutil_cleanup); + if (!status && (result == buffer)) { + char *data_name; + const void *ignore; + int i; + + data_name = malloc(strlen("_pammodutil_getpwuid") + 1 + + longlen((long) uid) + 1 + intlen(INT_MAX) + 1); + if ((pamh != NULL) && (data_name == NULL)) { + D(("was unable to register the data item [%s]", + pam_strerror(pamh, status))); + free(buffer); + return NULL; + } + + if (pamh != NULL) { + for (i = 0; i < INT_MAX; i++) { + sprintf(data_name, "_pammodutil_getpwuid_%ld_%d", + (long) uid, i); + _pammodutil_lock(); + status = PAM_NO_MODULE_DATA; + if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) { + status = pam_set_data(pamh, data_name, + result, _pammodutil_cleanup); + } + _pammodutil_unlock(); + if (status == PAM_SUCCESS) { + break; + } + } + } else { + status = PAM_SUCCESS; + } + + free(data_name); + if (status == PAM_SUCCESS) { D(("success")); return result; @@ -55,9 +122,12 @@ struct passwd *_pammodutil_getpwuid(pam_handle_t *pamh, uid_t uid) free(buffer); return NULL; - } + } else if (errno != ERANGE && errno != EINTR) { + /* no sense in repeating the call */ + break; + } - length <<= 1; + length <<= 2; } while (length < PWD_ABSURD_PWD_LENGTH); @@ -67,14 +137,14 @@ struct passwd *_pammodutil_getpwuid(pam_handle_t *pamh, uid_t uid) free(buffer); return NULL; -#else /* ie. ifndef HAVE_GETPWNAM_R */ +#else /* ie. ifndef HAVE_GETPWUID_R */ /* * Sorry, there does not appear to be a reentrant version of - * getpwnam(). So, we use the standard libc function. + * getpwuid(). So, we use the standard libc function. */ return getpwuid(uid); -#endif /* def HAVE_GETPWNAM_R */ +#endif /* def HAVE_GETPWUID_R */ } diff --git a/Linux-PAM/modules/pammodutil/modutil_getspnam.c b/Linux-PAM/modules/pammodutil/modutil_getspnam.c new file mode 100644 index 00000000..e966bb52 --- /dev/null +++ b/Linux-PAM/modules/pammodutil/modutil_getspnam.c @@ -0,0 +1,139 @@ +/* + * $Id: modutil_getspnam.c,v 1.3 2005/03/30 14:59:41 kukuk Exp $ + * + * This function provides a thread safer version of getspnam() for use + * with PAM modules that care about this sort of thing. + * + * XXX - or at least it should provide a thread-safe alternative. + */ + +#include "pammodutil.h" + +#include <errno.h> +#include <limits.h> +#include <pthread.h> +#include <shadow.h> +#include <stdio.h> +#include <stdlib.h> + +static pthread_mutex_t _pammodutil_mutex = PTHREAD_MUTEX_INITIALIZER; +static void _pammodutil_lock(void) +{ + pthread_mutex_lock(&_pammodutil_mutex); +} +static void _pammodutil_unlock(void) +{ + pthread_mutex_unlock(&_pammodutil_mutex); +} + +static int intlen(int number) +{ + int len = 2; + while (number != 0) { + number /= 10; + len++; + } + return len; +} + +struct spwd *_pammodutil_getspnam(pam_handle_t *pamh, const char *user) +{ +#ifdef HAVE_GETSPNAM_R + + void *buffer=NULL; + size_t length = PWD_INITIAL_LENGTH; + + do { + int status; + void *new_buffer; + struct spwd *result = NULL; + + new_buffer = realloc(buffer, sizeof(struct spwd) + length); + if (new_buffer == NULL) { + + D(("out of memory")); + + /* no memory for the user - so delete the memory */ + if (buffer) { + free(buffer); + } + return NULL; + } + buffer = new_buffer; + + /* make the re-entrant call to get the spwd structure */ + errno = 0; + status = getspnam_r(user, buffer, + sizeof(struct spwd) + (char *) buffer, + length, &result); + if (!status && (result == buffer)) { + char *data_name; + const void *ignore; + int i; + + data_name = malloc(strlen("_pammodutil_getspnam") + 1 + + strlen(user) + 1 + intlen(INT_MAX) + 1); + if ((pamh != NULL) && (data_name == NULL)) { + D(("was unable to register the data item [%s]", + pam_strerror(pamh, status))); + free(buffer); + return NULL; + } + + if (pamh != NULL) { + for (i = 0; i < INT_MAX; i++) { + sprintf(data_name, "_pammodutil_getspnam_%s_%d", user, i); + _pammodutil_lock(); + status = PAM_NO_MODULE_DATA; + if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) { + status = pam_set_data(pamh, data_name, + result, _pammodutil_cleanup); + } + _pammodutil_unlock(); + if (status == PAM_SUCCESS) { + break; + } + } + } else { + status = PAM_SUCCESS; + } + + free(data_name); + + if (status == PAM_SUCCESS) { + D(("success")); + return result; + } + + D(("was unable to register the data item [%s]", + pam_strerror(pamh, status))); + + free(buffer); + return NULL; + + } else if (errno != ERANGE && errno != EINTR) { + /* no sense in repeating the call */ + break; + } + + length <<= 2; + + } while (length < PWD_ABSURD_PWD_LENGTH); + + D(("spwd structure took %u bytes or so of memory", + length+sizeof(struct spwd))); + + free(buffer); + return NULL; + +#else /* ie. ifndef HAVE_GETSPNAM_R */ + + /* + * Sorry, there does not appear to be a reentrant version of + * getspnam(). So, we use the standard libc function. + */ + + return getspnam(user); + +#endif /* def HAVE_GETSPNAM_R */ +} diff --git a/Linux-PAM/modules/pammodutil/modutil_ingroup.c b/Linux-PAM/modules/pammodutil/modutil_ingroup.c new file mode 100644 index 00000000..e1f88b81 --- /dev/null +++ b/Linux-PAM/modules/pammodutil/modutil_ingroup.c @@ -0,0 +1,121 @@ +/* + * $Id: modutil_ingroup.c,v 1.1 2004/09/24 13:14:14 kukuk Exp $ + * + * This function provides common methods for checking if a user is in a + * specified group. + */ + +#include "pammodutil.h" +#include "include/security/_pam_modutil.h" +#include <pwd.h> +#include <grp.h> + +#ifdef HAVE_GETGROUPLIST +static int checkgrouplist(const char *user, gid_t primary, gid_t target) +{ + gid_t *grouplist = NULL; + int agroups, ngroups, i; + ngroups = agroups = 3; + do { + grouplist = malloc(sizeof(gid_t) * agroups); + if (grouplist == NULL) { + return 0; + } + ngroups = agroups; + i = getgrouplist(user, primary, grouplist, &ngroups); + if ((i < 0) || (ngroups < 1)) { + agroups *= 2; + free(grouplist); + } else { + for (i = 0; i < ngroups; i++) { + if (grouplist[i] == target) { + free(grouplist); + return 1; + } + } + free(grouplist); + } + } while (((i < 0) || (ngroups < 1)) && (agroups < 10000)); + return 0; +} +#endif + +static int _pammodutil_user_in_group_common(pam_handle_t *pamh, + struct passwd *pwd, + struct group *grp) +{ + int i; + + if (pwd == NULL) { + return 0; + } + if (grp == NULL) { + return 0; + } + + if (pwd->pw_gid == grp->gr_gid) { + return 1; + } + + for (i = 0; (grp->gr_mem != NULL) && (grp->gr_mem[i] != NULL); i++) { + if (strcmp(pwd->pw_name, grp->gr_mem[i]) == 0) { + return 1; + } + } + +#ifdef HAVE_GETGROUPLIST + if (checkgrouplist(pwd->pw_name, pwd->pw_gid, grp->gr_gid)) { + return 1; + } +#endif + + return 0; +} + +int _pammodutil_user_in_group_nam_nam(pam_handle_t *pamh, + const char *user, const char *group) +{ + struct passwd *pwd; + struct group *grp; + + pwd = _pammodutil_getpwnam(pamh, user); + grp = _pammodutil_getgrnam(pamh, group); + + return _pammodutil_user_in_group_common(pamh, pwd, grp); +} + +int _pammodutil_user_in_group_nam_gid(pam_handle_t *pamh, + const char *user, gid_t group) +{ + struct passwd *pwd; + struct group *grp; + + pwd = _pammodutil_getpwnam(pamh, user); + grp = _pammodutil_getgrgid(pamh, group); + + return _pammodutil_user_in_group_common(pamh, pwd, grp); +} + +int _pammodutil_user_in_group_uid_nam(pam_handle_t *pamh, + uid_t user, const char *group) +{ + struct passwd *pwd; + struct group *grp; + + pwd = _pammodutil_getpwuid(pamh, user); + grp = _pammodutil_getgrnam(pamh, group); + + return _pammodutil_user_in_group_common(pamh, pwd, grp); +} + +int _pammodutil_user_in_group_uid_gid(pam_handle_t *pamh, + uid_t user, gid_t group) +{ + struct passwd *pwd; + struct group *grp; + + pwd = _pammodutil_getpwuid(pamh, user); + grp = _pammodutil_getgrgid(pamh, group); + + return _pammodutil_user_in_group_common(pamh, pwd, grp); +} diff --git a/Linux-PAM/modules/pammodutil/modutil_ioloop.c b/Linux-PAM/modules/pammodutil/modutil_ioloop.c new file mode 100644 index 00000000..37ac76fc --- /dev/null +++ b/Linux-PAM/modules/pammodutil/modutil_ioloop.c @@ -0,0 +1,52 @@ +/* + * $Id: modutil_ioloop.c,v 1.2 2004/09/24 09:18:22 kukuk Exp $ + * + * These functions provides common methods for ensure a complete read or + * write occurs. It handles EINTR and partial read/write returns. + */ + +#include <unistd.h> +#include <errno.h> + +#include <security/pam_modules.h> +#include "include/security/_pam_modutil.h" + +int _pammodutil_read(int fd, char *buffer, int count) +{ + int block, offset = 0; + + while (count > 0) { + block = read(fd, &buffer[offset], count); + + if (block < 0) { + if (errno == EINTR) continue; + return block; + } + if (block == 0) return offset; + + offset += block; + count -= block; + } + + return offset; +} + +int _pammodutil_write(int fd, const char *buffer, int count) +{ + int block, offset = 0; + + while (count > 0) { + block = write(fd, &buffer[offset], count); + + if (block < 0) { + if (errno == EINTR) continue; + return block; + } + if (block == 0) return offset; + + offset += block; + count -= block; + } + + return offset; +} diff --git a/Linux-PAM/modules/pammodutil/pammodutil.h b/Linux-PAM/modules/pammodutil/pammodutil.h index 78d7e517..2b80c852 100644 --- a/Linux-PAM/modules/pammodutil/pammodutil.h +++ b/Linux-PAM/modules/pammodutil/pammodutil.h @@ -2,7 +2,7 @@ #define PAMMODUTIL_H /* - * $Id: pammodutil.h,v 1.1.1.1 2002/09/15 20:09:04 hartmans Exp $ + * $Id: pammodutil.h,v 1.2 2005/03/30 10:42:54 t8m Exp $ * * Copyright (c) 2001 Andrew Morgan <morgan@kernel.org> */ @@ -13,7 +13,7 @@ #include <security/_pam_modutil.h> #define PWD_INITIAL_LENGTH 0x100 -#define PWD_ABSURD_PWD_LENGTH 0x1000 +#define PWD_ABSURD_PWD_LENGTH 0x8000 /* This is a simple cleanup, it just free()s the 'data' memory */ extern void _pammodutil_cleanup(pam_handle_t *pamh, void *data, |