int iruserok(unsigned long raddr, int superuser, const char *ruser, const char *luser) { /* Returns 0 if ok, -1 if not ok. */ struct passwd *pwd; FILE *hostf; int i, r; char pbuf[PATH_MAX]; for (i = 0; i < 2; i++) { if (i == 0) { strcpy(pbuf, _PATH_HEQUIV); } else { if (!__check_rhosts_file) return (-1); if ((pwd = getpwnam(luser)) == NULL) return (-1); (void)strcpy(pbuf, pwd->pw_dir); (void)strcat(pbuf, "/.rhosts"); } if ((hostf = fopen(pbuf, "r")) == NULL) { if (errno == ENOENT) continue; return (-1); } r = __ivaliduser(hostf, raddr, luser, ruser); (void)fclose(hostf); if (r == 0) return (0); } return (-1); }
/* * 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. */ int ROKEN_LIB_FUNCTION iruserok(unsigned raddr, int superuser, const char *ruser, const char *luser) { char *cp; struct stat sbuf; struct passwd *pwd; FILE *hostf; uid_t uid; int first; char pbuf[MaxPathLen]; first = 1; hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); again: if (hostf) { if (__ivaliduser(hostf, raddr, luser, ruser) == 0) { fclose(hostf); return (0); } fclose(hostf); } if (first == 1 && (__check_rhosts_file || superuser)) { first = 0; if ((pwd = k_getpwnam((char*)luser)) == NULL) return (-1); snprintf (pbuf, sizeof(pbuf), "%s/.rhosts", pwd->pw_dir); /* * Change effective uid while opening .rhosts. If root and * reading an NFS mounted file system, can't read files that * are protected read/write owner only. */ uid = geteuid(); if (seteuid(pwd->pw_uid) < 0) return (-1); hostf = fopen(pbuf, "r"); seteuid(uid); if (hostf == NULL) return (-1); /* * 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(pbuf, &sbuf) < 0) cp = ".rhosts lstat failed"; else if (!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_IWGRP|S_IWOTH)) cp = ".rhosts writeable by other than owner"; /* If there were any problems, quit. */ if (cp) { __rcmd_errstr = cp; fclose(hostf); return (-1); } goto again; } return (-1); }
static int pam_iruserok(pam_handle_t *pamh, struct _options *opts, U32 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 pbuf[MAXPATHLEN]; /* potential buffer overrun */ 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 = _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 */ return(1); } /* check for buffer overrun */ if (strlen(pwd->pw_dir) + sizeof(USER_RHOSTS_FILE) + 2 >= MAXPATHLEN) { if (opts->opt_debug) _pam_log(LOG_DEBUG,"home directory for `%s' is too long", luser); return 1; /* to dangerous to try */ } (void) strcpy(pbuf, pwd->pw_dir); (void) strcat(pbuf, USER_RHOSTS_FILE); /* * 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(pbuf, "r"); #else uid = geteuid(); (void) seteuid(pwd->pw_uid); hostf = fopen(pbuf, "r"); #endif if (hostf == NULL) { if (opts->opt_debug) _pam_log(LOG_DEBUG,"Could not open %s file",pbuf); 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(pbuf, &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 = getgrgid(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 if (hostf != NULL) (void) fclose(hostf); return answer; }