2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1992-2001
6 Copyright (C) John H Terpsta 1999-2001
7 Copyright (C) Andrew Bartlett 2001
8 Copyright (C) Jeremy Allison 2001
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * This module provides PAM based functions for validation of
27 * username/password pairs, account managment, session and access control.
28 * Note: SMB password checking is done in smbpass.c
33 extern int DEBUGLEVEL;
37 /*******************************************************************
38 * Handle PAM authentication
39 * - Access, Authentication, Session, Password
40 * Note: See PAM Documentation and refer to local system PAM implementation
41 * which determines what actions/limitations/allowances become affected.
42 *********************************************************************/
44 #include <security/pam_appl.h>
47 * Static variables used to communicate between the conversation function
48 * and the server_login function
51 static char *PAM_username;
52 static char *PAM_password;
55 * Macros to help make life easy
57 #define COPY_STRING(s) (s) ? strdup(s) : NULL
62 static BOOL smb_pam_error_handler(pam_handle_t *pamh, int pam_error, char *msg, int dbglvl)
65 if( pam_error != PAM_SUCCESS) {
66 DEBUG(dbglvl, ("PAM: %s : %s\n", msg, pam_strerror(pamh, pam_error)));
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 smb_pam_conv(int num_msg,
79 const struct pam_message **msg,
80 struct pam_response **resp,
84 struct pam_response *reply = NULL;
86 reply = malloc(sizeof(struct pam_response) * num_msg);
90 for (replies = 0; replies < num_msg; replies++) {
91 switch (msg[replies]->msg_style) {
92 case PAM_PROMPT_ECHO_ON:
93 reply[replies].resp_retcode = PAM_SUCCESS;
95 COPY_STRING(PAM_username);
99 case PAM_PROMPT_ECHO_OFF:
100 reply[replies].resp_retcode = PAM_SUCCESS;
101 reply[replies].resp =
102 COPY_STRING(PAM_password);
111 reply[replies].resp_retcode = PAM_SUCCESS;
112 reply[replies].resp = NULL;
116 /* Must be an error of some sort... */
126 static struct pam_conv smb_pam_conversation = {
132 * PAM Closing out cleanup handler
134 static BOOL smb_pam_end(pam_handle_t *pamh)
139 pam_error = pam_end(pamh, 0);
140 if(smb_pam_error_handler(pamh, pam_error, "End Cleanup Failed", 2) == True) {
141 DEBUG(4, ("PAM: PAM_END OK.\n"));
145 DEBUG(2,("PAM: not initialised"));
150 * Start PAM authentication for specified account
152 static BOOL smb_pam_start(pam_handle_t **pamh, char *user, char *rhost)
156 *pamh = (pam_handle_t *)NULL;
158 DEBUG(4,("PAM: Init user: %s\n", user));
160 pam_error = pam_start("samba", user, &smb_pam_conversation, pamh);
161 if( !smb_pam_error_handler(*pamh, pam_error, "Init Failed", 0)) {
162 *pamh = (pam_handle_t *)NULL;
167 rhost = client_name();
168 if (strequal(rhost,"UNKNOWN"))
169 rhost = client_addr();
173 DEBUG(4,("PAM: setting rhost to: %s\n", rhost));
174 pam_error = pam_set_item(*pamh, PAM_RHOST, rhost);
175 if(!smb_pam_error_handler(*pamh, pam_error, "set rhost failed", 0)) {
177 *pamh = (pam_handle_t *)NULL;
182 DEBUG(4,("PAM: setting tty\n"));
183 pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
184 if (!smb_pam_error_handler(*pamh, pam_error, "set tty failed", 0)) {
186 *pamh = (pam_handle_t *)NULL;
190 DEBUG(4,("PAM: Init passed for user: %s\n", user));
195 * PAM Authentication Handler
197 static BOOL smb_pam_auth(pam_handle_t *pamh, char *user, char *password)
202 * To enable debugging set in /etc/pam.d/samba:
203 * auth required /lib/security/pam_pwdb.so nullok shadow audit
206 DEBUG(4,("PAM: Authenticate User: %s\n", user));
207 pam_error = pam_authenticate(pamh, PAM_SILENT); /* Can we authenticate user? */
210 DEBUG(2, ("PAM: Athentication Error\n"));
212 case PAM_CRED_INSUFFICIENT:
213 DEBUG(2, ("PAM: Insufficient Credentials\n"));
215 case PAM_AUTHINFO_UNAVAIL:
216 DEBUG(2, ("PAM: Authentication Information Unavailable\n"));
218 case PAM_USER_UNKNOWN:
219 DEBUG(2, ("PAM: Username NOT known to Authentication system\n"));
222 DEBUG(2, ("PAM: One or more authentication modules reports user limit exceeeded\n"));
225 DEBUG(0, ("PAM: One or more PAM modules failed to load\n"));
228 DEBUG(4, ("PAM: User %s Authenticated OK\n", user));
231 DEBUG(0, ("PAM: UNKNOWN ERROR while authenticating user %s\n", user));
233 if(!smb_pam_error_handler(pamh, pam_error, "Authentication Failure", 2)) {
237 /* If this point is reached, the user has been authenticated. */
242 * PAM Account Handler
244 static BOOL smb_pam_account(pam_handle_t *pamh, char * user, char * password, BOOL pam_auth)
248 DEBUG(4,("PAM: Account Management for User: %s\n", user));
249 pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
250 switch( pam_error ) {
251 case PAM_AUTHTOK_EXPIRED:
252 DEBUG(2, ("PAM: User is valid but password is expired\n"));
254 case PAM_ACCT_EXPIRED:
255 DEBUG(2, ("PAM: User no longer permitted to access system\n"));
258 DEBUG(2, ("PAM: There was an authentication error\n"));
260 case PAM_PERM_DENIED:
261 DEBUG(0, ("PAM: User is NOT permitted to access system at this time\n"));
263 case PAM_USER_UNKNOWN:
264 DEBUG(0, ("PAM: User \"%s\" is NOT known to account management\n", user));
267 DEBUG(4, ("PAM: Account OK for User: %s\n", user));
270 DEBUG(0, ("PAM: UNKNOWN ERROR for User: %s\n", user));
272 if(!smb_pam_error_handler(pamh, pam_error, "Account Check Failed", 2)) {
277 /* Skip the pam_setcred() call if we didn't use pam_authenticate()
278 for authentication -- it's an error to call pam_setcred without
279 calling pam_authenticate first */
281 DEBUG(4, ("PAM: Skipping setcred for user: %s (using encrypted passwords)\n", user));
286 * This will allow samba to aquire a kerberos token. And, when
287 * exporting an AFS cell, be able to /write/ to this cell.
290 DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
291 pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
292 switch( pam_error ) {
293 case PAM_CRED_UNAVAIL:
294 DEBUG(0, ("PAM: Credentials not found for user:%s", user ));
296 case PAM_CRED_EXPIRED:
297 DEBUG(0, ("PAM: Credentials for user: \"%s\" EXPIRED!", user ));
299 case PAM_USER_UNKNOWN:
300 DEBUG(0, ("PAM: User: \"%s\" is NOT known so can not set credentials!", user ));
303 DEBUG(0, ("PAM: Unknown setcredentials error - unable to set credentials for %s", user ));
306 DEBUG(4, ("PAM: SetCredentials OK for User: %s\n", user));
309 DEBUG(0, ("PAM: Error Condition Unknown in pam_setcred function call!"));
311 if(!smb_pam_error_handler(pamh, pam_error, "Set Credential Failure", 2)) {
316 /* If this point is reached, the user has been authenticated. */
322 * PAM Internal Session Handler
324 static BOOL smb_internal_pam_session(pam_handle_t *pamh, char *user, char *tty, BOOL flag)
332 DEBUG(4,("PAM: tty set to: %s\n", tty));
333 pam_error = pam_set_item(pamh, PAM_TTY, tty);
334 if (!smb_pam_error_handler(pamh, pam_error, "set tty failed", 0))
339 pam_error = pam_open_session(pamh, PAM_SILENT);
340 if (!smb_pam_error_handler(pamh, pam_error, "session setup failed", 0))
343 pam_error = pam_close_session(pamh, PAM_SILENT);
344 if (!smb_pam_error_handler(pamh, pam_error, "session close failed", 0))
351 * PAM Externally accessible Session handler
354 BOOL smb_pam_session(BOOL flag, const char *in_user, char *tty, char *rhost)
356 pam_handle_t *pamh = NULL;
359 /* Ignore PAM if told to. */
361 if (!lp_obey_pam_restrictions())
364 user = strdup(in_user);
365 if ( user == NULL ) {
366 DEBUG(0, ("PAM: PAM_session Malloc Failed!\n"));
370 if (!smb_pam_start(&pamh, user, rhost)) {
374 if (!smb_internal_pam_session(pamh, user, tty, flag)) {
378 return smb_pam_end(pamh);
382 * PAM Externally accessible Account handler
384 BOOL smb_pam_accountcheck(char * user)
386 pam_handle_t *pamh = NULL;
391 /* Ignore PAM if told to. */
393 if (!lp_obey_pam_restrictions())
396 if( smb_pam_start(&pamh, user, NULL)) {
397 if ( smb_pam_account(pamh, user, NULL, False)) {
398 return( smb_pam_end(pamh));
401 DEBUG(0, ("PAM: Account Validation Failed - Rejecting User!\n"));
406 * PAM Password Validation Suite
408 BOOL smb_pam_passcheck(char * user, char * password)
410 pam_handle_t *pamh = NULL;
413 PAM_password = password;
416 * Note we can't ignore PAM here as this is the only
417 * way of doing auths on plaintext passwords when
418 * compiled --with-pam.
421 if( smb_pam_start(&pamh, user, NULL)) {
422 if ( smb_pam_auth(pamh, user, password)) {
423 if ( smb_pam_account(pamh, user, password, True)) {
424 return( smb_pam_end(pamh));
428 DEBUG(0, ("PAM: System Validation Failed - Rejecting User!\n"));
434 /* If PAM not used, no PAM restrictions on accounts. */
435 BOOL smb_pam_accountcheck(char * user)
440 #endif /* WITH_PAM */