mod_pam.c
上传用户:pycemail
上传日期:2007-01-04
资源大小:329k
文件大小:8k
- /*
- * ProFTPD: mod_pam -- Support for PAM-style authentication.
- * Time-stamp: <1998-10-19 1:03:02 macgyver>
- * Copyright (c) 1998 Habeeb J. Dihu aka MacGyver <macgyver@tos.net>,
- * All Rights Reserved.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
- */
- /*
- * PAM module from ProFTPD
- *
- * This module should work equally well under all Linux distributions (which
- * have PAM support), as well as Solaris 2.5 and above.
- *
- * If you have any problems, questions, comments, or suggestions regarding
- * this module, please feel free to contact Habeeb J. Dihu aka MacGyver
- * <macgyver@tos.net>.
- *
- * -- DO NOT MODIFY THE TWO LINES BELOW --
- * $Libraries: -lpam$
- * $Id: mod_pam.c,v 1.2 1999/09/17 07:31:44 macgyver Exp $
- * $Log: mod_pam.c,v $
- * Revision 1.2 1999/09/17 07:31:44 macgyver
- * Implemented sstrncpy to handle proper buffer copying issues on all platforms.
- *
- * Revision 1.1 1999/09/10 20:17:18 macgyver
- * Moved PAM into the main module set. It's now a 'core' feature.
- *
- * Revision 1.4 1999/09/08 08:35:35 macgyver
- * Updates to auto-configuring for PAM on *BSD.
- *
- * Revision 1.3 1999/09/07 23:13:14 macgyver
- * Some minor security updates to fix potential buffer problems.
- *
- * Revision 1.2 1999/03/05 03:34:12 flood
- * MacGyver's patch to do argv[] rewriting the Right Way<tm>, and some minor
- * socket error handling fixes.
- *
- * Revision 1.1 1998/11/01 19:08:21 flood
- * APPE, mod_pam & mod_readme added
- *
- * Revision 1.6 1998/10/26 06:47:35 macgyver
- * Reworked configuration handling to be 1.2 compliant.
- *
- * Revision 1.5 1998/10/23 04:25:45 macgyver
- * Changed configuration parameter to AuthPAMAuthoritative to be more in tune
- * with Apache. Credit to Jay Soffian for the suggestion.
- *
- * Revision 1.4 1998/10/22 04:25:09 macgyver
- * Updated for CVS.
- *
- */
- #include "conf.h"
- #include "privs.h"
- #include <security/pam_appl.h>
- static char * pam_user = (char *)0;
- static char * pam_pass = (char *)0;
- static int pam_conv_error = 0;
- static int pam_exchange(num_msg, msg, resp, appdata_ptr)
- int num_msg;
- struct pam_message **msg;
- struct pam_response **resp;
- void *appdata_ptr;
- {
- int i;
- struct pam_response *response = NULL;
-
- response = malloc(sizeof(struct pam_response) * num_msg);
- if(response == (struct pam_response *)0)
- return PAM_CONV_ERR;
-
- for(i = 0; i < num_msg; i++) {
- response[i].resp_retcode = PAM_SUCCESS;
-
- switch(msg[i]->msg_style) {
- case PAM_PROMPT_ECHO_ON:
- response[i].resp = pam_user;
- /* PAM frees resp */
- break;
-
- case PAM_PROMPT_ECHO_OFF:
- response[i].resp = pam_pass;
- /* PAM frees resp */
- break;
-
- case PAM_TEXT_INFO:
- case PAM_ERROR_MSG:
- /* ignore it, but pam still wants a NULL response... */
- response[i].resp = NULL;
- break;
-
- default:
- /* Must be an error of some sort... */
- free(response);
- pam_conv_error = 1;
- return PAM_CONV_ERR;
- }
- }
-
- *resp = response;
- return PAM_SUCCESS;
- }
- static struct pam_conv pam_conv = {
- &pam_exchange,
- NULL
- };
- MODRET pam_auth(cmd_rec *cmd)
- {
- int pam_error = 0, retval = 0, pam_return_type;
- int success = 0;
- pam_handle_t *pamh = NULL;
- config_rec *c;
- char *pamconfig = "ftp";
-
- /* Figure out our default return style:
- * Whether or not PAM should allow other auth modules a shot at this
- * user or not is controlled by the parameter
- * "AuthPAMAuthoritative". It defaults to no, since it is a more
- * closed (read secure) environment.
- */
- pam_return_type = get_param_int(TOPLEVEL_CONF,
- "AuthPAMAuthoritative", FALSE);
-
- /* Just in case...
- */
- if(cmd->argc != 2)
- return pam_return_type ? ERROR(cmd) : DECLINED(cmd);
-
- /* Allocate our entries...we don't free this because PAM does this for us.
- */
- pam_user = malloc(strlen(cmd->argv[0]) + 1);
- if(pam_user == (char *)0)
- return pam_return_type ? ERROR(cmd) : DECLINED(cmd);
- sstrncpy(pam_user, cmd->argv[0], strlen(cmd->argv[0]) + 1);
-
- pam_pass = malloc(strlen(cmd->argv[1]) + 1);
- if(pam_pass == (char *)0)
- return pam_return_type ? ERROR(cmd) : DECLINED(cmd);
- sstrncpy(pam_pass, cmd->argv[1], strlen(cmd->argv[1]) + 1);
-
- /* Check for which PAM config file to use. Since we have many different
- * potential servers, they may each require a seperate type of PAM
- * authentication.
- */
- if((c = find_config(TOPLEVEL_CONF, CONF_PARAM, "PAMConfig", FALSE)) != NULL)
- pamconfig = c->argv[0];
-
- /* Due to the different types of authentication used, such as shadow
- * passwords, etc. we need root privs for this operation.
- */
- block_signals();
- PRIVS_ROOT
- pam_error = pam_start(pamconfig, pam_user, &pam_conv, &pamh);
- if(pam_error != PAM_SUCCESS)
- goto done;
-
- /* Authenticate, and get any credentials as needed.
- */
- pam_error = pam_authenticate(pamh, PAM_SILENT);
-
- if(pam_error != PAM_SUCCESS) {
- switch(pam_error) {
- case PAM_USER_UNKNOWN:
- retval = AUTH_NOPWD;
- break;
-
- default:
- retval = AUTH_BADPWD;
- break;
- }
-
- log_pri(LOG_NOTICE, "PAM(%s): %s", cmd->argv[0],
- pam_strerror(pamh, pam_error));
- goto done;
- }
-
- if(pam_conv_error != 0) {
- retval = AUTH_BADPWD;
- goto done;
- }
-
- pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
- if(pam_error != PAM_SUCCESS) {
- switch(pam_error) {
- #ifdef PAM_AUTHTOKEN_REQD
- case PAM_AUTHTOKEN_REQD:
- retval = AUTH_AGEPWD;
- break;
- #endif /* PAM_AUTHTOKEN_REQD */
- case PAM_ACCT_EXPIRED:
- retval = AUTH_DISABLEDPWD;
- break;
-
- case PAM_USER_UNKNOWN:
- retval = AUTH_NOPWD;
- break;
-
- default:
- retval = AUTH_BADPWD;
- break;
- }
-
- log_pri(LOG_NOTICE, "PAM(%s): %s", cmd->argv[0],
- pam_strerror(pamh, pam_error));
- goto done;
- }
-
- pam_error = pam_setcred(pamh, PAM_ESTABLISH_CRED);
-
- if(pam_error != PAM_SUCCESS) {
- switch(pam_error) {
- case PAM_CRED_EXPIRED:
- retval = AUTH_AGEPWD;
- break;
-
- case PAM_USER_UNKNOWN:
- retval = AUTH_NOPWD;
- break;
-
- default:
- retval = AUTH_BADPWD;
- break;
- }
-
- log_pri(LOG_NOTICE, "PAM(%s): %s", cmd->argv[0],
- pam_strerror(pamh, pam_error));
- goto done;
- }
-
- success++;
-
- done:
- /* And we're done. Close off any PAM pointers, and relinquish our root
- * privs.
- */
- pam_end(pamh, pam_error);
- PRIVS_RELINQUISH;
- unblock_signals();
-
- if(!success)
- return pam_return_type ? ERROR_INT(cmd, retval) : DECLINED(cmd);
- else
- return HANDLED(cmd);
- }
- MODRET set_pamauthoritative(cmd_rec *cmd)
- {
- int b;
-
- CHECK_ARGS(cmd, 1);
- CHECK_CONF(cmd, CONF_ROOT);
-
- if((b = get_boolean(cmd, 1)) == -1)
- CONF_ERROR(cmd, "expected boolean argument.");
- add_config_param("AuthPAMAuthoritative", 1, (void *) b);
- return HANDLED(cmd);
- }
- MODRET set_pamconfig(cmd_rec *cmd)
- {
- CHECK_ARGS(cmd, 1);
- CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_ANON | CONF_GLOBAL);
- add_config_param_str("PAMConfig", 1, (void *) cmd->argv[1]);
-
- return HANDLED(cmd);
- }
- static authtable pam_authtab[] = {
- { 0, "auth", pam_auth},
- { 0, NULL, NULL}
- };
- static conftable pam_conftab[] = {
- { "AuthPAMAuthoritative", set_pamauthoritative, NULL },
- { "PAMConfig", set_pamconfig, NULL },
- { NULL, NULL, NULL}
- };
- module pam_module = {
- NULL,NULL, /* Always NULL */
- 0x20, /* API Version 2.0 */
- "pam",
- pam_conftab, /* PAM configuration handler table */
- NULL, /* No command handler table */
- pam_authtab, /* PAM authentication handler table */
- NULL, /* No initialization needed */
- NULL /* No post-fork "child mode" init */
- };