1/* MODULE: auth_pam */ 2 3/* COPYRIGHT 4 * Copyright (c) 2000 Fabian Knittel. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain any existing copyright 11 * notice, and this entire permission notice in its entirety, 12 * including the disclaimer of warranties. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * 2. Redistributions in binary form must reproduce all prior and current 20 * copyright notices, this list of conditions, and the following 21 * disclaimer in the documentation and/or other materials provided 22 * with the distribution. 23 * 24 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 30 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 33 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 34 * DAMAGE. 35 * END COPYRIGHT */ 36 37/* 38 * Pluggable Authentication Modules, PAM(8), based authentication module 39 * for saslauthd. 40 * 41 * Written by Fabian Knittel <fknittel@gmx.de>. Original implementation 42 * Debian's pwcheck_pam daemon by Michael-John Turner <mj@debian.org>. 43 */ 44 45/* PUBLIC DEPENDENCIES */ 46#include "mechanisms.h" 47#include <stdio.h> 48 49#ifdef HAVE_CONFIG_H 50#include <config.h> 51#endif 52 53#ifdef AUTH_PAM 54 55# include <string.h> 56# include <syslog.h> 57#ifdef HAVE_SECURITY_PAM_APPL_H 58# include <security/pam_appl.h> 59#elif defined(HAVE_PAM_PAM_APPL_H) 60# include <pam/pam_appl.h> 61#endif 62 63# include "auth_pam.h" 64/* END PUBLIC DEPENDENCIES */ 65 66 67/* Structure for application specific data passed through PAM 68 * to our conv call-back routine saslauthd_pam_conv. */ 69typedef struct { 70 const char *login; /* plaintext authenticator */ 71 const char *password; /* plaintext password */ 72 pam_handle_t *pamh; /* pointer to PAM handle */ 73} pam_appdata; 74 75# define RETURN(x) return strdup(x) 76 77 78/* FUNCTION: saslauthd_pam_conv */ 79 80/* SYNOPSIS 81 * Call-back function used by the PAM library to communicate with us. Each 82 * received message expects a response, pointed to by resp. 83 * END SYNOPSIS */ 84 85static int /* R: PAM return code */ 86saslauthd_pam_conv ( 87 /* PARAMETERS */ 88 int num_msg, /* I: number of messages */ 89 const struct pam_message **msg, /* I: pointer to array of messages */ 90 struct pam_response **resp, /* O: pointer to pointer of response */ 91 void *appdata_ptr /* I: pointer to app specific data */ 92 /* END PARAMETERS */ 93 ) 94{ 95 /* VARIABLES */ 96 pam_appdata *my_appdata; /* application specific data */ 97 struct pam_response *my_resp; /* response created by this func */ 98 int i; /* loop counter */ 99 const char *login_prompt; /* string prompting for user-name */ 100 int rc; /* return code holder */ 101 /* END VARIABLES */ 102 103 my_appdata = appdata_ptr; 104 105 my_resp = malloc(sizeof(struct pam_response) * num_msg); 106 if (my_resp == NULL) 107 return PAM_CONV_ERR; 108 109 for (i = 0; i < num_msg; i++) 110 switch (msg[i]->msg_style) { 111 /* 112 * We assume PAM_PROMPT_ECHO_OFF to be a request for password. 113 * This assumption might be unsafe. 114 * 115 * For PAM_PROMPT_ECHO_ON we first check whether the provided 116 * request string matches PAM_USER_PROMPT and, only if they do 117 * match, assume it to be a request for the login. 118 */ 119 case PAM_PROMPT_ECHO_OFF: /* password */ 120 my_resp[i].resp = strdup(my_appdata->password); 121 if (my_resp[i].resp == NULL) { 122 syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: strdup failed"); 123 goto ret_error; 124 } 125 my_resp[i].resp_retcode = PAM_SUCCESS; 126 break; 127 128 case PAM_PROMPT_ECHO_ON: /* username? */ 129 /* Recheck setting each time, as it might have been changed 130 in the mean-while. */ 131 rc = pam_get_item(my_appdata->pamh, PAM_USER_PROMPT, 132 (void *) &login_prompt); 133 if (rc != PAM_SUCCESS) { 134 syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: unable to read " 135 "login prompt string: %s", 136 pam_strerror(my_appdata->pamh, rc)); 137 goto ret_error; 138 } 139 140 if (strcmp(msg[i]->msg, login_prompt) == 0) { 141 my_resp[i].resp = strdup(my_appdata->login); 142 my_resp[i].resp_retcode = PAM_SUCCESS; 143 } else { /* ignore */ 144 syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: unknown prompt " 145 "string: %s", msg[i]->msg); 146 my_resp[i].resp = NULL; 147 my_resp[i].resp_retcode = PAM_SUCCESS; 148 } 149 break; 150 151 case PAM_ERROR_MSG: /* ignore */ 152 case PAM_TEXT_INFO: /* ignore */ 153 my_resp[i].resp = NULL; 154 my_resp[i].resp_retcode = PAM_SUCCESS; 155 break; 156 157 default: /* error */ 158 goto ret_error; 159 } 160 *resp = my_resp; 161 return PAM_SUCCESS; 162 163ret_error: 164 /* 165 * Free response structure. Don't free my_resp[i], as that 166 * isn't initialised yet. 167 */ 168 { 169 int y; 170 171 for (y = 0; y < i; y++) 172 if (my_resp[y].resp != NULL) 173 free(my_resp[y].resp); 174 free(my_resp); 175 } 176 return PAM_CONV_ERR; 177} 178 179/* END FUNCTION: saslauthd_pam_conv */ 180 181/* FUNCTION: auth_pam */ 182 183char * /* R: allocated response string */ 184auth_pam ( 185 /* PARAMETERS */ 186 const char *login, /* I: plaintext authenticator */ 187 const char *password, /* I: plaintext password */ 188 const char *service, /* I: service name */ 189 const char *realm __attribute__((unused)) 190 /* END PARAMETERS */ 191 ) 192{ 193 /* VARIABLES */ 194 pam_appdata my_appdata; /* application specific data */ 195 struct pam_conv my_conv; /* pam conversion data */ 196 pam_handle_t *pamh; /* pointer to PAM handle */ 197 int rc; /* return code holder */ 198 /* END VARIABLES */ 199 200 my_appdata.login = login; 201 my_appdata.password = password; 202 my_appdata.pamh = NULL; 203 204 my_conv.conv = saslauthd_pam_conv; 205 my_conv.appdata_ptr = &my_appdata; 206 207 rc = pam_start(service, login, &my_conv, &pamh); 208 if (rc != PAM_SUCCESS) { 209 syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_start failed: %s", 210 pam_strerror(pamh, rc)); 211 RETURN("NO PAM start error"); 212 } 213 214 my_appdata.pamh = pamh; 215 216 rc = pam_authenticate(pamh, PAM_SILENT); 217 if (rc != PAM_SUCCESS) { 218 syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_authenticate failed: %s", 219 pam_strerror(pamh, rc)); 220 pam_end(pamh, rc); 221 RETURN("NO PAM auth error"); 222 } 223 224 rc = pam_acct_mgmt(pamh, PAM_SILENT); 225 if (rc != PAM_SUCCESS) { 226 syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_acct_mgmt failed: %s", 227 pam_strerror(pamh, rc)); 228 pam_end(pamh, rc); 229 RETURN("NO PAM acct error"); 230 } 231 232 pam_end(pamh, PAM_SUCCESS); 233 RETURN("OK"); 234} 235 236/* END FUNCTION: auth_pam */ 237 238#else /* !AUTH_PAM */ 239 240char * 241auth_pam( 242 const char *login __attribute__((unused)), 243 const char *password __attribute__((unused)), 244 const char *service __attribute__((unused)), 245 const char *realm __attribute__((unused)) 246 ) 247{ 248 return NULL; 249} 250 251#endif /* !AUTH_PAM */ 252 253/* END MODULE: auth_pam */ 254