/* pam.c - pam processing routines Copyright (C) 2009 Howard Chu Copyright (C) 2009-2014 Arthur de Jong This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define _GNU_SOURCE /* for crypt_r(3) in crypt.h */ #include #include "config.h" #include #include #include #ifdef HAVE_STDINT_H #include #endif /* HAVE_STDINT_H */ #include #include #include "common.h" #include "log.h" #include "cfg.h" #include "common/dict.h" #include "common/expr.h" struct authc { int authc_rc; int authz_rc; char authz_msg[BUFLEN_MESSAGE]; }; struct authz { int authz_rc; char authz_msg[BUFLEN_MESSAGE]; }; static int check_password(const char *password, const char *hash) { int ret; struct crypt_data data; data.initialized = 0; ret = (strcmp(crypt_r(password, hash, &data), hash) == 0); memset(&data, 0, sizeof(data)); return ret; } static int check_password_age(struct session *session, const char *username, char *authzmsg, size_t authzmsgsz, bool check_maxdays, bool check_mindays) { /* hackers.git doesn't use aging features */ return NSLCD_PAM_SUCCESS; } /* check authentication credentials of the user */ NSLCD_HANDLE_UID(PAM, AUTHC ,/* decls */ char username[BUFLEN_NAME]; char service[BUFLEN_NAME]; char ruser[BUFLEN_NAME]; char rhost[HOST_NAME_MAX+1]; char tty[64]; char password[BUFLEN_PASSWORD]; struct authc _entry; ,/* int read(TFILE *fp) */ READ_STRING(fp, username); READ_STRING(fp, service); READ_STRING(fp, ruser); READ_STRING(fp, rhost); READ_STRING(fp, tty); READ_STRING(fp, password); log_setrequest("authc=\"%s\"", username); log_log(LOG_DEBUG, "nslcd_pam_authc(\"%s\",\"%s\",\"%s\")", username, service, *password ? "***" : ""); return 0; ,/* check */ if (!isvalidname(username)) { log_log(LOG_WARNING, "request denied by validnames option"); return -1; } ,/* search(int *rcp, bool *more) */ struct authc, struct passwd *user = NULL; struct authc *entry = &_entry; *more = false; for (size_t i = 0; i < session->cnt; i++) { if (session->users[i].pw_uid != UID_INVALID && STR_CMP(username, session->users[i].pw_name)==0) { *rcp = 0; user = &(session->users[i]); } } if (user == NULL) return NULL; entry->authz_msg[0] = '\0'; /* try authentication */ entry->authc_rc = check_password(password, NULL /* TODO */) ? NSLCD_PAM_SUCCESS : NSLCD_PAM_AUTH_ERR; entry->authz_rc = entry->authc_rc; if (entry->authz_rc == NSLCD_PAM_SUCCESS) { /* perform shadow attribute checks */ entry->authz_rc = check_password_age(session, username, entry->authz_msg, sizeof(entry->authz_msg), true, false); } return entry; ,/* write(TFILE *fp, tentry *entry) */ WRITE_INT32(fp, NSLCD_RESULT_BEGIN); WRITE_INT32( fp, entry->authc_rc); WRITE_STRING(fp, username); WRITE_INT32( fp, entry->authz_rc); WRITE_STRING(fp, entry->authz_msg); return 0; ,/* cleanup */ memset(password, 0, sizeof(password)); ) /* check authorisation of the user */ NSLCD_HANDLE(PAM, AUTHZ ,/* decls */ char username[BUFLEN_NAME]; char service[BUFLEN_NAME]; char ruser[BUFLEN_NAME]; char rhost[HOST_NAME_MAX+1]; char tty[64]; struct authz _entry; ,/* int read(TFILE *fp) */ READ_STRING(fp, username); READ_STRING(fp, service); READ_STRING(fp, ruser); READ_STRING(fp, rhost); READ_STRING(fp, tty); return 0; /* log call */ log_setrequest("authz=\"%s\"", username); log_log(LOG_DEBUG, "nslcd_pam_authz(\"%s\",\"%s\",\"%s\",\"%s\",\"%s\")", username, service, ruser, rhost, tty); ,/* check */ ,/* search(int *rcp, bool *more) */ struct authz, struct passwd *user = NULL; struct authz *entry = &_entry; *more = false; for (size_t i = 0; i < session->cnt; i++) { if (session->users[i].pw_uid != UID_INVALID && STR_CMP(username, session->users[i].pw_name)==0) { *rcp = 0; user = &(session->users[i]); } } if (user == NULL) return NULL; /* Parabola doesn't have any weird reasons for authorization to suddenly fail */ if (0) { entry->authz_rc = NSLCD_PAM_PERM_DENIED; strcpy(entry->authz_msg, "hackers.git authorization check failed"); } else { /* perform shadow attribute checks */ entry->authz_rc = check_password_age(session, username, entry->authz_msg, sizeof(entry->authz_msg), false, false); } return entry; ,/* write(TFILE *fp, tentry *entry) */ WRITE_INT32(fp, NSLCD_RESULT_BEGIN); WRITE_INT32( fp, entry->authz_rc); WRITE_STRING(fp, entry->authz_msg); return 0; ,/* cleanup */ ) NSLCD_HANDLE(PAM, SESS_O ,/* decls */ char username[BUFLEN_NAME]; char service[BUFLEN_NAME]; char ruser[BUFLEN_NAME]; char rhost[HOST_NAME_MAX+1]; char tty[64]; char sessionid[25]; static const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "01234567890"; size_t i; ,/* int read(TFILE *fp) */ READ_STRING(fp, username); READ_STRING(fp, service); READ_STRING(fp, ruser); READ_STRING(fp, rhost); READ_STRING(fp, tty); return 0; /* generate pseudo-random session id */ for (i = 0; i < (sizeof(sessionid) - 1); i++) sessionid[i] = alphabet[rand() % (sizeof(alphabet) - 1)]; sessionid[i] = '\0'; /* log call */ log_setrequest("sess_o=\"%s\"", username); log_log(LOG_DEBUG, "nslcd_pam_sess_o(\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"): %s", username, service, tty, rhost, ruser, sessionid); ,/* check */ ,/* search(int *rcp, bool *more) */ void, *more = false; return (void*)1; /* return non-NULL */ ,/* write(TFILE *fp, tentry *entry) */ WRITE_INT32(fp, NSLCD_RESULT_BEGIN); WRITE_STRING(fp, sessionid); return 0; ,/* cleanup */ ) NSLCD_HANDLE(PAM, SESS_C ,/* decls */ char username[BUFLEN_NAME]; char service[BUFLEN_NAME]; char ruser[BUFLEN_NAME]; char rhost[HOST_NAME_MAX+1]; char tty[64]; char sessionid[64]; ,/* int read(TFILE *fp) */ READ_STRING(fp, username); READ_STRING(fp, service); READ_STRING(fp, ruser); READ_STRING(fp, rhost); READ_STRING(fp, tty); READ_STRING(fp, sessionid); log_setrequest("sess_c=\"%s\"", username); log_log(LOG_DEBUG, "nslcd_pam_sess_c(\"%s\",\"%s\",%s)", username, service, sessionid); return 0; ,/* check */ ,/* tentry *search(struct session *session, int *rcp, bool *more) */ void, *more = false; return (void*)1; /* return non-NULL */ ,/* int write(TFILE *fp, tentry *entry) */ WRITE_INT32(fp, NSLCD_RESULT_BEGIN); return 0; ,/* cleanup */ )