/* ======================================================================= * Copyright 1996, Jan D. Wolter and Steven R. Weiss, All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The names of the authors must not be used to endorse or * promote products derived from this software without prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ======================================================================= */ #include "pwauth.h" #if defined(PAM_SOLARIS_26) || defined(PAM_SOLARIS) || defined(PAM_OS_X) #define PAM #endif /* PAM_SOLARIS_26 or PAM_SOLARIS */ #ifdef PAM #ifdef NEED_UID #include #endif #ifdef PAM_OLD_OS_X #include #else #include #endif #endif #ifdef PAM /* ========================= PAM Authentication ======================== */ /* Based on version by Karyl Stein (xenon313@arbornet.org) */ /* and on parts of mod_auth_pam.c by Ingo Lutkebohnle */ /* Application data structure passed to PAM_conv: */ struct ad_user { char *login; char *passwd; }; /* The pam_unix.so library in Solaris 2.6 fails to pass along appdata_ptr * when it calls the conversation function. So we use a global variable. */ #ifdef PAM_SOLARIS_26 struct ad_user user_info; #define PAM_SOLARIS #endif /* PAM_SOLARIS_26 */ /* PAM_CONF - PAM Conversation Function. Called by PAM to get login/password. * Note that "appdata_ptr" is really a "struct ad_user *" structure. */ #ifdef PAM_SOLARIS /* In Solaris PAM, msg is a pointer to a pointer to a size num_msg array of * pam_message structures. */ # define msgi(i) ((*msg)[i]) #else /* In Linux PAM and OpenPAM, msg is a pointer to a size num_msg array of * pointers to pam_message structures. */ # define msgi(i) (*(msg[i])) #endif #ifdef PAM_SOLARIS_26 int PAM_conv (int num_msg, struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { struct ad_user *user= &user_info; #else int PAM_conv (int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { struct ad_user *user= (struct ad_user *)appdata_ptr; #endif /* PAM_SOLARIS_26 */ struct pam_response *response; int i; /* Sanity checking */ if (msg == NULL || resp == NULL || user == NULL) return PAM_CONV_ERR; #ifdef PAM_SOLARIS if (*msg == NULL) return PAM_CONV_ERR; #endif response= (struct pam_response *) malloc(num_msg * sizeof(struct pam_response)); for (i= 0; i < num_msg; i++) { response[i].resp_retcode= 0; response[i].resp= NULL; switch (msgi(i).msg_style) { case PAM_PROMPT_ECHO_ON: /* Store the login as the response */ /* This likely never gets called, since login was on pam_start() */ response[i].resp= appdata_ptr ? (char *)strdup(user->login) : NULL; break; case PAM_PROMPT_ECHO_OFF: /* Store the password as the response */ response[i].resp= appdata_ptr ? (char *)strdup(user->passwd) : NULL; break; case PAM_TEXT_INFO: case PAM_ERROR_MSG: /* Shouldn't happen since we have PAM_SILENT set. If it happens * anyway, ignore it. */ break; default: /* Something strange... */ if (response != NULL) free(response); return PAM_CONV_ERR; } } /* On success, return the response structure */ *resp= response; return PAM_SUCCESS; } /* CHECK_AUTH - Check a login and return a status code. * (This version for systems using PAM.) */ int check_auth(char *login, char *passwd) { #ifndef PAM_SOLARIS_26 struct ad_user user_info= {login, passwd}; #endif /* PAM_SOLARIS_26 */ struct pam_conv conv= { PAM_conv, (void *)&user_info }; pam_handle_t *pamh= NULL; int retval; #ifdef NEED_UID struct passwd *pwd; if ((pwd= getpwnam(login)) == NULL) return STATUS_UNKNOWN; hisuid= pwd->pw_uid; haveuid= 1; #endif #ifdef MIN_UNIX_UID if (hisuid < MIN_UNIX_UID) return STATUS_BLOCKED; #endif #ifdef PAM_SOLARIS_26 user_info.login= login; user_info.passwd= passwd; #endif /* PAM_SOLARIS_26 */ retval= pam_start("pwauth", login, &conv, &pamh); if (retval == PAM_SUCCESS) retval= pam_authenticate(pamh, PAM_SILENT); if (retval == PAM_SUCCESS) retval= pam_acct_mgmt(pamh, 0); /* permitted access? */ if (pam_end(pamh,retval) != PAM_SUCCESS) /* close PAM */ { pamh= NULL; return STATUS_INT_ERR; } /* On failure we always return STATUS_UNKNOWN although we can't tell * if the failure was because of a bad login or a bad password */ return (retval == PAM_SUCCESS ? STATUS_OK : STATUS_UNKNOWN); } #endif /* PAM */