/* ** Copyright 2001-2003 University of Illinois Board of Trustees ** Copyright 2001-2003 Mark D. Roth ** All rights reserved. ** ** pam_pseudo.c - PAM module for pseudo-user authentication ** ** Mark D. Roth ** Campus Information Technologies and Educational Services ** University of Illinois at Urbana-Champaign */ #include #include #include #include #ifdef STDC_HEADERS # include # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_CRYPT_H # include #endif #ifdef HAVE_SHADOW_H # include #endif #include #include #include #define PAM_PSEUDO_DEFAULT_MAPFILE "/etc/pam_pseudo.map" #define PAM_PSEUDO_BUFSIZE 1024 #ifndef LOG_AUTHPRIV # define LOG_AUTHPRIV LOG_AUTH #endif /* ** pseudo_map_lookup() - look up key in PAM_PSEUDO_MAPFILE ** returns: ** 0 access granted ** 1 access denied ** -1 pseudo-user not found or file does not exist */ static int pseudo_map_lookup(char *mapfile, char *puser, char *ruser) { FILE *fp; char buf[PAM_PSEUDO_BUFSIZE]; char *keyp, *valp; char *cp; int retval = 1; if (mapfile == NULL) mapfile = PAM_PSEUDO_DEFAULT_MAPFILE; fp = fopen(mapfile, "r"); if (fp == NULL) return -1; while (fgets(buf, sizeof(buf), fp) != NULL) { /* strip newline */ buf[strlen(buf) - 1] = '\0'; /* strip comments */ if ((cp = strchr(buf, '#')) != NULL && (cp == buf || *(cp - 1) != '\\')) *cp = '\0'; /* strip leading whitespace */ keyp = buf + strspn(buf, " \t"); /* skip blank lines */ if (*keyp == '\0') continue; /* seperate the key and value */ valp = NULL; if ((cp = strchr(keyp, ':')) != NULL) { *cp = '\0'; valp = cp + 1; } /* strip trailing whitespace in key (if any) */ if ((cp = strpbrk(keyp, " \t")) != NULL) *cp = '\0'; /* if it's not a match or there's no value, continue */ if (strcmp(keyp, puser) != 0 || valp == NULL) continue; while ((cp = strsep(&valp, " \t")) != NULL) { if (*cp == '\0') continue; if (strcmp(cp, ruser) == 0) return 0; } return 1; } fclose(fp); return -1; } /* macros for handling users which aren't listed in PAM_PSEUDO_MAPFILE */ #define MAP_UNKNOWN_FAIL 1 #define MAP_UNKNOWN_SUCCEED 2 #define MAP_UNKNOWN_IGNORE 3 int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char *argv[]) { char *user, *ruser, *pass, *mapfile = NULL; struct pam_message prompt = { PAM_PROMPT_ECHO_OFF, NULL }; struct pam_message *msg[1] = { &prompt }; struct pam_conv *conv; char buf[PAM_PSEUDO_BUFSIZE]; struct pam_response *response = NULL; int i, map_flags = 0; struct passwd *pwd; #ifdef HAVE_GETSPNAM struct spwd *spwd; #endif #ifdef DEBUG printf("==> pam_pseudo_authenticate(pamh=0x%lx, flags=%d)\n", pamh, flags); #endif for (i = 0; i < argc; i++) { #ifdef DEBUG printf(" pam_pseudo_authenticate(): argv[%d] = \"%s\"\n", i, argv[i]); #endif if (strncmp(argv[i], "unknown_user=", 13) == 0) { if (strcmp(argv[i] + 13, "fail") == 0) map_flags = MAP_UNKNOWN_FAIL; else if (strcmp(argv[i] + 13, "succeed") == 0) map_flags = MAP_UNKNOWN_SUCCEED; else if (strcmp(argv[i] + 13, "ignore") == 0) map_flags = MAP_UNKNOWN_IGNORE; else syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_authenticate: unknown " "argument \"%s\"", argv[i]); continue; } if (strncmp(argv[i], "mapfile=", 8) == 0) { mapfile = (char *)argv[i] + 8; continue; } syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_authenticate: unknown " "argument \"%s\"", argv[i]); } if (pam_get_user(pamh, (char **)&user, "login: ") != PAM_SUCCESS) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_authenticate: pam_get_user failed"); return PAM_USER_UNKNOWN; } /* ** first check the PAM_RUSER item, then fall back to the real uid */ if (pam_get_item(pamh, PAM_RUSER, (void **)&ruser) == PAM_SUCCESS && ruser != NULL) { pwd = getpwnam(ruser); if (pwd == NULL) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_authenticate: getpwnam(): %m"); return PAM_AUTHINFO_UNAVAIL; } } else { pwd = getpwuid(getuid()); if (pwd == NULL) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_authenticate: getpwuid(): %m"); return PAM_AUTHINFO_UNAVAIL; } ruser = pwd->pw_name; } #ifdef DEBUG printf("user=\"%s\"\n", user); printf("ruser=\"%s\"\n", ruser); #endif switch (pseudo_map_lookup(mapfile, user, ruser)) { case -1: syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_authenticate: pseudo-user \"%s\" not found", user); if (map_flags == MAP_UNKNOWN_FAIL) return PAM_USER_UNKNOWN; else if (map_flags == MAP_UNKNOWN_SUCCEED) return PAM_SUCCESS; else if (map_flags == MAP_UNKNOWN_IGNORE) return PAM_IGNORE; /* FALLTHROUGH */ case 1: syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_authenticate: user \"%s\" not authorized " "to access pseudo-user \"%s\"", ruser, user); return PAM_AUTH_ERR; case 0: break; } snprintf(buf, sizeof(buf), "%s's Password: ", ruser); prompt.msg = buf; if (pam_get_item(pamh, PAM_CONV, (void **)&conv) != PAM_SUCCESS || conv->conv(1, (struct pam_message **)msg, &response, conv->appdata_ptr) != PAM_SUCCESS || response == NULL || response[0].resp == NULL) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_authenticate: cannot get user response"); return PAM_AUTHINFO_UNAVAIL; } strlcpy(buf, response[0].resp, sizeof(buf)); free(response[0].resp); #ifdef HAVE_GETSPNAM spwd = getspnam(ruser); if (spwd == NULL) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_authenticate: getspnam(\"%s\"): %m", ruser); return PAM_AUTHINFO_UNAVAIL; } pass = spwd->sp_pwdp; #else /* ! HAVE_GETSPNAM */ pass = pwd->pw_passwd; #endif /* HAVE_GETSPNAM */ if (strcmp(pass, crypt(buf, pass)) != 0) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_authenticate: invalid password"); return PAM_AUTH_ERR; } #ifdef DEBUG printf("<== pam_pseudo_authenticate(): success\n"); #endif return PAM_SUCCESS; } int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char *argv[]) { #ifdef DEBUG syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_setcred: not implemented"); #endif return PAM_SUCCESS; } int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char *argv[]) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_acct_mgmt: not implemented"); return PAM_IGNORE; } int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char *argv[]) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_open_session: not implemented"); return PAM_IGNORE; } int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char *argv[]) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_close_session: not implemented"); return PAM_IGNORE; } int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char *argv[]) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_pseudo_chauthtok: not implemented"); return PAM_IGNORE; }