pampass.c

来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 876 行 · 第 1/2 页

C
876
字号
/*    Unix SMB/CIFS implementation.   PAM Password checking   Copyright (C) Andrew Tridgell 1992-2001   Copyright (C) John H Terpsta 1999-2001   Copyright (C) Andrew Bartlett 2001   Copyright (C) Jeremy Allison 2001      This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2 of the License, or   (at your option) any later version.      This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.      You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*//* * This module provides PAM based functions for validation of * username/password pairs, account managment, session and access control. * Note: SMB password checking is done in smbpass.c */#include "includes.h"#undef DBGC_CLASS#define DBGC_CLASS DBGC_AUTH#ifdef WITH_PAM/******************************************************************* * Handle PAM authentication  * 	- Access, Authentication, Session, Password *   Note: See PAM Documentation and refer to local system PAM implementation *   which determines what actions/limitations/allowances become affected. *********************************************************************/#include <security/pam_appl.h>/* * Structure used to communicate between the conversation function * and the server_login/change password functions. */struct smb_pam_userdata {	const char *PAM_username;	const char *PAM_password;	const char *PAM_newpassword;};typedef int (*smb_pam_conv_fn)(int, const struct pam_message **, struct pam_response **, void *appdata_ptr);/* *  Macros to help make life easy */#define COPY_STRING(s) (s) ? SMB_STRDUP(s) : NULL/******************************************************************* PAM error handler. *********************************************************************/static BOOL smb_pam_error_handler(pam_handle_t *pamh, int pam_error, const char *msg, int dbglvl){	if( pam_error != PAM_SUCCESS) {		DEBUG(dbglvl, ("smb_pam_error_handler: PAM: %s : %s\n",				msg, pam_strerror(pamh, pam_error)));				return False;	}	return True;}/******************************************************************* This function is a sanity check, to make sure that we NEVER report failure as sucess.*********************************************************************/static BOOL smb_pam_nt_status_error_handler(pam_handle_t *pamh, int pam_error,					    const char *msg, int dbglvl, 					    NTSTATUS *nt_status){	*nt_status = pam_to_nt_status(pam_error);	if (smb_pam_error_handler(pamh, pam_error, msg, dbglvl))		return True;	if (NT_STATUS_IS_OK(*nt_status)) {		/* Complain LOUDLY */		DEBUG(0, ("smb_pam_nt_status_error_handler: PAM: BUG: PAM and NT_STATUS \error MISMATCH, forcing to NT_STATUS_LOGON_FAILURE"));		*nt_status = NT_STATUS_LOGON_FAILURE;	}	return False;}/* * PAM conversation function * Here we assume (for now, at least) that echo on means login name, and * echo off means password. */static int smb_pam_conv(int num_msg,		    const struct pam_message **msg,		    struct pam_response **resp,		    void *appdata_ptr){	int replies = 0;	struct pam_response *reply = NULL;	struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;	*resp = NULL;	if (num_msg <= 0)		return PAM_CONV_ERR;	/*	 * Apparantly HPUX has a buggy PAM that doesn't support the	 * appdata_ptr. Fail if this is the case. JRA.	 */	if (udp == NULL) {		DEBUG(0,("smb_pam_conv: PAM on this system is broken - appdata_ptr == NULL !\n"));		return PAM_CONV_ERR;	}	reply = SMB_MALLOC_ARRAY(struct pam_response, num_msg);	if (!reply)		return PAM_CONV_ERR;	memset(reply, '\0', sizeof(struct pam_response) * num_msg);	for (replies = 0; replies < num_msg; replies++) {		switch (msg[replies]->msg_style) {			case PAM_PROMPT_ECHO_ON:				reply[replies].resp_retcode = PAM_SUCCESS;				reply[replies].resp = COPY_STRING(udp->PAM_username);				/* PAM frees resp */				break;			case PAM_PROMPT_ECHO_OFF:				reply[replies].resp_retcode = PAM_SUCCESS;				reply[replies].resp = COPY_STRING(udp->PAM_password);				/* PAM frees resp */				break;			case PAM_TEXT_INFO:				/* fall through */			case PAM_ERROR_MSG:				/* ignore it... */				reply[replies].resp_retcode = PAM_SUCCESS;				reply[replies].resp = NULL;				break;			default:				/* Must be an error of some sort... */				SAFE_FREE(reply);				return PAM_CONV_ERR;		}	}	if (reply)		*resp = reply;	return PAM_SUCCESS;}/* * PAM password change conversation function * Here we assume (for now, at least) that echo on means login name, and * echo off means password. */static void special_char_sub(char *buf){	all_string_sub(buf, "\\n", "", 0);	all_string_sub(buf, "\\r", "", 0);	all_string_sub(buf, "\\s", " ", 0);	all_string_sub(buf, "\\t", "\t", 0);}static void pwd_sub(char *buf, const char *username, const char *oldpass, const char *newpass){	fstring_sub(buf, "%u", username);	all_string_sub(buf, "%o", oldpass, sizeof(fstring));	all_string_sub(buf, "%n", newpass, sizeof(fstring));}struct chat_struct {	struct chat_struct *next, *prev;	fstring prompt;	fstring reply;};/************************************************************** Create a linked list containing chat data.***************************************************************/static struct chat_struct *make_pw_chat(const char *p) {	fstring prompt;	fstring reply;	struct chat_struct *list = NULL;	struct chat_struct *t;	struct chat_struct *tmp;	while (1) {		t = SMB_MALLOC_P(struct chat_struct);		if (!t) {			DEBUG(0,("make_pw_chat: malloc failed!\n"));			return NULL;		}		ZERO_STRUCTP(t);		DLIST_ADD_END(list, t, tmp);		if (!next_token(&p, prompt, NULL, sizeof(fstring)))			break;		if (strequal(prompt,"."))			fstrcpy(prompt,"*");		special_char_sub(prompt);		fstrcpy(t->prompt, prompt);		strlower_m(t->prompt);		trim_char(t->prompt, ' ', ' ');		if (!next_token(&p, reply, NULL, sizeof(fstring)))			break;		if (strequal(reply,"."))				fstrcpy(reply,"");		special_char_sub(reply);		fstrcpy(t->reply, reply);		strlower_m(t->reply);		trim_char(t->reply, ' ', ' ');	}	return list;}static void free_pw_chat(struct chat_struct *list){    while (list) {        struct chat_struct *old_head = list;        DLIST_REMOVE(list, list);        SAFE_FREE(old_head);    }}static int smb_pam_passchange_conv(int num_msg,				const struct pam_message **msg,				struct pam_response **resp,				void *appdata_ptr){	int replies = 0;	struct pam_response *reply = NULL;	fstring current_prompt;	fstring current_reply;	struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;	struct chat_struct *pw_chat= make_pw_chat(lp_passwd_chat());	struct chat_struct *t;	BOOL found; 	*resp = NULL;		DEBUG(10,("smb_pam_passchange_conv: starting converstation for %d messages\n", num_msg));	if (num_msg <= 0)		return PAM_CONV_ERR;	if (pw_chat == NULL)		return PAM_CONV_ERR;	/*	 * Apparantly HPUX has a buggy PAM that doesn't support the	 * appdata_ptr. Fail if this is the case. JRA.	 */	if (udp == NULL) {		DEBUG(0,("smb_pam_passchange_conv: PAM on this system is broken - appdata_ptr == NULL !\n"));		free_pw_chat(pw_chat);		return PAM_CONV_ERR;	}	reply = SMB_MALLOC_ARRAY(struct pam_response, num_msg);	if (!reply) {		DEBUG(0,("smb_pam_passchange_conv: malloc for reply failed!\n"));		free_pw_chat(pw_chat);		return PAM_CONV_ERR;	}	for (replies = 0; replies < num_msg; replies++) {		found = False;		DEBUG(10,("smb_pam_passchange_conv: Processing message %d\n", replies));		switch (msg[replies]->msg_style) {		case PAM_PROMPT_ECHO_ON:			DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: PAM said: %s\n", msg[replies]->msg));			fstrcpy(current_prompt, msg[replies]->msg);			trim_char(current_prompt, ' ', ' ');			for (t=pw_chat; t; t=t->next) {				DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: trying to match |%s| to |%s|\n",						t->prompt, current_prompt ));				if (unix_wild_match(t->prompt, current_prompt)) {					fstrcpy(current_reply, t->reply);					DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We sent: %s\n", current_reply));					pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);#ifdef DEBUG_PASSWORD					DEBUG(100,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We actualy sent: %s\n", current_reply));#endif					reply[replies].resp_retcode = PAM_SUCCESS;					reply[replies].resp = COPY_STRING(current_reply);					found = True;					break;				}			}			/* PAM frees resp */			if (!found) {				DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg));				free_pw_chat(pw_chat);				SAFE_FREE(reply);				return PAM_CONV_ERR;			}			break;		case PAM_PROMPT_ECHO_OFF:			DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: PAM said: %s\n", msg[replies]->msg));			fstrcpy(current_prompt, msg[replies]->msg);			trim_char(current_prompt, ' ', ' ');			for (t=pw_chat; t; t=t->next) {				DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: trying to match |%s| to |%s|\n",						t->prompt, current_prompt ));				if (unix_wild_match(t->prompt, current_prompt)) {					fstrcpy(current_reply, t->reply);					DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We sent: %s\n", current_reply));					pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);					reply[replies].resp_retcode = PAM_SUCCESS;					reply[replies].resp = COPY_STRING(current_reply);#ifdef DEBUG_PASSWORD					DEBUG(100,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We actualy sent: %s\n", current_reply));#endif					found = True;					break;				}			}			/* PAM frees resp */						if (!found) {				DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg));				free_pw_chat(pw_chat);				SAFE_FREE(reply);				return PAM_CONV_ERR;			}			break;		case PAM_TEXT_INFO:			/* fall through */		case PAM_ERROR_MSG:			/* ignore it... */			reply[replies].resp_retcode = PAM_SUCCESS;			reply[replies].resp = NULL;			break;					default:			/* Must be an error of some sort... */			free_pw_chat(pw_chat);			SAFE_FREE(reply);			return PAM_CONV_ERR;		}	}			free_pw_chat(pw_chat);	if (reply)		*resp = reply;	return PAM_SUCCESS;}/*************************************************************************** Free up a malloced pam_conv struct.****************************************************************************/static void smb_free_pam_conv(struct pam_conv *pconv){	if (pconv)		SAFE_FREE(pconv->appdata_ptr);	SAFE_FREE(pconv);}/*************************************************************************** Allocate a pam_conv struct.****************************************************************************/static struct pam_conv *smb_setup_pam_conv(smb_pam_conv_fn smb_pam_conv_fnptr, const char *user,					const char *passwd, const char *newpass){	struct pam_conv *pconv = SMB_MALLOC_P(struct pam_conv);	struct smb_pam_userdata *udp = SMB_MALLOC_P(struct smb_pam_userdata);	if (pconv == NULL || udp == NULL) {		SAFE_FREE(pconv);		SAFE_FREE(udp);		return NULL;	}	udp->PAM_username = user;	udp->PAM_password = passwd;	udp->PAM_newpassword = newpass;	pconv->conv = smb_pam_conv_fnptr;	pconv->appdata_ptr = (void *)udp;	return pconv;}/*  * PAM Closing out cleanup handler */static BOOL smb_pam_end(pam_handle_t *pamh, struct pam_conv *smb_pam_conv_ptr){	int pam_error;	smb_free_pam_conv(smb_pam_conv_ptr);       	if( pamh != NULL ) {		pam_error = pam_end(pamh, 0);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?