/* * Copyright (c) 2007, OpenFWTK Development Group * All rights reserved. See LICENSE. */ /* ** Copyright 2000-2003 University of Illinois Board of Trustees ** Copyright 2000-2003 Mark D. Roth ** All rights reserved. ** ** pam_authsrv.c - PAM module for TIS authsrv authentication ** ** Mark D. Roth ** Campus Information Technologies and Educational Services ** University of Illinois at Urbana-Champaign */ #include #include #include #include #include #include #include #include #include #include "firewall.h" #include "firewall2.h" #include "fwfunc.h" #include "auth.h" extern char* ip2name(struct in_addr); #define PAM_AUTHSRV_MAPFILE "/etc/pam_tis.map" #define PAM_AUTHSRV_BUFSIZE 1024 #ifndef LOG_AUTHPRIV # define LOG_AUTHPRIV LOG_AUTH #endif /* ** tis_map_lookup() - look up key in PAM_AUTHSRV_MAPFILE ** ** If key is found and value is present, store value in val and return 0. ** If key is found without a value, copy key to val and return 0. ** If key is not found or mapfile cannot be read, copy key to val and return 1. */ static int tis_map_lookup(char *key, char *val, size_t valuelen) { FILE *fp; char buf[PAM_AUTHSRV_BUFSIZE]; char *keyp, *valp; char *cp; int retval = 1; fp = fopen(PAM_AUTHSRV_MAPFILE, "r"); while (fp != NULL && 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, continue */ if (strcmp(keyp, key) != 0) continue; /* strip whitespace in value */ if (valp != NULL) { valp += strspn(valp, " \t"); if ((cp = strpbrk(valp, " \t")) != NULL) *cp = '\0'; } /* if no value is present, return key */ if (valp == NULL || *valp == '\0') { retval = 0; break; } /* return value */ strlcpy(val, valp, valuelen); fclose(fp); return 0; } if (fp != NULL) fclose(fp); strlcpy(val, key, valuelen); return retval; } /* macros for handling users which aren't listed in PAM_AUTHSRV_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, *service, *rladdr, *riaddr; char authuser[PAM_AUTHSRV_BUFSIZE]; struct pam_message prompt = { PAM_PROMPT_ECHO_ON, NULL }; struct pam_message *msg[1]; struct pam_conv *conv; Cfg *confp; char buf[PAM_AUTHSRV_BUFSIZE]; struct pam_response *response = NULL; int i, map_flags = 0; struct in_addr addr; #ifdef DEBUG printf("==> pam_sm_authenticate(pamh=0x%lx, flags=%d): " "argument vector:", pamh, flags); #endif for (i = 0; i < argc; i++) { #ifdef DEBUG printf(" pam_sm_authenticate(): argv[%d] = \"%s\"", i, argv[i]); #endif if (strcmp(argv[i], "unknown_user=fail") == 0) map_flags = MAP_UNKNOWN_FAIL; else if (strcmp(argv[i], "unknown_user=succeed") == 0) map_flags = MAP_UNKNOWN_SUCCEED; else if (strcmp(argv[i], "unknown_user=ignore") == 0) map_flags = MAP_UNKNOWN_IGNORE; else syslog(LOG_AUTHPRIV | LOG_ERR, "pam_authsrv_authenticate: unknown " "argument \"%s\"", argv[i]); } if (pam_get_user(pamh, (const char **)&user, "login: ") != PAM_SUCCESS) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_authsrv_authenticate: pam_get_user failed"); return PAM_USER_UNKNOWN; } if (tis_map_lookup(user, authuser, sizeof(authuser)) != 0) { 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; } if (pam_get_item(pamh, PAM_SERVICE, (const void **)&service) != PAM_SUCCESS) service = "unknown"; /* * We do not trust application's name resolution just because even if it * behaves properly, it is not possible to know which ip of hostname * having multiple addresses is our originator. So we suggest turning dns * resolution off in PAM client application, so we can deal with IP address. */ if ((pam_get_item(pamh, PAM_RHOST, (const void **)&riaddr) == PAM_SUCCESS) && ((addr.s_addr = inet_addr(riaddr)) != INADDR_NONE)) { rladdr = ip2name(addr); } else rladdr = riaddr = NULL; #ifdef DEBUG printf("user = \"%s\", authuser = \"%s\", service = \"%s\"\n", user, authuser, service); #endif confp = cfg_read(service); if (confp == NULL || confp == (Cfg *)(-1)) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_authsrv_authenticate: cannot read " "netperm-table file"); return PAM_AUTHINFO_UNAVAIL; } if (auth_open(confp) != 0 || auth_recv(buf, sizeof(buf)) != 0 || strncmp(buf, "Authsrv ready", 13) != 0) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_authsrv_authenticate: auth_open failed"); cfg_free(confp); return PAM_AUTHINFO_UNAVAIL; } cfg_free(confp); if (riaddr) snprintf(buf, sizeof(buf), "authenticate %.64s '%.64s %.512s/%.64s'", authuser, service, rladdr, riaddr); else snprintf(buf, sizeof(buf), "authenticate %.64s '%.64s'", authuser, service); if (auth_send(buf) != 0 || auth_recv(buf, sizeof(buf)) != 0) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_authsrv_authenticate: authentication " "request failed"); auth_close(); return PAM_AUTHINFO_UNAVAIL; } if (strncmp(buf, "challenge ", 10) == 0) prompt.msg = buf + 10; else if (strncmp(buf, "chalnecho ", 10) == 0) { prompt.msg = buf + 10; prompt.msg_style = PAM_PROMPT_ECHO_OFF; } else if (strcmp(buf, "password") == 0) prompt.msg = "Password: "; else { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_authsrv_authenticate: server reply: %s", buf); auth_close(); return PAM_USER_UNKNOWN; } msg[0] = &prompt; if (pam_get_item(pamh, PAM_CONV, (const void **)&conv) != PAM_SUCCESS || conv->conv(1, (const struct pam_message **)msg, &response, conv->appdata_ptr) != PAM_SUCCESS || response == NULL || response[0].resp == NULL) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_authsrv_authenticate: cannot get user response"); auth_close(); return PAM_AUTHINFO_UNAVAIL; } snprintf(buf, sizeof(buf), "response '%s'", response[0].resp); free(response[0].resp); if (auth_send(buf) != 0 || auth_recv(buf, sizeof(buf)) != 0) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_authsrv_authenticate: cannot send user response"); auth_close(); return PAM_AUTHINFO_UNAVAIL; } if (strncmp(buf, "ok", 2) != 0) { syslog(LOG_AUTHPRIV | LOG_ERR, "pam_authsrv_authenticate: authentication rejected by server"); auth_close(); return PAM_AUTH_ERR; } auth_close(); 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_authsrv_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_authsrv_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_authsrv_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_authsrv_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_authsrv_chauthtok: not implemented"); return PAM_IGNORE; }