static int __icheckuser(pam_handle_t *pamh, struct _options *opts , const char *luser, const char *ruser , const char *rhost) { /* luser is user entry from .rhosts/hosts.equiv file ruser is user id on remote host rhost is the remote host name */ char *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, (const void **)&user); _pam_log(LOG_WARNING, "user %s has a `+' user entry", 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 on positive match, 0 on no match, -1 on negative match. */ static int __icheckuser (const char *luser, const char *ruser) { /* luser is user entry from .rhosts/hosts.equiv file ruser is user id on remote host */ #ifdef HAVE_NETGROUP /* [-+]@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); #endif /* HAVE_NETGROUP */ /* -user */ if (strncmp ("-", luser, 1) == 0) return -(strcmp (&luser[1], ruser) == 0); /* + */ if (strcmp ("+", luser) == 0) return 1; /* simple string match */ return strcmp (ruser, luser) == 0; }
static int netgroup_match(const char *group, const char *machine, const char *user) { #if 0 /* original code */ #ifdef NIS static char *mydomain = 0; if (mydomain == 0) yp_get_default_domain(&mydomain); return (innetgr(group, machine, user, mydomain)); #else syslog(LOG_ERR, "NIS netgroup support not configured"); return (NO); #endif #else /* works better with glibc? */ static char *mydomain = 0; if (mydomain == 0) { static char domain[MAXHOSTNAMELEN+1]; getdomainname(domain, MAXHOSTNAMELEN); mydomain = domain; } return innetgr(group, machine, user, mydomain); #endif }
static int __icheckhost (pam_handle_t *pamh, struct _options *opts, U32 raddr , register char *lhost, const char *rhost) { struct hostent *hp; U32 laddr; int negate=1; /* Multiply return with this to get -1 instead of 1 */ char **pp, *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, (const void **)&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) && (long)(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 (U32))) return (negate); /* No match. */ return (0); }
bool user_in_netgroup(TALLOC_CTX *ctx, const char *user, const char *ngname) { #ifdef HAVE_NETGROUP static char *my_yp_domain = NULL; char *lowercase_user = NULL; if (my_yp_domain == NULL) { yp_get_default_domain(&my_yp_domain); } if (my_yp_domain == NULL) { DEBUG(5,("Unable to get default yp domain, " "let's try without specifying it\n")); } DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", user, my_yp_domain?my_yp_domain:"(ANY)", ngname)); if (innetgr(ngname, NULL, user, my_yp_domain)) { DEBUG(5,("user_in_netgroup: Found\n")); return true; } /* * Ok, innetgr is case sensitive. Try once more with lowercase * just in case. Attempt to fix #703. JRA. */ lowercase_user = talloc_strdup(ctx, user); if (!lowercase_user) { return false; } if (!strlower_m(lowercase_user)) { return false; } if (strcmp(user,lowercase_user) == 0) { /* user name was already lower case! */ return false; } DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", lowercase_user, my_yp_domain?my_yp_domain:"(ANY)", ngname)); if (innetgr(ngname, NULL, lowercase_user, my_yp_domain)) { DEBUG(5,("user_in_netgroup: Found\n")); return true; } #endif /* HAVE_NETGROUP */ return false; }
static int netgroup_match (pam_handle_t *pamh, const char *netgroup, const char *machine, const char *user, int debug) { int retval; char *mydomain = NULL; #ifdef HAVE_YP_GET_DEFAUTL_DOMAIN yp_get_default_domain(&mydomain); #elif defined(HAVE_GETDOMAINNAME) char domainname_res[256]; if (getdomainname (domainname_res, sizeof (domainname_res)) == 0) { if (domainname_res[0] != '\0' && strcmp (domainname_res, "(none)") != 0) { mydomain = domainname_res; } } #endif #ifdef HAVE_INNETGR retval = innetgr (netgroup, machine, user, mydomain); #else retval = 0; pam_syslog (pamh, LOG_ERR, "pam_access does not have netgroup support"); #endif if (debug == YES) pam_syslog (pamh, LOG_DEBUG, "netgroup_match: %d (netgroup=%s, machine=%s, user=%s, domain=%s)", retval, netgroup ? netgroup : "NULL", machine ? machine : "NULL", user ? user : "******", mydomain ? mydomain : "NULL"); return retval; }
/* Return PAM_SUCCESS if the (host,user) is NOT in the netgroup. */ static int evaluate_notinnetgr(const char *host, const char *user, const char *group) { if (innetgr(group, host, user, NULL) == 0) return PAM_SUCCESS; return PAM_AUTH_ERR; }
static int netgroupUserMatch(void *priv, const struct SquidInfo *info) { if (innetgr((char *)priv, NULL, info->ident, NULL)) { sgLogDebug("user '%s' is in netgroup %s", info->ident, priv); return 1; } return 0; }
/* test if this host (fully-qualified name) is in netgroup (arg) */ static int f_netgrpd(char *arg) { int status; status = innetgr(arg, opt_hostd, NULL, NULL); dlog("netgrp = %s status = %d hostd = %s", arg, status, opt_hostd); return status; }
static int netgroupHostMatch(void *priv, const struct SquidInfo *info) { if (innetgr((char *)priv, NULL, info->domain, NULL)) { sgLogDebug("host '%s' is in netgroup %s", info->domain, priv); return 1; } return 0; }
/* Return PAM_SUCCESS if the (host,user) is NOT in the netgroup. */ static int evaluate_notinnetgr(const pam_handle_t* pamh, const char *host, const char *user, const char *group) { #ifdef HAVE_INNETGR if (innetgr(group, host, user, NULL) == 0) return PAM_SUCCESS; #else pam_syslog (pamh, LOG_ERR, "pam_succeed_if does not have netgroup support"); #endif return PAM_AUTH_ERR; }
NGR_R_RETURN innetgr_r(const char *netgroup, const char *host, const char *user, const char *domain) { char *ng, *ho, *us, *dom; DE_CONST(netgroup, ng); DE_CONST(host, ho); DE_CONST(user, us); DE_CONST(domain, dom); return (innetgr(ng, ho, us, dom)); }
BOOL user_in_netgroup(const char *user, const char *ngname) { #ifdef HAVE_NETGROUP static char *mydomain = NULL; fstring lowercase_user; if (mydomain == NULL) yp_get_default_domain(&mydomain); if(mydomain == NULL) { DEBUG(5,("Unable to get default yp domain, let's try without specifying it\n")); } DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", user, mydomain?mydomain:"(ANY)", ngname)); if (innetgr(ngname, NULL, user, mydomain)) { DEBUG(5,("user_in_netgroup: Found\n")); return (True); } else { /* * Ok, innetgr is case sensitive. Try once more with lowercase * just in case. Attempt to fix #703. JRA. */ fstrcpy(lowercase_user, user); strlower_m(lowercase_user); DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", lowercase_user, mydomain?mydomain:"(ANY)", ngname)); if (innetgr(ngname, NULL, lowercase_user, mydomain)) { DEBUG(5,("user_in_netgroup: Found\n")); return (True); } } #endif /* HAVE_NETGROUP */ return False; }
static BOOL user_in_netgroup_list(char *user,char *ngname) { #ifdef HAVE_NETGROUP static char *mydomain = NULL; if (mydomain == NULL) yp_get_default_domain(&mydomain); if(mydomain == NULL) { DEBUG(5,("Unable to get default yp domain\n")); } else { DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", user, mydomain, ngname)); DEBUG(5,("innetgr is %s\n", innetgr(ngname, NULL, user, mydomain) ? "TRUE" : "FALSE")); if (innetgr(ngname, NULL, user, mydomain)) return (True); } #endif /* HAVE_NETGROUP */ return False; }
static int netgroup_match(char *group, char *machine, char *user) { #ifdef NIS static char *mydomain = 0; 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 }
/* netgroup_match - match group against machine or user */ static bool netgroup_match (const char *group, const char *machine, const char *user) { static char *mydomain = (char *)0; if (mydomain == (char *)0) { static char domain[MAXHOSTNAMELEN + 1]; getdomainname (domain, MAXHOSTNAMELEN); mydomain = domain; } return (innetgr (group, machine, user, mydomain) != 0); }
static int netgroup_match(const char *group, const char *machine, const char *user) { char domain[1024]; unsigned int i; if (getdomainname(domain, sizeof(domain)) != 0 || *domain == '\0') { syslog(LOG_ERR, "NIS netgroup support disabled: no NIS domain"); return (NO); } /* getdomainname() does not reliably terminate the string */ for (i = 0; i < sizeof(domain); ++i) if (domain[i] == '\0') break; if (i == sizeof(domain)) { syslog(LOG_ERR, "NIS netgroup support disabled: invalid NIS domain"); return (NO); } if (innetgr(group, machine, user, domain) == 1) return (YES); return (NO); }
/* * Returns 0 if ok, -1 if not ok. */ static int __ivaliduser(FILE *hostf, unsigned raddr, const char *luser, const char *ruser) { char *user, *p; int ch; char buf[MaxHostNameLen + 128]; /* host + login */ char hname[MaxHostNameLen]; struct hostent *hp; /* Presumed guilty until proven innocent. */ int userok = 0, hostok = 0; #ifdef HAVE_YP_GET_DEFAULT_DOMAIN char *ypdomain; if (yp_get_default_domain(&ypdomain)) ypdomain = NULL; #else #define ypdomain NULL #endif /* We need to get the damn hostname back for netgroup matching. */ if ((hp = gethostbyaddr((char *)&raddr, sizeof(u_long), AF_INET)) == NULL) return (-1); strlcpy(hname, hp->h_name, sizeof(hname)); while (fgets(buf, sizeof(buf), hostf)) { p = buf; /* Skip lines that are too long. */ if (strchr(p, '\n') == NULL) { while ((ch = getc(hostf)) != '\n' && ch != EOF); continue; } if (*p == '\n' || *p == '#') { /* comment... */ continue; } while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { if (isupper((unsigned char)*p)) *p = tolower((unsigned char)*p); p++; } if (*p == ' ' || *p == '\t') { *p++ = '\0'; while (*p == ' ' || *p == '\t') p++; user = p; while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') p++; } else user = p; *p = '\0'; /* * Do +/- and +@/-@ checking. This looks really nasty, * but it matches SunOS's behavior so far as I can tell. */ switch(buf[0]) { case '+': if (!buf[1]) { /* '+' matches all hosts */ hostok = 1; break; } if (buf[1] == '@') /* match a host by netgroup */ hostok = innetgr((char *)&buf[2], (char *)&hname, NULL, ypdomain); else /* match a host by addr */ hostok = __icheckhost(raddr,(char *)&buf[1]); break; case '-': /* reject '-' hosts and all their users */ if (buf[1] == '@') { if (innetgr((char *)&buf[2], (char *)&hname, NULL, ypdomain)) return(-1); } else { if (__icheckhost(raddr,(char *)&buf[1])) return(-1); } break; default: /* if no '+' or '-', do a simple match */ hostok = __icheckhost(raddr, buf); break; } switch(*user) { case '+': if (!*(user+1)) { /* '+' matches all users */ userok = 1; break; } if (*(user+1) == '@') /* match a user by netgroup */ userok = innetgr(user+2, NULL, (char *)ruser, ypdomain); else /* match a user by direct specification */ userok = !(strcmp(ruser, user+1)); break; case '-': /* if we matched a hostname, */ if (hostok) { /* check for user field rejections */ if (!*(user+1)) return(-1); if (*(user+1) == '@') { if (innetgr(user+2, NULL, (char *)ruser, ypdomain)) return(-1); } else { if (!strcmp(ruser, user+1)) return(-1); } } break; default: /* no rejections: try to match the user */ if (hostok) userok = !(strcmp(ruser,*user ? user : luser)); break; } if (hostok && userok) return(0); } return (-1); }
/**************************************************************************** read the a hosts.equiv or .rhosts file and check if it allows this user from this machine ****************************************************************************/ static BOOL check_user_equiv(char *user, char *remote, char *equiv_file) { pstring buf; int plus_allowed = 1; char *file_host; char *file_user; FILE *fp = fopen(equiv_file, "r"); DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file)); if (! fp) return False; while(fgets(buf, sizeof(buf), fp)) { trim_string(buf," "," "); if (buf[0] != '#' && buf[0] != '\n') { BOOL is_group = False; int plus = 1; char *bp = buf; if (strcmp(buf, "NO_PLUS\n") == 0) { DEBUG(6, ("check_user_equiv NO_PLUS\n")); plus_allowed = 0; } else { if (buf[0] == '+') { bp++; if (*bp == '\n' && plus_allowed) { /* a bare plus means everbody allowed */ DEBUG(6, ("check_user_equiv everybody allowed\n")); fclose(fp); return True; } } else if (buf[0] == '-') { bp++; plus = 0; } if (*bp == '@') { is_group = True; bp++; } file_host = strtok(bp, " \t\n"); file_user = strtok(NULL, " \t\n"); DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)", file_user ? file_user : "******" )); if (file_host && *file_host) { BOOL host_ok = False; #ifdef NETGROUP if (is_group) { static char *mydomain = NULL; if (!mydomain) yp_get_default_domain(&mydomain); if (mydomain && innetgr(file_host,remote,user,mydomain)) host_ok = True; } #else if (is_group) { DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n")); continue; } #endif /* is it this host */ /* the fact that remote has come from a call of gethostbyaddr * means that it may have the fully qualified domain name * so we could look up the file version to get it into * a canonical form, but I would rather just type it * in full in the equiv file */ if (!host_ok && !is_group && strequal(remote, file_host)) host_ok = True; if (!host_ok) continue; /* is it this user */ if (file_user == 0 || strequal(user, file_user)) { fclose(fp); DEBUG(5, ("check_user_equiv matched %s%s %s\n", (plus ? "+" : "-"), file_host, (file_user ? file_user : ""))); return (plus ? True : False); } } } } } fclose(fp); return False; }
static int _validuser(FILE *hostf, char *rhost, const char *luser, const char *ruser, int baselen) { char *user; char ahost[BUFSIZ]; char *uchost = (char *)NULL; int hostmatch, usermatch; char *p; #ifdef NIS if (domain == NULL) { (void) usingypmap(&domain, NULL); } #endif /* NIS */ while (fgets(ahost, (int)sizeof (ahost), hostf)) { uchost = (char *)NULL; hostmatch = usermatch = 0; p = ahost; /* * We can get a line bigger than our buffer. If so we skip * the offending line. */ if (strchr(p, '\n') == NULL) { while (fgets(ahost, (int)sizeof (ahost), hostf) && strchr(ahost, '\n') == NULL) ; continue; } while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { /* * Both host and user ``names'' can be netgroups, * and must have their case preserved. Case is * preserved for user names because we break out * of this loop when finding a field separator. * To do so for host names, we must make a copy of * the host name field. */ if (isupper(*p)) { if (uchost == (char *)NULL) uchost = strdup(ahost); *p = tolower(*p); } p++; } if (*p != '\0' && uchost != (char *)NULL) uchost[p - ahost] = '\0'; if (*p == ' ' || *p == '\t') { *p++ = '\0'; while (*p == ' ' || *p == '\t') p++; user = p; while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') p++; } else user = p; *p = '\0'; if (ahost[0] == '+' && ahost[1] == 0) hostmatch = 1; #ifdef NIS else if (ahost[0] == '+' && ahost[1] == '@') if (uchost != (char *)NULL) hostmatch = innetgr(uchost + 2, rhost, NULL, domain); else hostmatch = innetgr(ahost + 2, rhost, NULL, domain); else if (ahost[0] == '-' && ahost[1] == '@') { if (uchost != (char *)NULL) { if (innetgr(uchost + 2, rhost, NULL, domain)) break; } else { if (innetgr(ahost + 2, rhost, NULL, domain)) break; } } #endif /* NIS */ else if (ahost[0] == '-') { if (_checkhost(rhost, ahost+1, baselen)) break; } else hostmatch = _checkhost(rhost, ahost, baselen); if (user[0]) { if (user[0] == '+' && user[1] == 0) usermatch = 1; #ifdef NIS else if (user[0] == '+' && user[1] == '@') usermatch = innetgr(user+2, NULL, ruser, domain); else if (user[0] == '-' && user[1] == '@') { if (hostmatch && innetgr(user+2, NULL, ruser, domain)) break; } #endif /* NIS */ else if (user[0] == '-') { if (hostmatch && (strcmp(user+1, ruser) == 0)) break; } else usermatch = (strcmp(user, ruser) == 0); } else usermatch = (strcmp(ruser, luser) == 0); if (uchost != (char *)NULL) free(uchost); if (hostmatch && usermatch) return (0); } if (uchost != (char *)NULL) free(uchost); return (-1); }
/*ARGSUSED*/ int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { FILE *fd; const char *allowdeny_filename = PF_PATH; char buf[BUFSIZ]; char hostname[MAXHOSTNAMELEN]; char *username = NULL; char *bufp; char *rhost; char *limit; int userok = 0; int hostok = 0; int i; int allow_deny_test = 0; boolean_t debug = B_FALSE; boolean_t allow = B_FALSE; boolean_t matched = B_FALSE; boolean_t check_user = B_TRUE; boolean_t check_host = B_FALSE; boolean_t check_exact = B_FALSE; pam_list_mode_t op_mode = LIST_PLUS_CHECK; for (i = 0; i < argc; ++i) { if (strncasecmp(argv[i], "debug", sizeof ("debug")) == 0) { debug = B_TRUE; } else if (strncasecmp(argv[i], "user", sizeof ("user")) == 0) { check_user = B_TRUE; } else if (strncasecmp(argv[i], "nouser", sizeof ("nouser")) == 0) { check_user = B_FALSE; } else if (strncasecmp(argv[i], "host", sizeof ("host")) == 0) { check_host = B_TRUE; } else if (strncasecmp(argv[i], "nohost", sizeof ("nohost")) == 0) { check_host = B_FALSE; } else if (strncasecmp(argv[i], "user_host_exact", sizeof ("user_host_exact")) == 0) { check_exact = B_TRUE; } else if (strcasecmp(argv[i], "compat") == 0) { if (op_mode == LIST_PLUS_CHECK) { op_mode = LIST_COMPAT_MODE; } else { log_illegal_combination("compat", string_mode_type(op_mode, allow)); return (PAM_SERVICE_ERR); } } else if (strncasecmp(argv[i], "allow=", sizeof ("allow=") - 1) == 0) { if (op_mode == LIST_PLUS_CHECK) { allowdeny_filename = argv[i] + sizeof ("allow=") - 1; allow = B_TRUE; op_mode = LIST_EXTERNAL_FILE; allow_deny_test++; } else { log_illegal_combination("allow", string_mode_type(op_mode, allow)); return (PAM_SERVICE_ERR); } } else if (strncasecmp(argv[i], "deny=", sizeof ("deny=") - 1) == 0) { if (op_mode == LIST_PLUS_CHECK) { allowdeny_filename = argv[i] + sizeof ("deny=") - 1; allow = B_FALSE; op_mode = LIST_EXTERNAL_FILE; allow_deny_test++; } else { log_illegal_combination("deny", string_mode_type(op_mode, allow)); return (PAM_SERVICE_ERR); } } else { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: illegal option %s", argv[i]); return (PAM_SERVICE_ERR); } } if (((check_user || check_host || check_exact) == B_FALSE) || (allow_deny_test > 1)) { __pam_log(LOG_AUTH | LOG_ERR, ILLEGAL_COMBINATION); return (PAM_SERVICE_ERR); } if ((op_mode == LIST_COMPAT_MODE) && (check_user == B_FALSE)) { log_illegal_combination("compat", "nouser"); return (PAM_SERVICE_ERR); } if (debug) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_list: check_user = %d, check_host = %d," "check_exact = %d\n", check_user, check_host, check_exact); __pam_log(LOG_AUTH | LOG_DEBUG, "pam_list: auth_file: %s, %s\n", allowdeny_filename, (op_mode == LIST_COMPAT_MODE) ? "compat mode" : (allow ? "allow file" : "deny file")); } (void) pam_get_item(pamh, PAM_USER, (void**)&username); if ((check_user || check_exact) && ((username == NULL) || (*username == '\0'))) { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: username not supplied, critical error"); return (PAM_USER_UNKNOWN); } (void) pam_get_item(pamh, PAM_RHOST, (void**)&rhost); if ((check_host || check_exact) && ((rhost == NULL) || (*rhost == '\0'))) { if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { rhost = hostname; } else { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: error by gethostname - %m"); return (PAM_SERVICE_ERR); } } if (debug) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_list: pam_sm_acct_mgmt for (%s,%s,)", (rhost != NULL) ? rhost : "", username); } if (strlen(allowdeny_filename) == 0) { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: file name not specified"); return (PAM_SERVICE_ERR); } if ((fd = fopen(allowdeny_filename, "rF")) == NULL) { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: fopen of %s: %s", allowdeny_filename, strerror(errno)); return (PAM_SERVICE_ERR); } while (fgets(buf, BUFSIZ, fd) != NULL) { /* lines longer than BUFSIZ-1 */ if ((strlen(buf) == (BUFSIZ - 1)) && (buf[BUFSIZ - 2] != '\n')) { while ((fgetc(fd) != '\n') && (!feof(fd))) { continue; } __pam_log(LOG_AUTH | LOG_DEBUG, "pam_list: long line in file," "more than %d chars, the rest ignored", BUFSIZ - 1); } /* remove unneeded colons if necessary */ if ((limit = strpbrk(buf, ":\n")) != NULL) { *limit = '\0'; } /* ignore free values */ if (buf[0] == '\0') { continue; } bufp = buf; /* test for interesting lines = +/- in /etc/passwd */ if (op_mode == LIST_COMPAT_MODE) { /* simple + matches all */ if ((buf[0] == '+') && (buf[1] == '\0')) { matched = B_TRUE; allow = B_TRUE; break; } /* simple - is not defined */ if ((buf[0] == '-') && (buf[1] == '\0')) { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: simple minus unknown, " "illegal line in " PF_PATH); (void) fclose(fd); return (PAM_SERVICE_ERR); } /* @ is not allowed on the first position */ if (buf[0] == '@') { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: @ is not allowed on the first " "position in " PF_PATH); (void) fclose(fd); return (PAM_SERVICE_ERR); } /* -user or -@netgroup */ if (buf[0] == '-') { allow = B_FALSE; bufp++; /* +user or +@netgroup */ } else if (buf[0] == '+') { allow = B_TRUE; bufp++; /* user */ } else { allow = B_TRUE; } } else if (op_mode == LIST_PLUS_CHECK) { if (((buf[0] != '+') && (buf[0] != '-')) || (buf[1] == '\0')) { continue; } if (buf[0] == '+') { allow = B_TRUE; } else { allow = B_FALSE; } bufp++; } /* * if -> netgroup line * else -> user line */ if ((bufp[0] == '@') && (bufp[1] != '\0')) { bufp++; if (check_exact) { if (innetgr(bufp, rhost, username, NULL) == 1) { matched = B_TRUE; break; } } else { if (check_user) { userok = innetgr(bufp, NULL, username, NULL); } else { userok = 1; } if (check_host) { hostok = innetgr(bufp, rhost, NULL, NULL); } else { hostok = 1; } if (userok && hostok) { matched = B_TRUE; break; } } } else { if (check_user) { if (strcmp(bufp, username) == 0) { matched = B_TRUE; break; } } } /* * No match found in /etc/passwd yet. For compat mode * a failure to match should result in a return of * PAM_PERM_DENIED which is achieved below if 'matched' * is false and 'allow' is true. */ if (op_mode == LIST_COMPAT_MODE) { allow = B_TRUE; } } (void) fclose(fd); if (debug) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_list: %s for %s", matched ? "matched" : "no match", allow ? "allow" : "deny"); } if (matched) { return (allow ? PAM_SUCCESS : PAM_PERM_DENIED); } /* * For compatibility with passwd_compat mode to prevent root access * denied. */ if (op_mode == LIST_PLUS_CHECK) { return (PAM_IGNORE); } return (allow ? PAM_PERM_DENIED : PAM_SUCCESS); }
/* Returns 1 on positive match, 0 on no match, -1 on negative match. */ static int __icheckhost (u_int32_t raddr, 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; #ifdef __UCLIBC_HAS_REENTRANT_RPC__ int save_errno; size_t buflen; char *buffer; struct hostent hostbuf; int herr; #endif #ifdef HAVE_NETGROUP /* Check nis netgroup. */ if (strncmp ("+@", lhost, 2) == 0) return innetgr (&lhost[2], rhost, NULL, NULL); if (strncmp ("-@", lhost, 2) == 0) return -innetgr (&lhost[2], rhost, NULL, NULL); #endif /* HAVE_NETGROUP */ /* -host */ if (strncmp ("-", lhost,1) == 0) { negate = -1; lhost++; } else if (strcmp ("+",lhost) == 0) { return 1; /* asking for trouble, but ok.. */ } /* Try for raw ip address first. */ if (isdigit (*lhost) && (laddr = inet_addr (lhost)) != INADDR_NONE) return negate * (! (raddr ^ laddr)); /* Better be a hostname. */ #ifdef __UCLIBC_HAS_REENTRANT_RPC__ buflen = 1024; buffer = malloc(buflen); save_errno = errno; while (gethostbyname_r (lhost, &hostbuf, buffer, buflen, &hp, &herr) != 0) { free(buffer); return (0); } free(buffer); __set_errno (save_errno); #else hp = gethostbyname(lhost); #endif /* __UCLIBC_HAS_REENTRANT_RPC__ */ 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); }
/* update our image of the net-group of trustworthy hosts */ void get_goodgroup(int force) { # define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */ static unsigned long last_update = -NG_DELAY; unsigned long new_update; struct goodhost *ghp, **ghpp; #ifdef HAVENIS struct hosttbl *htp; char *mach, *usr, *dom; #endif /* HAVENIS */ struct tms tm; /* if no netgroup, then we are finished */ if (goodgroup == NULL || !Mflag) return; /* Do not chatter with the netgroup master too often. */ new_update = times(&tm); if (new_update < last_update + NG_DELAY && !force) return; last_update = new_update; /* forget the old temporary entries */ ghpp = &goodhosts; while ((ghp = *ghpp) != NULL) { if (!ghp->perm) { *ghpp = ghp->next; free(ghp); } else { ghpp = &ghp->next; } } #ifdef HAVENIS /* quit now if we are not one of the trusted masters */ if (!innetgr(goodgroup, &hostname[0], 0,0)) { if (trace) (void)fprintf(fd, "get_goodgroup: %s not in %s\n", &hostname[0], goodgroup); return; } if (trace) (void)fprintf(fd, "get_goodgroup: %s in %s\n", &hostname[0], goodgroup); /* mark the entire netgroup as trusted */ (void)setnetgrent(goodgroup); while (getnetgrent(&mach,&usr,&dom)) { if (mach != NULL) add_good_host(mach,0); } (void)endnetgrent(); /* update list of slaves */ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { htp->good = good_host_name(&htp->name[0]); } #endif /* HAVENIS */ }
int __ivaliduser_sa(FILE *hostf, const struct sockaddr *raddr, socklen_t salen, const char *luser, const char *ruser) { char *user, *p; int ch; char buf[MAXHOSTNAMELEN + 128]; /* host + login */ char hname[MAXHOSTNAMELEN]; /* Presumed guilty until proven innocent. */ int userok = 0, hostok = 0; #ifdef YP char *ypdomain; if (yp_get_default_domain(&ypdomain)) ypdomain = NULL; #else #define ypdomain NULL #endif /* We need to get the damn hostname back for netgroup matching. */ if (getnameinfo(raddr, salen, hname, sizeof(hname), NULL, 0, NI_NAMEREQD) != 0) hname[0] = '\0'; while (fgets(buf, sizeof(buf), hostf)) { p = buf; /* Skip lines that are too long. */ if (strchr(p, '\n') == NULL) { while ((ch = getc(hostf)) != '\n' && ch != EOF); continue; } if (*p == '\n' || *p == '#') { /* comment... */ continue; } while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { *p = isupper((unsigned char)*p) ? tolower((unsigned char)*p) : *p; p++; } if (*p == ' ' || *p == '\t') { *p++ = '\0'; while (*p == ' ' || *p == '\t') p++; user = p; while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') p++; } else user = p; *p = '\0'; /* * Do +/- and +@/-@ checking. This looks really nasty, * but it matches SunOS's behavior so far as I can tell. */ switch(buf[0]) { case '+': if (!buf[1]) { /* '+' matches all hosts */ hostok = 1; break; } if (buf[1] == '@') /* match a host by netgroup */ hostok = hname[0] != '\0' && innetgr(&buf[2], hname, NULL, ypdomain); else /* match a host by addr */ hostok = __icheckhost(raddr, salen, (char *)&buf[1]); break; case '-': /* reject '-' hosts and all their users */ if (buf[1] == '@') { if (hname[0] == '\0' || innetgr(&buf[2], hname, NULL, ypdomain)) return(-1); } else { if (__icheckhost(raddr, salen, (char *)&buf[1])) return(-1); } break; default: /* if no '+' or '-', do a simple match */ hostok = __icheckhost(raddr, salen, buf); break; } switch(*user) { case '+': if (!*(user+1)) { /* '+' matches all users */ userok = 1; break; } if (*(user+1) == '@') /* match a user by netgroup */ userok = innetgr(user+2, NULL, ruser, ypdomain); else /* match a user by direct specification */ userok = !(strcmp(ruser, user+1)); break; case '-': /* if we matched a hostname, */ if (hostok) { /* check for user field rejections */ if (!*(user+1)) return(-1); if (*(user+1) == '@') { if (innetgr(user+2, NULL, ruser, ypdomain)) return(-1); } else { if (!strcmp(ruser, user+1)) return(-1); } } break; default: /* no rejections: try to match the user */ if (hostok) userok = !(strcmp(ruser,*user ? user : luser)); break; } if (hostok && userok) return(0); } return (-1); }
/* string_match - match string against token */ static int string_match(char *tok,char *s) { int tok_len; int str_len; char *cut; /* * Return YES if a token has the magic value "ALL". Return FAIL if the * token is "FAIL". If the token starts with a "." (domain name), return * YES if it matches the last fields of the string. If the token has the * magic value "LOCAL", return YES if the string does not contain a "." * character. If the token ends on a "." (network number), return YES if * it matches the first fields of the string. If the token begins with a * "@" (netgroup name), return YES if the string is a (host) member of * the netgroup. Return YES if the token fully matches the string. If the * token is a netnumber/netmask pair, return YES if the address is a * member of the specified subnet. */ if (tok[0] == '.') { /* domain: match last fields */ if ((str_len = strlen(s)) > (tok_len = strlen(tok)) && strcasecmp(tok, s + str_len - tok_len) == 0) return (YES); } else if (tok[0] == '@') { /* netgroup: look it up */ #ifdef NETGROUP static char *mydomain = NULL; char *hostname = NULL; BOOL netgroup_ok = False; if (!mydomain) yp_get_default_domain(&mydomain); if (!mydomain) { DEBUG(0,("Unable to get default yp domain.\n")); return NO; } if (!(hostname = strdup(s))) { DEBUG(1,("out of memory for strdup!\n")); return NO; } netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain); DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n", hostname, mydomain, tok+1, BOOLSTR(netgroup_ok))); #ifdef NETGROUP_INSECURE /* if you really want netgroups that match non qualified names then define NETGROUP_INSECURE. It can, however, be a big security hole */ { char *clnt_domain; if (!netgroup_ok && (clnt_domain=strchr(hostname,'.'))) { *clnt_domain++ = '\0'; netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain); } } #endif free(hostname); if (netgroup_ok) return(YES); #else DEBUG(0,("access: netgroup support is not configured\n")); return (NO); #endif } else if (strcasecmp(tok, "ALL") == 0) { /* all: match any */ return (YES); } else if (strcasecmp(tok, "FAIL") == 0) { /* fail: match any */ return (FAIL); } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */ if (strchr(s, '.') == 0 && strcasecmp(s, "unknown") != 0) return (YES); } else if (!strcasecmp(tok, s)) { /* match host name or address */ return (YES); } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */ if (strncmp(tok, s, tok_len) == 0) return (YES); } else if ((cut = strchr(tok, '/')) != 0) { /* netnumber/netmask */ if (isdigit(s[0]) && masked_match(tok, cut, s)) return (YES); } return (NO); }
int fullLock(void) { uid_t uid; int ngroups = NGROUPS; #ifdef SUNOS4 gid_t mygidset[NGROUPS * sizeof (gid_t)]; #else gid_t mygidset[NGROUPS]; #endif int ngrps, i; struct passwd *pwp; struct group *gp; FILE *fp; char buf[BUFSIZ]; #ifndef NO_NEGATIVE_LOGOUT if (logoutButton < 0) return (FULL_LOCK); #endif /* The debug portion may depend on what you are debugging. :) */ if (inwindow || inroot || nolock /*|| debug */ ) return (FULL_LOCK); /* (mostly) harmless user */ uid = getuid(); /* Do not try to logout root! */ if (!uid) return (FULL_LOCK); /* root */ pwp = getpwuid(uid); if ((ngrps = getgroups(ngroups, mygidset)) == -1) perror(ProgramName); #ifdef STAFF_NETGROUP if (innetgr(STAFF_NETGROUP, NULL, pwp->pw_name, NULL)) return (FULL_LOCK); #endif if ((fp = my_fopen(STAFF_FILE, "r")) == NULL) return (TEMP_LOCK); while ((fgets(buf, BUFSIZ, fp)) != NULL) { char *cp; if ((cp = (char *) strchr(buf, '\n')) != NULL) *cp = '\0'; if (!strcmp(buf, pwp->pw_name)) return (FULL_LOCK); if ((gp = getgrnam(buf)) != NULL) { /* check all of user's groups */ #ifdef SUNOS4 for (i = 1; i < ngrps * sizeof (gid_t); i += 2) #else for (i = 0; i < ngrps; ++i) #endif if (gp->gr_gid == mygidset[i]) return (FULL_LOCK); } } (void) fclose(fp); return (TEMP_LOCK); }
/* string_match - match string s against token tok */ static bool string_match(const char *tok,const char *s) { size_t tok_len; size_t str_len; const char *cut; /* Return true if a token has the magic value "ALL". Return * true if the token is "FAIL". If the token starts with a "." * (domain name), return true if it matches the last fields of * the string. If the token has the magic value "LOCAL", * return true if the string does not contain a "." * character. If the token ends on a "." (network number), * return true if it matches the first fields of the * string. If the token begins with a "@" (netgroup name), * return true if the string is a (host) member of the * netgroup. Return true if the token fully matches the * string. If the token is a netnumber/netmask pair, return * true if the address is a member of the specified subnet. */ if (tok[0] == '.') { /* domain: match last fields */ if ((str_len = strlen(s)) > (tok_len = strlen(tok)) && strequal(tok, s + str_len - tok_len)) { return true; } } else if (tok[0] == '@') { /* netgroup: look it up */ #ifdef HAVE_NETGROUP DATA_BLOB tmp; char *mydomain = NULL; char *hostname = NULL; bool netgroup_ok = false; if (memcache_lookup( NULL, SINGLETON_CACHE, data_blob_string_const_null("yp_default_domain"), &tmp)) { SMB_ASSERT(tmp.length > 0); mydomain = (tmp.data[0] == '\0') ? NULL : (char *)tmp.data; } else { yp_get_default_domain(&mydomain); memcache_add( NULL, SINGLETON_CACHE, data_blob_string_const_null("yp_default_domain"), data_blob_string_const_null(mydomain?mydomain:"")); } if (!mydomain) { DEBUG(0,("Unable to get default yp domain. " "Try without it.\n")); } if (!(hostname = SMB_STRDUP(s))) { DEBUG(1,("out of memory for strdup!\n")); return false; } netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain); DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n", hostname, mydomain?mydomain:"(ANY)", tok+1, BOOLSTR(netgroup_ok))); SAFE_FREE(hostname); if (netgroup_ok) return true; #else DEBUG(0,("access: netgroup support is not configured\n")); return false; #endif } else if (strequal(tok, "ALL")) { /* all: match any */ return true; } else if (strequal(tok, "FAIL")) { /* fail: match any */ return true; } else if (strequal(tok, "LOCAL")) { /* local: no dots */ if (strchr_m(s, '.') == 0 && !strequal(s, "unknown")) { return true; } } else if (strequal(tok, s)) { /* match host name or address */ return true; } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */ if (strncmp(tok, s, tok_len) == 0) { return true; } } else if ((cut = strchr_m(tok, '/')) != 0) { /* netnumber/netmask */ if ((isdigit(s[0]) && strchr_m(tok, '.') != NULL) || (tok[0] == '[' && cut > tok && cut[-1] == ']') || ((isxdigit(s[0]) || s[0] == ':') && strchr_m(tok, ':') != NULL)) { /* IPv4/netmask or * [IPv6:addr]/netmask or IPv6:addr/netmask */ return masked_match(tok, cut, s); } } else if (strchr_m(tok, '*') != 0 || strchr_m(tok, '?')) { return unix_wild_match(tok, s); } return false; }
int _validuser(FILE *hostf, char *rhost, char *luser, char *ruser, int baselen) { char *user; char ahost[MAXHOSTNAMELEN]; int hostmatch, usermatch; char *p; if (domain == NULL) { (void) yp_get_default_domain(&domain); } while (fgets(ahost, sizeof (ahost), hostf)) { hostmatch = usermatch = 0; /* bugid fix 1033104 */ p = ahost; while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { *p = isupper(*p) ? tolower(*p) : *p; p++; } if (*p == ' ' || *p == '\t') { *p++ = '\0'; while (*p == ' ' || *p == '\t') p++; user = p; while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') p++; } else user = p; *p = '\0'; if (ahost[0] == '+' && ahost[1] == 0) hostmatch = 1; else if (ahost[0] == '+' && ahost[1] == '@') hostmatch = innetgr(ahost + 2, rhost, NULL, domain); else if (ahost[0] == '-' && ahost[1] == '@') { if (innetgr(ahost + 2, rhost, NULL, domain)) break; } else if (ahost[0] == '-') { if (_checkhost(rhost, ahost+1, baselen)) break; } else hostmatch = _checkhost(rhost, ahost, baselen); if (user[0]) { if (user[0] == '+' && user[1] == 0) usermatch = 1; else if (user[0] == '+' && user[1] == '@') usermatch = innetgr(user+2, NULL, ruser, domain); else if (user[0] == '-' && user[1] == '@') { if (hostmatch && innetgr(user+2, NULL, ruser, domain)) break; } else if (user[0] == '-') { if (hostmatch && !strcmp(user+1, ruser)) break; } else usermatch = !strcmp(user, ruser); } else usermatch = !strcmp(ruser, luser); if (hostmatch && usermatch) return (0); } return (-1); }
static int check_rhosts_file(const char *filename, const char *hostname, const char *ipaddr, const char *client_user, const char *server_user) { FILE *f; char buf[1024]; /* Must not be larger than host, user, dummy below. */ int fd; struct stat st; /* Open the .rhosts file, deny if unreadable */ if ((fd = open(filename, O_RDONLY|O_NONBLOCK)) == -1) return 0; if (fstat(fd, &st) == -1) { close(fd); return 0; } if (!S_ISREG(st.st_mode)) { logit("User %s hosts file %s is not a regular file", server_user, filename); close(fd); return 0; } unset_nonblock(fd); if ((f = fdopen(fd, "r")) == NULL) { close(fd); return 0; } while (fgets(buf, sizeof(buf), f)) { /* All three must be at least as big as buf to avoid overflows. */ char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp; int negated; for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) ; if (*cp == '#' || *cp == '\n' || !*cp) continue; /* * NO_PLUS is supported at least on OSF/1. We skip it (we * don't ever support the plus syntax). */ if (strncmp(cp, "NO_PLUS", 7) == 0) continue; /* * This should be safe because each buffer is as big as the * whole string, and thus cannot be overwritten. */ switch (sscanf(buf, "%1023s %1023s %1023s", hostbuf, userbuf, dummy)) { case 0: auth_debug_add("Found empty line in %.100s.", filename); continue; case 1: /* Host name only. */ strlcpy(userbuf, server_user, sizeof(userbuf)); break; case 2: /* Got both host and user name. */ break; case 3: auth_debug_add("Found garbage in %.100s.", filename); continue; default: /* Weird... */ continue; } host = hostbuf; user = userbuf; negated = 0; /* Process negated host names, or positive netgroups. */ if (host[0] == '-') { negated = 1; host++; } else if (host[0] == '+') host++; if (user[0] == '-') { negated = 1; user++; } else if (user[0] == '+') user++; /* Check for empty host/user names (particularly '+'). */ if (!host[0] || !user[0]) { /* We come here if either was '+' or '-'. */ auth_debug_add("Ignoring wild host/user names in %.100s.", filename); continue; } /* Verify that host name matches. */ if (host[0] == '@') { if (!innetgr(host + 1, hostname, NULL, NULL) && !innetgr(host + 1, ipaddr, NULL, NULL)) continue; } else if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0) continue; /* Different hostname. */ /* Verify that user name matches. */ if (user[0] == '@') { if (!innetgr(user + 1, NULL, client_user, NULL)) continue; } else if (strcmp(user, client_user) != 0) continue; /* Different username. */ /* Found the user and host. */ fclose(f); /* If the entry was negated, deny access. */ if (negated) { auth_debug_add("Matched negative entry in %.100s.", filename); return 0; } /* Accept authentication. */ return 1; } /* Authentication using this file denied. */ fclose(f); return 0; }
int __ivaliduser_sa(FILE *hostf, struct sockaddr *raddr, socklen_t salen, const char *luser, const char *ruser) { char *user, *p; char *buf; const char *auser, *ahost; int hostok, userok; char *rhost = (char *)-1; char domain[MAXHOSTNAMELEN]; size_t buflen; getdomainname(domain, sizeof(domain)); while ((buf = fgetln(hostf, &buflen))) { p = buf; if (*p == '#') continue; while (p < buf + buflen && *p != '\n' && *p != ' ' && *p != '\t') { if (!isprint(*p)) goto bail; *p = isupper(*p) ? tolower(*p) : *p; p++; } if (p >= buf + buflen) continue; if (*p == ' ' || *p == '\t') { *p++ = '\0'; while (p < buf + buflen && (*p == ' ' || *p == '\t')) p++; if (p >= buf + buflen) continue; user = p; while (p < buf + buflen && *p != '\n' && *p != ' ' && *p != '\t') { if (!isprint(*p)) goto bail; p++; } } else user = p; *p = '\0'; if (p == buf) continue; auser = *user ? user : luser; ahost = buf; if (strlen(ahost) >= MAXHOSTNAMELEN) continue; /* * innetgr() must lookup a hostname (we do not attempt * to change the semantics so that netgroups may have * #.#.#.# addresses in the list.) */ if (ahost[0] == '+') switch (ahost[1]) { case '\0': hostok = 1; break; case '@': if (rhost == (char *)-1) rhost = __gethostloop(raddr, salen); hostok = 0; if (rhost) hostok = innetgr(&ahost[2], rhost, NULL, domain); break; default: hostok = __icheckhost(raddr, salen, &ahost[1]); break; } else if (ahost[0] == '-') switch (ahost[1]) { case '\0': hostok = -1; break; case '@': if (rhost == (char *)-1) rhost = __gethostloop(raddr, salen); hostok = 0; if (rhost) hostok = -innetgr(&ahost[2], rhost, NULL, domain); break; default: hostok = -__icheckhost(raddr, salen, &ahost[1]); break; } else hostok = __icheckhost(raddr, salen, ahost); if (auser[0] == '+') switch (auser[1]) { case '\0': userok = 1; break; case '@': userok = innetgr(&auser[2], NULL, ruser, domain); break; default: userok = strcmp(ruser, &auser[1]) ? 0 : 1; break; } else if (auser[0] == '-') switch (auser[1]) { case '\0': userok = -1; break; case '@': userok = -innetgr(&auser[2], NULL, ruser, domain); break; default: userok = strcmp(ruser, &auser[1]) ? 0 : -1; break; } else userok = strcmp(ruser, auser) ? 0 : 1; /* Check if one component did not match */ if (hostok == 0 || userok == 0) continue; /* Check if we got a forbidden pair */ if (userok <= -1 || hostok <= -1) return (-1); /* Check if we got a valid pair */ if (hostok >= 1 && userok >= 1) return (0); } bail: return (-1); }