[Mod-auth-commit] mod_authn_pam/src mod_authn_pam.c,NONE,1.1
Brought to you by:
firechipmunk,
honx
From: <fir...@us...> - 2003-11-11 08:39:30
|
Update of /cvsroot/mod-auth/mod_authn_pam/src In directory sc8-pr-cvs1:/tmp/cvs-serv6305/src Added Files: mod_authn_pam.c Log Message: adding authn_pam. I am having problems with this on FreeBSD 5.x I will try it with a Linux box in a couple days. --- NEW FILE: mod_authn_pam.c --- /* Copyright (c) 2000 Ingo Luetkebohle, All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CODE CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id: mod_authn_pam.c,v 1.1 2003/11/11 08:39:27 firechipmunk Exp $ * * mod_authn_pam for apache 2.1 * * Based on: v 2.0-1.1 from 07. July 2002 for APACHE 2.0 * * mod_authn_pam: * basic authentication against pluggable authentication module lib * * Written by Ingo Luetkebohle, based upon mod_auth.c, with contributions * from Fredrik Ohrn (group performance), Dirk-Willem van Gulik (licensing * consultation) and Michael Johnson (example group implementation). * Ported to Apache 2.0 by Dirk-Willem van Gulik. * * Ported to Apache 2.1 by Paul Querna * */ #include <sys/types.h> #include <pwd.h> /* for getpwnam et.al. */ #include <grp.h> /* for getpwnam et.al. */ #include <unistd.h> #include "ap_config.h" #include "httpd.h" #include "http_config.h" #include "http_core.h" #include "http_log.h" #include "http_protocol.h" #include "http_request.h" #include "mod_auth.h" #include <security/pam_appl.h> /* change this to 0 on RedHat 4.x */ #define PAM_STRE_NEEDS_PAMH 1 #define VERSION "2.0-1.1" module authn_pam_module; static const char *pam_servicename = "sshd", *valid_user = "valid-user"; typedef struct { request_rec * r; char *name, *pw; } authn_pam_userinfo; /* * Solaris 2.6.x has a broken conversation function and needs this * as a global variable * I refused to pollute code for other platforms with this, * so all Solaris 2.6 specific stuff is if'd like the following */ #if SOLARIS2 == 260 authn_pam_userinfo *global_userinfo; #endif /* * the pam_strerror function has different parameters in early PAM * versions */ #ifndef PAM_STRE_NEEDS_PAMH #define compat_pam_strerror(pamh, res) pam_strerror(res) #else #define compat_pam_strerror(pamh, res) pam_strerror(pamh, res) #endif /* * configuration directive handling */ typedef struct { int fail_delay; /* fail delay in ms -- needs library support */ } authn_pam_dir_config; static int authn_pam_init( apr_pool_t * p, apr_pool_t * plog, apr_pool_t * ptemp, server_rec * s ) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "PAM: mod_authn_pam/" VERSION); return OK; } static void *create_authn_pam_dir_config(apr_pool_t * p, char *dummy) { authn_pam_dir_config *new = (authn_pam_dir_config *) apr_palloc(p, sizeof(authn_pam_dir_config)); new->fail_delay = 0; /* 0 ms */ return new; } static command_rec authn_pam_cmds[] = { AP_INIT_TAKE1("AuthnPAMFailDelay", ap_set_int_slot, (void *) APR_OFFSETOF(authn_pam_dir_config, fail_delay), OR_AUTHCFG, "number of micro seconds to wait after failed authentication " "attempt. (default is 0.)"), {NULL} }; /* * authn_pam_talker: supply authentication information to PAM when asked * * Assumptions: * A password is asked for by requesting input without echoing * A username is asked for by requesting input _with_ echoing * */ static int authn_pam_talker(int num_msg, const struct pam_message ** msg, struct pam_response ** resp, void *appdata_ptr) { unsigned short i = 0; authn_pam_userinfo *userinfo = (authn_pam_userinfo *) appdata_ptr; struct pam_response *response = 0; #if SOLARIS2 == 260 if (!userinfo) userinfo = global_userinfo; #endif /* parameter sanity checking */ if (!resp || !msg || !userinfo) return PAM_CONV_ERR; /* allocate memory to store response */ response = malloc(num_msg * sizeof(struct pam_response)); if (!response) return PAM_CONV_ERR; /* copy values */ for (i = 0; i < num_msg; i++) { /* initialize to safe values */ response[i].resp_retcode = 0; response[i].resp = 0; /* select response based on requested output style */ switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_ON: /* on memory allocation failure, auth fails */ response[i].resp = strdup(userinfo->name); break; case PAM_PROMPT_ECHO_OFF: response[i].resp = strdup(userinfo->pw); break; default: if (response) free(response); return PAM_CONV_ERR; } } /* everything okay, set PAM response values */ *resp = response; return PAM_SUCCESS; } static authn_status check_pam_pw(request_rec * r, const char *user, const char *password) { int res = 0; /* mod_authn_pam specific */ authn_pam_userinfo userinfo = {NULL, NULL}; authn_pam_dir_config *conf = (authn_pam_dir_config *) ap_get_module_config(r->per_dir_config, &authn_pam_module); /* PAM specific */ struct pam_conv conv_info = {&authn_pam_talker, (void *) &userinfo}; pam_handle_t *pamh = NULL; userinfo.r = r; userinfo.name = (char*)user; userinfo.pw = (char*)password; if ((res = pam_start(pam_servicename, userinfo.name, &conv_info, &pamh)) != PAM_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "PAM: Could not start pam service: %s", compat_pam_strerror(pamh, res)); return HTTP_INTERNAL_SERVER_ERROR; } #ifdef PAM_FAIL_DELAY pam_fail_delay(pamh, conf->fail_delay); #endif if ((res = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "PAM: user '%s' - not authenticated: (%d) %s", user, res, compat_pam_strerror(pamh, res)); pam_end(pamh, PAM_SUCCESS); return AUTH_DENIED; } if ((res = pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "PAM: user '%s' - invalid account: %s", user, compat_pam_strerror(pamh, res)); pam_end(pamh, PAM_SUCCESS); return AUTH_DENIED; } pam_end(pamh, PAM_SUCCESS); // XXX: I don't like defaulting to GRANTED. I would like to reorganize the logic above sometime -chip return AUTH_GRANTED; } static authn_status get_pam_realm_hash(request_rec * r, const char *user, const char *realm, char **rethash) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "[mod_authn_pam.c] - Digest Authentication with authn_pam is not possible"); return AUTH_DENIED; } static const authn_provider authn_pam_provider = { &check_pam_pw, &get_pam_realm_hash }; static void pam_register_hooks(apr_pool_t * p) { ap_hook_post_config(authn_pam_init, NULL, NULL, APR_HOOK_MIDDLE); ap_register_provider(p, AUTHN_PROVIDER_GROUP, "pam", "0", &authn_pam_provider); } module AP_MODULE_DECLARE_DATA authn_pam_module = { STANDARD20_MODULE_STUFF, create_authn_pam_dir_config, /* dir config creater */ NULL, /* dir merger --- default is to override */ NULL, /* server config */ NULL, /* merge server config */ authn_pam_cmds, /* command table */ pam_register_hooks, /* register hooks */ }; |