[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 */
};
|