patch from Steve Langasek <vorlon@netexpress.net> to make sure we
[Samba/gbeck.git] / source / auth / pampass.c
blob271c46045bce5c0875b96ddf1bff4c6d352c5631
1 /*
2 Unix SMB/Netbios implementation.
3 Version 2.2.
4 PAM Password checking
5 Copyright (C) Andrew Tridgell 1992-2001
6 Copyright (C) John H Terpsta 1999-2001
7 Copyright (C) Andrew Bartlett 2001
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 * This module provides PAM based functions for validation of
26 * username/password pairs, account managment, session and access control.
27 * Note: SMB password checking is done in smbpass.c
30 #include "includes.h"
32 extern int DEBUGLEVEL;
34 #ifdef WITH_PAM
36 /*******************************************************************
37 * Handle PAM authentication
38 * - Access, Authentication, Session, Password
39 * Note: See PAM Documentation and refer to local system PAM implementation
40 * which determines what actions/limitations/allowances become affected.
41 *********************************************************************/
43 #include <security/pam_appl.h>
46 * Static variables used to communicate between the conversation function
47 * and the server_login function
50 static char *PAM_username;
51 static char *PAM_password;
54 * Macros to help make life easy
56 #define COPY_STRING(s) (s) ? strdup(s) : NULL
59 * PAM error handler.
61 static BOOL pam_error_handler(pam_handle_t *pamh, int pam_error, char *msg, int dbglvl)
64 if( pam_error != PAM_SUCCESS)
66 DEBUG(dbglvl, ("PAM: %s : %s\n", msg, pam_strerror(pamh, pam_error)));
67 return False;
69 return True;
73 * PAM conversation function
74 * Here we assume (for now, at least) that echo on means login name, and
75 * echo off means password.
78 static int PAM_conv(int num_msg,
79 const struct pam_message **msg,
80 struct pam_response **resp,
81 void *appdata_ptr)
83 int replies = 0;
84 struct pam_response *reply = NULL;
86 reply = malloc(sizeof(struct pam_response) * num_msg);
87 if (!reply)
88 return PAM_CONV_ERR;
90 for (replies = 0; replies < num_msg; replies++)
92 switch (msg[replies]->msg_style)
94 case PAM_PROMPT_ECHO_ON:
95 reply[replies].resp_retcode = PAM_SUCCESS;
96 reply[replies].resp =
97 COPY_STRING(PAM_username);
98 /* PAM frees resp */
99 break;
101 case PAM_PROMPT_ECHO_OFF:
102 reply[replies].resp_retcode = PAM_SUCCESS;
103 reply[replies].resp =
104 COPY_STRING(PAM_password);
105 /* PAM frees resp */
106 break;
108 case PAM_TEXT_INFO:
109 /* fall through */
111 case PAM_ERROR_MSG:
112 /* ignore it... */
113 reply[replies].resp_retcode = PAM_SUCCESS;
114 reply[replies].resp = NULL;
115 break;
117 default:
118 /* Must be an error of some sort... */
119 free(reply);
120 return PAM_CONV_ERR;
123 if (reply)
124 *resp = reply;
125 return PAM_SUCCESS;
128 static struct pam_conv PAM_conversation = {
129 &PAM_conv,
130 NULL
134 * PAM Closing out cleanup handler
136 static BOOL proc_pam_end(pam_handle_t *pamh)
138 int pam_error;
140 if( pamh != NULL )
142 pam_error = pam_end(pamh, 0);
143 if(pam_error_handler(pamh, pam_error, "End Cleanup Failed", 2) == True) {
144 DEBUG(4, ("PAM: PAM_END OK.\n"));
145 return True;
148 DEBUG(2,("PAM: not initialised"));
149 return False;
153 * Start PAM authentication for specified account
155 static BOOL proc_pam_start(pam_handle_t **pamh, char *user)
157 int pam_error;
158 char * rhost;
160 DEBUG(4,("PAM: Init user: %s\n", user));
162 pam_error = pam_start("samba", user, &PAM_conversation, pamh);
163 if( !pam_error_handler(*pamh, pam_error, "Init Failed", 0)) {
164 proc_pam_end(*pamh);
165 return False;
168 rhost = client_name();
169 if (strcmp(rhost,"UNKNOWN") == 0)
170 rhost = client_addr();
172 #ifdef PAM_RHOST
173 DEBUG(4,("PAM: setting rhost to: %s\n", rhost));
174 pam_error = pam_set_item(*pamh, PAM_RHOST, rhost);
175 if(!pam_error_handler(*pamh, pam_error, "set rhost failed", 0)) {
176 proc_pam_end(*pamh);
177 return False;
179 #endif
180 #ifdef PAM_TTY
181 DEBUG(4,("PAM: setting tty\n"));
182 pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
183 if (!pam_error_handler(*pamh, pam_error, "set tty failed", 0)) {
184 proc_pam_end(*pamh);
185 return False;
187 #endif
188 DEBUG(4,("PAM: Init passed for user: %s\n", user));
189 return True;
193 * PAM Authentication Handler
195 static BOOL pam_auth(pam_handle_t *pamh, char *user, char *password)
197 int pam_error;
200 * To enable debugging set in /etc/pam.d/samba:
201 * auth required /lib/security/pam_pwdb.so nullok shadow audit
204 DEBUG(4,("PAM: Authenticate User: %s\n", user));
205 pam_error = pam_authenticate(pamh, PAM_SILENT); /* Can we authenticate user? */
206 switch( pam_error ){
207 case PAM_AUTH_ERR:
208 DEBUG(2, ("PAM: Athentication Error\n"));
209 break;
210 case PAM_CRED_INSUFFICIENT:
211 DEBUG(2, ("PAM: Insufficient Credentials\n"));
212 break;
213 case PAM_AUTHINFO_UNAVAIL:
214 DEBUG(2, ("PAM: Authentication Information Unavailable\n"));
215 break;
216 case PAM_USER_UNKNOWN:
217 DEBUG(2, ("PAM: Username NOT known to Authentication system\n"));
218 break;
219 case PAM_MAXTRIES:
220 DEBUG(2, ("PAM: One or more authentication modules reports user limit exceeeded\n"));
221 break;
222 case PAM_ABORT:
223 DEBUG(0, ("PAM: One or more PAM modules failed to load\n"));
224 break;
225 case PAM_SUCCESS:
226 DEBUG(4, ("PAM: User %s Authenticated OK\n", user));
227 break;
228 default:
229 DEBUG(0, ("PAM: UNKNOWN ERROR while authenticating user %s\n", user));
231 if(!pam_error_handler(pamh, pam_error, "Authentication Failure", 2)) {
232 proc_pam_end(pamh);
233 return False;
235 /* If this point is reached, the user has been authenticated. */
236 return (True);
240 * PAM Account Handler
242 static BOOL pam_account(pam_handle_t *pamh, char * user, char * password, BOOL pam_auth)
244 int pam_error;
246 DEBUG(4,("PAM: Account Management for User: %s\n", user));
247 pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
248 switch( pam_error ) {
249 case PAM_AUTHTOK_EXPIRED:
250 DEBUG(2, ("PAM: User is valid but password is expired\n"));
251 break;
252 case PAM_ACCT_EXPIRED:
253 DEBUG(2, ("PAM: User no longer permitted to access system\n"));
254 break;
255 case PAM_AUTH_ERR:
256 DEBUG(2, ("PAM: There was an authentication error\n"));
257 break;
258 case PAM_PERM_DENIED:
259 DEBUG(0, ("PAM: User is NOT permitted to access system at this time\n"));
260 break;
261 case PAM_USER_UNKNOWN:
262 DEBUG(0, ("PAM: User \"%s\" is NOT known to account management\n", user));
263 break;
264 case PAM_SUCCESS:
265 DEBUG(4, ("PAM: Account OK for User: %s\n", user));
266 break;
267 default:
268 DEBUG(0, ("PAM: UNKNOWN ERROR for User: %s\n", user));
270 if(!pam_error_handler(pamh, pam_error, "Account Check Failed", 2)) {
271 proc_pam_end(pamh);
272 return False;
275 /* Skip the pam_setcred() call if we didn't use pam_authenticate()
276 for authentication -- it's an error to call pam_setcred without
277 calling pam_authenticate first */
278 if (!pam_auth) {
279 DEBUG(4, ("PAM: Skipping setcred for user: %s (using encrypted passwords)\n", user));
280 return True;
284 * This will allow samba to aquire a kerberos token. And, when
285 * exporting an AFS cell, be able to /write/ to this cell.
288 DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
289 pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
290 if(!pam_error_handler(pamh, pam_error, "Set Credential Failure", 2)) {
291 proc_pam_end(pamh);
292 return False;
295 /* If this point is reached, the user has been authenticated. */
296 return (True);
301 * PAM Internal Session Handler
303 static BOOL proc_pam_session(pam_handle_t *pamh, char *user, char *tty, BOOL flag)
305 int pam_error;
307 PAM_password = NULL;
308 PAM_username = user;
310 #ifdef PAM_TTY
311 DEBUG(4,("PAM: tty set to: %s\n", tty));
312 pam_error = pam_set_item(pamh, PAM_TTY, tty);
313 if (!pam_error_handler(pamh, pam_error, "set tty failed", 0)) {
314 proc_pam_end(pamh);
315 return False;
317 #endif
319 if (flag) {
320 pam_error = pam_open_session(pamh, PAM_SILENT);
321 if (!pam_error_handler(pamh, pam_error, "session setup failed", 0)) {
322 proc_pam_end(pamh);
323 return False;
326 else
328 pam_error = pam_close_session(pamh, PAM_SILENT);
329 if (!pam_error_handler(pamh, pam_error, "session close failed", 0)) {
330 proc_pam_end(pamh);
331 return False;
334 return (True);
338 * PAM Externally accessible Session handler
340 BOOL pam_session(BOOL flag, const connection_struct *conn, char *tty)
342 pam_handle_t *pamh = NULL;
343 char * user;
345 user = malloc(strlen(conn->user)+1);
346 if ( user == NULL )
348 DEBUG(0, ("PAM: PAM_session Malloc Failed!\n"));
349 return False;
352 /* This is freed by PAM */
353 StrnCpy(user, conn->user, strlen(conn->user)+1);
355 if (!proc_pam_start(&pamh, user))
357 proc_pam_end(pamh);
358 return False;
361 if (proc_pam_session(pamh, user, tty, flag))
363 return proc_pam_end(pamh);
365 else
367 proc_pam_end(pamh);
368 return False;
373 * PAM Externally accessible Account handler
375 BOOL pam_accountcheck(char * user)
377 pam_handle_t *pamh = NULL;
379 PAM_username = user;
380 PAM_password = NULL;
382 if( proc_pam_start(&pamh, user))
384 if ( pam_account(pamh, user, NULL, False))
386 return( proc_pam_end(pamh));
389 DEBUG(0, ("PAM: Account Validation Failed - Rejecting User!\n"));
390 return( False );
394 * PAM Password Validation Suite
396 BOOL pam_passcheck(char * user, char * password)
398 pam_handle_t *pamh = NULL;
400 PAM_username = user;
401 PAM_password = password;
403 if( proc_pam_start(&pamh, user))
405 if ( pam_auth(pamh, user, password))
407 if ( pam_account(pamh, user, password, True))
409 return( proc_pam_end(pamh));
413 DEBUG(0, ("PAM: System Validation Failed - Rejecting User!\n"));
414 return( False );
417 #else
419 /* Do *NOT* make this function static. Doing so breaks the compile on gcc */
421 void pampass_dummy_function( void ) { } /*This stops compiler complaints */
423 #endif /* WITH_PAM */