[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pam-list
Subject:    pam & apache 1.3.2
From:       Ingo Luetkebohle ingo () devconsult ! de
Date:       1998-09-30 20:13:11
[Download RAW message or body]

On Wed, 30 Sep 1998, Leo Wierzbowski wrote:
> Anyone able to get the PAM module to make with Apache 1.3.2 on RedHat 5.1?

I am, which is not very surprising, since I'm the author :-)

I currently have sent a copy of a 1.3.x compatible mod_auth_pam to everyone
who asked for it. The reason its not "officially" available is because
there's no configure support and no real testing yet.

I attached a version for everyone who's interested.

--
	Ingo Luetkebohle / netdancer@irc / ingo@blank.pages.de
dev/consulting Gesellschaft fuer Netzwerkentwicklung und -beratung mbH
url: http://www.devconsult.de/ - fon: 0521-1365800 - fax: 0521-1365803 

["mod_auth_pam.c" (TEXT/PLAIN)]

/* 
 * Copyright (c) 1997,1998 Ingo Lütkebohle <ingo@blank.pages.de>
 * All rights reserved.
 * 
 */

/*
 * v 0.6 from 25-Sep-98
 *
 * mod_auth_pam:
 *  basic authentication against pluggable authentication module lib
 *
 *  For information about PAM, please refer to
 *    http://parc.power.net/morgan/Linux-PAM/
 *
 *  For recent versions of this file and other information refer to
 *    http://blank.pages.de/pam/
 *
 * Author: Ingo Lütkebohle <ingo@blank.pages.de>
 *  based upon mod_auth.c
 *
 * Changes:
 *   25-Sep-98: replaced pwdb groups routine with standard C
 *   19-Oct-97: made module fall through (if configured to do so),
 * 		even when a user of the given name is found in the PAM
 *		databases
 *   17-Apr-97: fixed segfault that occured when Apache couldn't look
 *              up the remote host name
 *              removed annoying compiler warnings
 *
 *   05-Apr-97: made fall-through configurable with AuthPAM_Authorative
 *
 *   25-Mar-97: added support for transparent fall-through to other auth
 *              modules with configurable fail delays
 *              added acct_mgmt hook
 *              added group support (through libpwdb)
 *
 * usage information:
 *
 * 1. Configuration:
 *     Module pam_auth_module mod_auth_pam.o
 *     EXTRA_LIBS+= -lpam -ldl
 *
 * 2. Add an auth and an account entry for service type "httpd"
 *    to your PAM configuration
 *
 *
 * configuration directives:
 * AuthFailDelay <msecs>
 *                              number of mili-seconds to wait after a
 *                              failed authentication attempt. this is
 *                              a minimum value and may have been
 *                              increased by other pam apps.
 *                              defaults to 0
 *
 * AuthPAM_Authorative on|off
 *                              If off, mod_auth_pam will DECLINE if it
 *                              can't authenticate the user. this will
 *                              enable other authentication modules to
 *                              have a try.
 *                              defaults to on. Only change this if
 *                              you know what you are doing!
 *
 */

#include <unistd.h>

#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_protocol.h"

#include <security/pam_appl.h>

#define PAM_STRE_NEEDS_PAMH 1

module pam_auth_module;

static const char
  *pam_servicename = "httpd",
  *valid_user = "valid-user";

typedef struct {
  char *name, *pw;
} auth_pam_userinfo;

/*
 * configuration directive handling
 */

typedef struct {
  int fail_delay, is_authorative;
} auth_pam_dir_config;

void* create_auth_pam_dir_config(pool *p, char *dummy)
{
  auth_pam_dir_config *new =
    (auth_pam_dir_config*) ap_palloc (p, sizeof(auth_pam_dir_config));

  new->fail_delay   = 0; /* 0 ms */
  new->is_authorative = 1; /* on */
  return new;
}

char* auth_fail_delay(cmd_parms *cmd, auth_pam_dir_config *config, char *secs)
{
  if(secs)
    config->fail_delay = atoi(secs);
  return NULL;
}

char* auth_fall_through(cmd_parms *cmd, auth_pam_dir_config *config, int arg)
{
  config->is_authorative = arg;
  return NULL;
}

command_rec auth_pam_cmds[] = {
  { "AuthFailDelay", (const char*(*)())auth_fail_delay, 0, OR_AUTHCFG, TAKE1,
    "number of micro seconds to wait after failed authentication attempt. defau
lt is 0" },
  { "AuthPAM_Authorative", (const char*(*)())auth_fall_through, 0, OR_AUTHCFG, FLAG,
    "on|off - determines if other authentication methods are attempted if this
one fails" },
  { 0 }
};


/*
 * get a list of groups the given user belongs to
 *
 * adapted from the version in mod_auth to use a new means of
 * group information.
 *
 * note: someone should really have a hard look at all the auth
 *       modules and compile a more generic version of the
 *       functions. currently there's lots of code overlap
 */
table *get_groups (pool *p, char *user)
{
  table *grps = ap_make_table (p, 15);
  pool *sp = 0;
  char *group_name = 0;
  int ngrps = 0;
  gid_t *gid_list = 0;
  struct passwd *pw_ent = 0;
  struct group *gr_ent = 0;
  int i = 0;

  sp = ap_make_sub_pool(p);
  if(!sp)
	return 0;

  /* enter principal group */
  if(pw_ent = getpwnam(user)) {
    gr_ent = getgrgid(pw_ent->pw_gid);
    if(gr_ent)
    	ap_table_set(grps, gr_ent->gr_name, "in");
  } else
	return 0; /* no such user */

  /* get list of supplemental groups */
  ngrps = getgroups(0, 0);
  gid_list = ap_palloc(sp, ngrps * sizeof(gid_t));
  if(gid_list)
  	getgroups(ngrps, gid_list);

  /* enter supplemental groups */
  for(i = 0; i < ngrps; i++) {
	gr_ent = getgrgid(gid_list[i]);
	ap_table_set(grps, gr_ent->gr_name, "in");
  }
 
  ap_destroy_pool (sp);
  return grps;
}

/*
 * auth_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
 *
 */
int auth_pam_talker(int num_msg,
                    const struct pam_message **msg,
                    struct pam_response **resp,
                    void *appdata_ptr)
{
  unsigned short i = 0;
  auth_pam_userinfo *userinfo = (auth_pam_userinfo*)appdata_ptr;
  struct pam_response *response = 0;

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

/*
 * These functions return 0 if client is OK, and proper error status
 * if not... either AUTH_REQUIRED, if we made a check, and it failed, or
 * SERVER_ERROR, if things are so totally confused that we couldn't
 * figure out how to tell if the client is authorized or not.
 *
 * If they return DECLINED, and all other modules also decline, that's
 * treated by the server core as a configuration error, logged and
 * reported as such.
 */

/*
 * Determine user ID, and check if it really is that user
 */
int pam_auth_basic_user (request_rec *r)
{
    int res = 0;
    /* mod_auth_pam specific */
    auth_pam_userinfo userinfo = { NULL, NULL };
    auth_pam_dir_config *conf = (auth_pam_dir_config*)
      ap_get_module_config(r->per_dir_config, &pam_auth_module);
    /* PAM specific  */
    struct pam_conv conv_info = { &auth_pam_talker, &userinfo};
    pam_handle_t *pamh  = NULL;

    /* read sent pw */
    if ((res = ap_get_basic_auth_pw (r, (const char**)&(userinfo.pw))))
      return res;

    /* this is only set after get_basic_auth_pw was called */
    userinfo.name = r->connection->user;

    /* initialize pam */
    if((res = pam_start(pam_servicename,
                        userinfo.name,
                        &conv_info,
                        &pamh)) != PAM_SUCCESS) {

#ifdef PAM_STRE_NEEDS_PAMH
      ap_log_reason((char*)pam_strerror(pamh, res), r->uri, r);
#else
      ap_log_reason((char*)pam_strerror(res), r->uri, r);
#endif
      return DECLINED;
    }

    /* set fail delay */
#ifdef PAM_FAIL_DELAY
    pam_fail_delay(pamh, conf->fail_delay);
#endif

    /* set remote user information */
    /* this seems to cause segfaults in lots of cases -- disabled for now
        pam_set_item(pamh, PAM_USER, userinfo.name);
        pam_set_item(pamh, PAM_RHOST, get_remote_host(r->connection,
                                                  conf,
                                                  REMOTE_NAME));
        */

    /* try to authenticate user, log error on failure */
    if((res = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS
) {
      if(!conf->is_authorative) {
        /* we don't know about the user, but other auth modules might do */
        pam_end(pamh, PAM_SUCCESS);
        return DECLINED;
      }
      else {
#ifdef PAM_STRE_NEEDS_PAMH
        ap_log_reason((char*)pam_strerror(pamh, res), r->uri, r);
#else
        ap_log_reason((char*)pam_strerror(res), r->uri, r);
#endif
        pam_end(pamh, PAM_SUCCESS);
        ap_note_basic_auth_failure(r);
        return AUTH_REQUIRED;
      }
    }

    /* check that the account is healthy */
    if((res = pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) {
#ifdef PAM_STRE_NEEDS_PAMH
      ap_log_reason((char*)pam_strerror(pamh, res), r->uri, r);
#else
      ap_log_reason((char*)pam_strerror(res), r->uri, r);
#endif
      pam_end(pamh, PAM_SUCCESS);
      return AUTH_REQUIRED;
    }

    pam_end(pamh, PAM_SUCCESS);
    return OK;
}

/*
 * Look if that user (as authenticated above) is allowed here
 */

int pam_check_auth (request_rec *r)
{
  register int i = 0;
  char method_restricted = 0, *line = 0, *word = 0;
  table *groups = 0;

  /* check for allowed users/group */
  const array_header *reqs_arr = ap_requires (r);
  require_line *reqs = 0;

  /* if any valid user suffices return success */
  if (!reqs_arr)
    return (OK);

  /* otherwise */
  reqs = (require_line*)reqs_arr->elts;
  groups = get_groups(r->pool, r->connection->user);

  /*  loop over requirement lines */
  for( i = 0; i < reqs_arr->nelts; i++) {
    /* if method of this requirement matches current method */
    if (reqs[i].method_mask & (1 << r->method_number)) {
      method_restricted = 1;

      line = reqs[i].requirement;
      word = ap_getword(r->pool, (const char**)&line, ' ');

      /* if any user is ok */
      if(!strcmp(word, valid_user))
        return OK;

      /* loop over line */
      if(!strcmp(word, "user")) {
        while(*line) {
          word = ap_getword_conf(r->pool, (const char**)&line);
          /* if username matches remote username */
          if(!strcmp(r->connection->user, word))
            /* return success */
            return OK;
        }
      } /* end if user */
      else if(!strcmp(word, "group")) {
        if(!groups) {
          ap_log_printf(r->server, "couldn't get group list");
          return DECLINED;
        }
        
        while(*line) {
          word = ap_getword_conf(r->pool, (const char**)&line);
          if(ap_table_get(groups, word))
            return OK;
        }
      } /* end if group */
    }
  }

  if (!method_restricted)
    return OK;

  ap_note_basic_auth_failure (r);
  return AUTH_REQUIRED;
}

module pam_auth_module = {
   STANDARD_MODULE_STUFF,
   NULL,                        /* initializer */
   create_auth_pam_dir_config,  /* dir config creater */
   NULL,                        /* dir merger --- default is to override */
   NULL,                        /* server config */
   NULL,                        /* merge server config */
   auth_pam_cmds,               /* command table */
   NULL,                        /* handlers */
   NULL,                        /* filename translation */
   pam_auth_basic_user,         /* check_user_id */
   pam_check_auth,              /* check auth */
   NULL,                        /* check access */
   NULL,                        /* type_checker */
   NULL,                        /* fixups */
   NULL                         /* logger */
};



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic