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 # include <security/pam_appl.h>
58 # include "auth_pam.h"
59 /* END PUBLIC DEPENDENCIES */
60 
61 
62 /* Structure for application specific data passed through PAM
63  * to our conv call-back routine saslauthd_pam_conv. */
64 typedef struct {
65     const char *login;			/* plaintext authenticator */
66     const char *password;		/* plaintext password */
67     pam_handle_t *pamh;			/* pointer to PAM handle */
68 } pam_appdata;
69 
70 # define RETURN(x) return strdup(x)
71 
72 
73 /* FUNCTION: saslauthd_pam_conv */
74 
75 /* SYNOPSIS
76  * Call-back function used by the PAM library to communicate with us. Each
77  * received message expects a response, pointed to by resp.
78  * END SYNOPSIS */
79 
80 static int				/* R: PAM return code */
saslauthd_pam_conv(int num_msg,const struct pam_message ** msg,struct pam_response ** resp,void * appdata_ptr)81 saslauthd_pam_conv (
82   /* PARAMETERS */
83   int num_msg,				/* I: number of messages */
84   const struct pam_message **msg,	/* I: pointer to array of messages */
85   struct pam_response **resp,		/* O: pointer to pointer of response */
86   void *appdata_ptr			/* I: pointer to app specific data */
87   /* END PARAMETERS */
88   )
89 {
90     /* VARIABLES */
91     pam_appdata *my_appdata;		/* application specific data */
92     struct pam_response *my_resp;	/* response created by this func */
93     int i;				/* loop counter */
94     const char *login_prompt;		/* string prompting for user-name */
95     int rc;				/* return code holder */
96     /* END VARIABLES */
97 
98     my_appdata = appdata_ptr;
99 
100     my_resp = malloc(sizeof(struct pam_response) * num_msg);
101     if (my_resp == NULL)
102 	return PAM_CONV_ERR;
103 
104     for (i = 0; i < num_msg; i++)
105 	switch (msg[i]->msg_style) {
106 	/*
107 	 * We assume PAM_PROMPT_ECHO_OFF to be a request for password.
108 	 * This assumption might be unsafe.
109 	 *
110 	 * For PAM_PROMPT_ECHO_ON we first check whether the provided
111 	 * request string matches PAM_USER_PROMPT and, only if they do
112 	 * match, assume it to be a request for the login.
113 	 */
114 	case PAM_PROMPT_ECHO_OFF:	/* password */
115 	    my_resp[i].resp = strdup(my_appdata->password);
116 	    if (my_resp[i].resp == NULL) {
117 		syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: strdup failed");
118 		goto ret_error;
119 	    }
120 	    my_resp[i].resp_retcode = PAM_SUCCESS;
121 	    break;
122 
123 	case PAM_PROMPT_ECHO_ON:	/* username? */
124 	    /* Recheck setting each time, as it might have been changed
125 	       in the mean-while. */
126 	    rc = pam_get_item(my_appdata->pamh, PAM_USER_PROMPT,
127 			      (void *) &login_prompt);
128 	    if (rc != PAM_SUCCESS) {
129 		syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: unable to read "
130 		       "login prompt string: %s",
131 		       pam_strerror(my_appdata->pamh, rc));
132 		goto ret_error;
133 	    }
134 
135 	    if (strcmp(msg[i]->msg, login_prompt) == 0) {
136 		my_resp[i].resp = strdup(my_appdata->login);
137 		my_resp[i].resp_retcode = PAM_SUCCESS;
138 	    } else {			/* ignore */
139 		syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: unknown prompt "
140 		       "string: %s", msg[i]->msg);
141 		my_resp[i].resp = NULL;
142 		my_resp[i].resp_retcode = PAM_SUCCESS;
143 	    }
144 	    break;
145 
146 	case PAM_ERROR_MSG:		/* ignore */
147 	case PAM_TEXT_INFO:		/* ignore */
148 	    my_resp[i].resp = NULL;
149 	    my_resp[i].resp_retcode = PAM_SUCCESS;
150 	    break;
151 
152 	default:			/* error */
153 	    goto ret_error;
154 	}
155     *resp = my_resp;
156     return PAM_SUCCESS;
157 
158 ret_error:
159     /*
160      * Free response structure. Don't free my_resp[i], as that
161      * isn't initialised yet.
162      */
163     {
164 	int y;
165 
166 	for (y = 0; y < i; y++)
167 	    if (my_resp[y].resp != NULL)
168 		free(my_resp[y].resp);
169 	free(my_resp);
170     }
171     return PAM_CONV_ERR;
172 }
173 
174 /* END FUNCTION: saslauthd_pam_conv */
175 
176 /* FUNCTION: auth_pam */
177 
178 char *					/* R: allocated response string */
auth_pam(const char * login,const char * password,const char * service,const char * realm)179 auth_pam (
180   /* PARAMETERS */
181   const char *login,			/* I: plaintext authenticator */
182   const char *password,			/* I: plaintext password */
183   const char *service,			/* I: service name */
184   const char *realm __attribute__((unused))
185   /* END PARAMETERS */
186   )
187 {
188     /* VARIABLES */
189     pam_appdata my_appdata;		/* application specific data */
190     struct pam_conv my_conv;		/* pam conversion data */
191     pam_handle_t *pamh;			/* pointer to PAM handle */
192     int rc;				/* return code holder */
193     /* END VARIABLES */
194 
195     my_appdata.login = login;
196     my_appdata.password = password;
197     my_appdata.pamh = NULL;
198 
199     my_conv.conv = saslauthd_pam_conv;
200     my_conv.appdata_ptr = &my_appdata;
201 
202     rc = pam_start(service, login, &my_conv, &pamh);
203     if (rc != PAM_SUCCESS) {
204 	syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_start failed: %s",
205 	       pam_strerror(pamh, rc));
206 	RETURN("NO PAM start error");
207     }
208 
209     my_appdata.pamh = pamh;
210 
211     rc = pam_authenticate(pamh, PAM_SILENT);
212     if (rc != PAM_SUCCESS) {
213 	syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_authenticate failed: %s",
214 	       pam_strerror(pamh, rc));
215 	pam_end(pamh, rc);
216 	RETURN("NO PAM auth error");
217     }
218 
219     rc = pam_acct_mgmt(pamh, PAM_SILENT);
220     if (rc != PAM_SUCCESS) {
221 	syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_acct_mgmt failed: %s",
222 	       pam_strerror(pamh, rc));
223 	pam_end(pamh, rc);
224 	RETURN("NO PAM acct error");
225     }
226 
227     pam_end(pamh, PAM_SUCCESS);
228     RETURN("OK");
229 }
230 
231 /* END FUNCTION: auth_pam */
232 
233 #else /* !AUTH_PAM */
234 
235 char *
auth_pam(const char * login,const char * password,const char * service,const char * realm)236 auth_pam(
237   const char *login __attribute__((unused)),
238   const char *password __attribute__((unused)),
239   const char *service __attribute__((unused)),
240   const char *realm __attribute__((unused))
241   )
242 {
243     return NULL;
244 }
245 
246 #endif /* !AUTH_PAM */
247 
248 /* END MODULE: auth_pam */
249