From 0f27b084fe6c0ddeec3293ef86730b6c8d9b5120 Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Wed, 13 Feb 2008 14:39:41 +0000 Subject: Relevant BUGIDs: Purpose of commit: bugfix Commit summary: --------------- 2008-02-13 Thorsten Kukuk * modules/pam_rhosts/Makefile.am: Remove pam_rhosts_auth. * modules/pam_rhosts/pam_rhosts_auth.c: Removed. * modules/pam_rhosts/tst-pam_rhosts_auth: Removed. * modules/pam_namespace/Makefile.am (noinst_HEADERS): Add pam_namespace.h. --- modules/pam_rhosts/Makefile.am | 9 +- modules/pam_rhosts/pam_rhosts_auth.c | 782 --------------------------------- modules/pam_rhosts/tst-pam_rhosts_auth | 2 - 3 files changed, 4 insertions(+), 789 deletions(-) delete mode 100644 modules/pam_rhosts/pam_rhosts_auth.c delete mode 100755 modules/pam_rhosts/tst-pam_rhosts_auth (limited to 'modules/pam_rhosts') diff --git a/modules/pam_rhosts/Makefile.am b/modules/pam_rhosts/Makefile.am index 26fdf9c6..547ad621 100644 --- a/modules/pam_rhosts/Makefile.am +++ b/modules/pam_rhosts/Makefile.am @@ -1,12 +1,12 @@ # -# Copyright (c) 2005, 2006 Thorsten Kukuk +# Copyright (c) 2005, 2006, 2008 Thorsten Kukuk # CLEANFILES = *~ -EXTRA_DIST = README $(MANS) $(XMLS) tst-pam_rhosts_auth tst-pam_rhosts +EXTRA_DIST = README $(MANS) $(XMLS) tst-pam_rhosts -TESTS = tst-pam_rhosts_auth tst-pam_rhosts +TESTS = tst-pam_rhosts man_MANS = pam_rhosts.8 @@ -21,8 +21,7 @@ if HAVE_VERSIONING AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map endif -securelib_LTLIBRARIES = pam_rhosts_auth.la pam_rhosts.la -pam_rhosts_auth_la_LIBADD = -L$(top_builddir)/libpam -lpam +securelib_LTLIBRARIES = pam_rhosts.la pam_rhosts_la_LIBADD = -L$(top_builddir)/libpam -lpam if ENABLE_REGENERATE_MAN diff --git a/modules/pam_rhosts/pam_rhosts_auth.c b/modules/pam_rhosts/pam_rhosts_auth.c deleted file mode 100644 index db28290a..00000000 --- a/modules/pam_rhosts/pam_rhosts_auth.c +++ /dev/null @@ -1,782 +0,0 @@ -/*---------------------------------------------------------------------- - * Modified for Linux-PAM by Al Longyear 96/5/5 - * Modifications, Cristian Gafton 97/2/8 - * Modifications, Peter Allgeyer 97/3 - * Modifications (netgroups and fixes), Nicolai Langfeldt 97/3/21 - * Security fix: 97/10/2 - gethostbyname called repeatedly without care - * Modification (added privategroup option) Andrew - *---------------------------------------------------------------------- - * Copyright (c) 1983, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * 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, this list of conditions and the following disclaimer. - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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 "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_FSUID_H -#include -#endif /* HAVE_SYS_FSUID_H */ -#ifdef HAVE_NET_IF_H -#include -#endif -#include -#include -#include - -#ifndef MAXDNAME -#define MAXDNAME 256 -#endif - -#ifndef _PATH_HEQUIV -#define _PATH_HEQUIV "/etc/hosts.equiv" -#endif /* _PATH_HEQUIV */ - -#define USER_RHOSTS_FILE "/.rhosts" /* prefixed by user's home dir */ - -#define PAM_SM_AUTH /* only defines this management group */ - -#include -#include -#include -#include - -/* - * Options for this module - */ - -struct _options { - int opt_no_hosts_equiv; - int opt_hosts_equiv_rootok; - int opt_no_rhosts; - int opt_debug; - int opt_nowarn; - int opt_disallow_null_authtok; - int opt_silent; - int opt_promiscuous; - int opt_suppress; - int opt_private_group; - int opt_no_uid_check; - const char *superuser; - const char *last_error; -}; - -static void -set_option (const pam_handle_t *pamh, struct _options *opts, const char *arg) -{ - if (strcmp(arg, "no_hosts_equiv") == 0) { - opts->opt_no_hosts_equiv = 1; - return; - } - - if (strcmp(arg, "hosts_equiv_rootok") == 0) { - opts->opt_hosts_equiv_rootok = 1; - return; - } - - if (strcmp(arg, "no_rhosts") == 0) { - opts->opt_no_rhosts = 1; - return; - } - - if (strcmp(arg, "debug") == 0) { - D(("debugging enabled")); - opts->opt_debug = 1; - return; - } - - if (strcmp(arg, "no_warn") == 0) { - opts->opt_nowarn = 1; - return; - } - - if (strcmp(arg, "promiscuous") == 0) { - opts->opt_promiscuous = 1; /* used to permit '+' in ...hosts file */ - return; - } - - if (strcmp(arg, "suppress") == 0) { - opts->opt_suppress = 1; /* used to suppress failure warning message */ - return; - } - - if (strcmp(arg, "privategroup") == 0) { - opts->opt_private_group = 1; /* used to permit group write on .rhosts - file if group has same name as owner */ - return; - } - - if (strcmp(arg, "no_uid_check") == 0) { - opts->opt_no_uid_check = 1; /* NIS optimization */ - return; - } - - if (strncmp(arg, "superuser=", sizeof("superuser=")-1) == 0) { - opts->superuser = arg+sizeof("superuser=")-1; - return; - } - /* - * All other options are ignored at the present time. - */ - pam_syslog(pamh, LOG_WARNING, "unrecognized option '%s'", arg); -} - -static void -set_parameters (const pam_handle_t *pamh, struct _options *opts, - int flags, int argc, const char **argv) -{ - opts->opt_silent = flags & PAM_SILENT; - opts->opt_disallow_null_authtok = flags & PAM_DISALLOW_NULL_AUTHTOK; - - while (argc-- > 0) { - set_option (pamh, opts, *argv); - ++argv; - } -} - -/* - * Obtain the name of the remote host. Currently, this is simply by - * requesting the contents of the PAM_RHOST item. - */ - -static int -pam_get_rhost (pam_handle_t *pamh, const char **rhost) -{ - int retval; - const void *current; - - retval = pam_get_item (pamh, PAM_RHOST, ¤t); - if (retval != PAM_SUCCESS) - return retval; - - if (current == NULL) { - return PAM_AUTH_ERR; - } - *rhost = current; - - return retval; /* pass on any error from conversation */ -} - -/* - * Obtain the name of the remote user. Currently, this is simply by - * requesting the contents of the PAM_RUSER item. - */ - -static int -pam_get_ruser(pam_handle_t *pamh, const char **ruser) -{ - int retval; - const void *current; - - retval = pam_get_item (pamh, PAM_RUSER, ¤t); - if (retval != PAM_SUCCESS) { - return retval; - } - - if (current == NULL) { - return PAM_AUTH_ERR; - } - *ruser = current; - - return retval; /* pass on any error from conversation */ -} - -/* - * Returns 1 if positive match, 0 if no match, -1 if negative match. - */ - -static int -__icheckhost (pam_handle_t *pamh, struct _options *opts, u_int32_t raddr - , register char *lhost, const char *rhost) -{ - struct hostent *hp; - u_int32_t laddr; - int negate=1; /* Multiply return with this to get -1 instead of 1 */ - char **pp; - const void *user; - - /* Check nis netgroup. We assume that pam has done all needed - paranoia checking before we are handed the rhost */ - if (strncmp("+@",lhost,2) == 0) - return(innetgr(&lhost[2],rhost,NULL,NULL)); - - if (strncmp("-@",lhost,2) == 0) - return(-innetgr(&lhost[2],rhost,NULL,NULL)); - - /* -host */ - if (strncmp("-",lhost,1) == 0) { - negate=-1; - lhost++; - } else if (strcmp("+",lhost) == 0) { - (void) pam_get_item(pamh, PAM_USER, &user); - D(("user %s has a `+' host entry", user)); - if (opts->opt_promiscuous) - return (1); /* asking for trouble, but ok.. */ - /* If not promiscuous: handle as negative */ - return (-1); - } else if (strncmp("+",lhost,1) == 0) { - /* '+hostname' is supposed to be equivalent to 'hostname' */ - lhost++; - } - - - /* Try for raw ip address first. */ - if (isdigit(*lhost) && (int32_t)(laddr = inet_addr(lhost)) != -1) - return (negate*(! (raddr ^ laddr))); - - /* Better be a hostname. */ - 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 (u_int32_t))) - return (negate); - - /* No match. */ - return (0); -} - -/* Returns 1 on positive match, 0 on no match, -1 on negative match */ - -static int -__icheckuser (pam_handle_t *pamh, struct _options *opts, - const char *luser, const char *ruser) -{ - /* - luser is user entry from .rhosts/hosts.equiv file - ruser is user id on remote host - */ - const void *user; - - /* [-+]@netgroup */ - if (strncmp("+@",luser,2) == 0) - return (innetgr(&luser[2],NULL,ruser,NULL)); - - if (strncmp("-@",luser,2) == 0) - return (-innetgr(&luser[2],NULL,ruser,NULL)); - - /* -user */ - if (strncmp("-",luser,1) == 0) - return(-(strcmp(&luser[1],ruser) == 0)); - - /* + */ - if (strcmp("+",luser) == 0) { - (void) pam_get_item(pamh, PAM_USER, &user); - pam_syslog(pamh, LOG_WARNING, "user %s has a `+' user entry", - (const char *) user); - if (opts->opt_promiscuous) - return(1); - /* If not promiscuous we handle it as a negative match */ - return(-1); - } - - /* simple string match */ - return (strcmp(ruser, luser) == 0); -} - -/* - * Returns 1 for blank lines (or only comment lines) and 0 otherwise - */ - -static int __isempty(char *p) -{ - while (*p && isspace(*p)) { - ++p; - } - - return (*p == '\0' || *p == '#') ? 1:0 ; -} - -/* - * Returns 0 if positive match, 1 if _not_ ok. - */ - -static int -__ivaliduser (pam_handle_t *pamh, struct _options *opts, - FILE *hostf, u_int32_t raddr, - const char *luser, const char *ruser, const char *rhost) -{ - register const char *user; - register char *p; - int hcheck, ucheck; - int retval = 1; -#ifdef HAVE_GETLINE - char *buf=NULL; - size_t buflen=0; - - while (getline(&buf,&buflen,hostf) > 0) { -#else - char buf[MAXHOSTNAMELEN + 128]; /* host + login */ - - while (fgets(buf, sizeof(buf), hostf) != NULL) { /* hostf file line */ -#endif - p = buf; /* from beginning of file.. */ - - /* Skip empty or comment lines */ - if (__isempty(p)) { - continue; - } - - /* Skip lines that are too long. */ - if (strchr(p, '\n') == NULL) { - int ch = getc(hostf); - - while (ch != '\n' && ch != EOF) - ch = getc(hostf); - continue; - } - - /* - * If there is a hostname at the start of the line. Set it to - * lower case. A leading ' ' or '\t' indicates no hostname - */ - - for (;*p && !isspace(*p); ++p) { - *p = tolower(*p); - } - - /* - * next we want to find the permitted name for the remote user - */ - - if (*p == ' ' || *p == '\t') { - - /* terminate hostname and skip spaces */ - for (*p++='\0'; *p && isspace(*p); ++p); - - user = p; /* this is the user's name */ - while (*p && !isspace(*p)) - ++p; /* find end of user's name */ - } else - user = p; - - *p = '\0'; /* terminate username (+host?) */ - - /* buf -> host(?) ; user -> username(?) */ - - /* First check host part */ - hcheck=__icheckhost(pamh, opts, raddr, buf, rhost); - - if (hcheck<0) - break; - - if (hcheck) { - /* Then check user part */ - if (! (*user)) - user = luser; - - ucheck=__icheckuser(pamh, opts, user, ruser); - - /* Positive 'host user' match? */ - if (ucheck>0) { - retval = 0; - break; - } - - /* Negative 'host -user' match? */ - if (ucheck<0) - break; - - /* Neither, go on looking for match */ - } - } -#ifdef HAVE_GETLINE - if(buf)free(buf); -#endif - - return retval; -} - -/* - * New .rhosts strategy: We are passed an ip address. We spin through - * hosts.equiv and .rhosts looking for a match. When the .rhosts only - * has ip addresses, we don't have to trust a nameserver. When it - * contains hostnames, we spin through the list of addresses the nameserver - * gives us and look for a match. - * - * Returns 0 if ok, -1 if not ok. - */ - -static int -pam_iruserok(pam_handle_t *pamh, - struct _options *opts, u_int32_t raddr, int superuser, - const char *ruser, const char *luser, const char *rhost) -{ - const char *cp; - struct stat sbuf; - struct passwd *pwd; - FILE *hostf; - uid_t uid; - int answer; - char *fpath; - - if ((!superuser||opts->opt_hosts_equiv_rootok) && !opts->opt_no_hosts_equiv ) { - - /* try to open system hosts.equiv file */ - hostf = fopen (_PATH_HEQUIV, "r"); - if (hostf) { - answer = __ivaliduser(pamh, opts, hostf, raddr, luser - , ruser, rhost); - (void) fclose(hostf); - if (answer == 0) - return 0; /* remote host is equivalent to localhost */ - } /* else { - No hosts.equiv file on system. - } */ - } - - if ( opts->opt_no_rhosts ) - return 1; - - /* - * Identify user's local .rhosts file - */ - - pwd = pam_modutil_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 - */ - return(1); - } - - if (asprintf (&fpath, "%s%s", pwd->pw_dir, USER_RHOSTS_FILE) < 0) { - pam_syslog (pamh, LOG_ALERT, "Running out of memory"); - return 1; - } - - /* - * Change effective uid while _reading_ .rhosts. (not just - * opening). If root and reading an NFS mounted file system, - * can't read files that are 0600 as .rhosts files should be. - */ - - /* We are root, this will not fail */ -#ifdef __linux__ - /* If we are on linux the better way is setfsuid */ - uid = setfsuid(pwd->pw_uid); - hostf = fopen(fpath, "r"); -#else - uid = geteuid(); - (void) seteuid(pwd->pw_uid); - hostf = fopen(fpath, "r"); -#endif - - if (hostf == NULL) { - if (opts->opt_debug) - pam_syslog(pamh, LOG_DEBUG, "Could not open %s: %m", fpath); - answer = 1; - goto exit_function; - } - - /* - * If not a regular file, or is owned by someone other than - * user or root or if writeable by anyone but the owner, quit. - */ - - cp = NULL; - if (lstat(fpath, &sbuf) < 0 || !S_ISREG(sbuf.st_mode)) - cp = ".rhosts not regular file"; - else if (fstat(fileno(hostf), &sbuf) < 0) - cp = ".rhosts fstat failed"; - else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) - cp = "bad .rhosts owner"; - else if (sbuf.st_mode & S_IWOTH) - cp = ".rhosts writable by other!"; - else if (sbuf.st_mode & S_IWGRP) { - - /* private group caveat */ - if (opts->opt_private_group) { - struct group *grp = pam_modutil_getgrgid(pamh, sbuf.st_gid); - - if (NULL == grp || NULL == grp->gr_name - || strcmp(luser,grp->gr_name)) { - cp = ".rhosts writable by public group"; - } else if (grp->gr_mem) { - int gcount; - - /* require at most one member (luser) of this group */ - for (gcount=0; grp->gr_mem[gcount]; ++gcount) { - if (strcmp(grp->gr_mem[gcount], luser)) { - gcount = -1; - break; - } - } - if (gcount < 0) { - cp = ".rhosts writable by other members of group"; - } - } - } else { - cp = ".rhosts writable by group"; - } - - } /* It is _NOT_ safe to append an else here... Do so prior to - * S_IWGRP check */ - - /* If there were any problems, quit. */ - if (cp) { - opts->last_error = cp; - answer = 1; - goto exit_function; - } - - answer = __ivaliduser (pamh, opts, hostf, raddr, luser, ruser, rhost); - -exit_function: - /* - * Go here to exit after the fsuid/euid has been adjusted so that - * they are reset before we exit. - */ - -#ifdef __linux__ - setfsuid(uid); -#else - (void)seteuid(uid); -#endif - - free (fpath); - - if (hostf != NULL) - (void) fclose(hostf); - - return answer; -} - -static int -pam_ruserok (pam_handle_t *pamh, - struct _options *opts, const char *rhost, int superuser, - const char *ruser, const char *luser) -{ - struct hostent *hp; - int answer = 1; /* default to failure */ - u_int32_t *addrs; - int n, i; - - opts->last_error = (char *) 0; - hp = gethostbyname(rhost); /* identify host */ - - if (hp != NULL) { - /* First of all check the address length */ - if (hp->h_length != 4) { - pam_syslog(pamh, LOG_ALERT, - "pam_rhosts module can't work with non-IPv4 addresses"); - return 1; /* not allowed */ - } - - /* loop though address list */ - for (n = 0; hp->h_addr_list[n]; n++); - D(("rhosts: %d addresses", n)); - - if (n) { - addrs = calloc (n, hp->h_length); - for (i = 0; i < n; i++) - memcpy (addrs+i, hp->h_addr_list[i], hp->h_length); - - for (i = 0; i < n && answer; i++) { - D(("rhosts: address %d is %04x", i, addrs[i])); - answer = pam_iruserok(pamh, opts, addrs[i], superuser, - ruser, luser, rhost); - /* answer == 0 means success */ - } - - free (addrs); - } - } - - return answer; -} - -/* - * Internal function to do authentication - */ - -static int _pam_auth_rhosts (pam_handle_t *pamh, - int flags, - int argc, - const char **argv) -{ - int retval; - const char *luser = NULL; - const char *ruser = NULL, *rhost = NULL; - struct _options opts; - int as_root = 0; - - /* - * Look at the options and set the flags accordingly. - */ - memset (&opts, 0, sizeof (opts)); - set_parameters (pamh, &opts, flags, argc, argv); - /* - * Obtain the parameters for the various items - */ - for (;;) { /* abuse loop to avoid goto */ - - /* get the remotehost */ - D(("getting rhost")); - retval = pam_get_rhost(pamh, &rhost); - (void) pam_set_item(pamh, PAM_RHOST, rhost); - if (retval != PAM_SUCCESS) { - if (opts.opt_debug) { - pam_syslog(pamh, LOG_DEBUG, - "could not get the remote host name"); - } - break; - } - - /* get the remote user */ - D(("getting ruser")); - retval = pam_get_ruser(pamh, &ruser); - (void) pam_set_item(pamh, PAM_RUSER, ruser); - if (retval != PAM_SUCCESS) { - if (opts.opt_debug) - pam_syslog(pamh, LOG_DEBUG, - "could not get the remote username"); - break; - } - - /* get the local user */ - D(("getting user")); - retval = pam_get_user(pamh, &luser, NULL); - if (retval != PAM_SUCCESS) { - if (opts.opt_debug) - pam_syslog(pamh, LOG_DEBUG, - "could not determine name of local user"); - break; - } - - if (opts.superuser && !strcmp(opts.superuser, luser)) { - as_root = 1; - } - - /* check if the luser uid == 0... --cristiang */ - if (! opts.opt_no_uid_check) { - struct passwd *luser_pwd; - - luser_pwd = pam_modutil_getpwnam(pamh, luser); - if (luser_pwd == NULL) { - if (opts.opt_debug) - pam_syslog(pamh, LOG_DEBUG, - "user '%s' unknown to this system", luser); - retval = PAM_AUTH_ERR; - break; - } - if (luser_pwd->pw_uid == 0) - as_root = 1; - luser_pwd = NULL; /* forget */ - } -/* - * Validate the account information. - */ - if (pam_ruserok (pamh, &opts, rhost, as_root, ruser, luser) != 0) { - if ( !opts.opt_suppress ) { - pam_syslog(pamh, LOG_WARNING, "denied to %s@%s as %s: %s", - ruser, rhost, luser, (opts.last_error==NULL) ? - "access not allowed":opts.last_error); - } - retval = PAM_AUTH_ERR; - } else { - pam_syslog(pamh, LOG_NOTICE, "allowed to %s@%s as %s", - ruser, rhost, luser); - } - break; - } - - return retval; -} - -/* --- authentication management functions --- */ - -PAM_EXTERN -int pam_sm_authenticate (pam_handle_t *pamh, - int flags, - int argc, - const char **argv) -{ - int retval; - - if (sizeof(u_int32_t) != 4) { - pam_syslog (pamh, LOG_ALERT, - "pam_rhosts module can\'t work on this hardware (yet)"); - return PAM_AUTH_ERR; - } - sethostent(1); - retval = _pam_auth_rhosts (pamh, flags, argc, argv); - endhostent(); - return retval; -} - -PAM_EXTERN int -pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED, - int argc UNUSED, const char **argv UNUSED) -{ - return PAM_SUCCESS; -} - -/* end of module definition */ - - -#ifdef PAM_STATIC - -/* static module data */ - -struct pam_module _pam_rhosts_auth_modstruct = { - "pam_rhosts_auth", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - NULL, - NULL, - NULL, -}; - -#endif diff --git a/modules/pam_rhosts/tst-pam_rhosts_auth b/modules/pam_rhosts/tst-pam_rhosts_auth deleted file mode 100755 index 6b14ec51..00000000 --- a/modules/pam_rhosts/tst-pam_rhosts_auth +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -../../tests/tst-dlopen .libs/pam_rhosts_auth.so -- cgit v1.2.3