home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 25 / CDROM25.iso / Share / linux / apache / contrib / modules / mod_auth_pg95.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-11  |  15.4 KB  |  526 lines

  1.  
  2. /* ====================================================================
  3.  * Copyright (c) 1995 The Apache Group.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer. 
  11.  *
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in
  14.  *    the documentation and/or other materials provided with the
  15.  *    distribution.
  16.  *
  17.  * 3. All advertising materials mentioning features or use of this
  18.  *    software must display the following acknowledgment:
  19.  *    "This product includes software developed by the Apache Group
  20.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  21.  *
  22.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  23.  *    endorse or promote products derived from this software without
  24.  *    prior written permission.
  25.  *
  26.  * 5. Redistributions of any form whatsoever must retain the following
  27.  *    acknowledgment:
  28.  *    "This product includes software developed by the Apache Group
  29.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  30.  *
  31.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  32.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  33.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  34.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  35.  * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  42.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  43.  * ====================================================================
  44.  *
  45.  * This software consists of voluntary contributions made by many
  46.  * individuals on behalf of the Apache Group and was originally based
  47.  * on public domain software written at the National Center for
  48.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  49.  * For more information on the Apache Group and the Apache HTTP server
  50.  * project, please see <http://www.apache.org/>.
  51.  *
  52.  */
  53.  
  54.  
  55. /*
  56.  * 
  57.  * Postgres95 authentication
  58.  *
  59.  * Version 0.3 (March 1996)
  60.  *
  61.  * Adapted from mod_auth_msql.c version 0.5 (Feb 1996)
  62.  * 
  63.  * mod_auth_msql.c was written by  Dirk.vanGulik@jrc.it; 
  64.  *                 http://ewse.ceo.org; http://me-www.jrc.it/~dirkx
  65.  *
  66.  *
  67.  * Needs libpq-fe.h and libpq.a
  68.  *
  69.  * Outline:
  70.  *
  71.  * One database, and one (or two) tables.
  72.  * one table holds the username (preferably as
  73.  * a primary key) and the encryped password. 
  74.  * the other table holds the username and the
  75.  * names of the group to which the user belongs.
  76.  * It is possible to have username, groupname and
  77.  * password in the same table.
  78.  * 
  79.  * Directives:
  80.  *
  81.  * Auth_PGhost       Hostname of the machine running
  82.  *               the postmaster. The effective uid
  83.  *               of the server should be allowed
  84.  *               access. 
  85.  *
  86.  * Auth_PGport            Port that the postmaster is listening to.
  87.  *
  88.  * Auth_PGoptions    Options to set on the database connection(optional)
  89.  *
  90.  * Auth_PGdatabase    Name of the database in which the following
  91.  *            table(s) are
  92.  *            
  93.  * Auth_PGpwd_table    Contains at least the fields with the
  94.  *            username and the (encrypted) password
  95.  *
  96.  * Auth_PGgrp_table    Contains at least the fields with the
  97.  *            username and the groupname. A user which
  98.  *            is in multiple groups has therefore
  99.  *            multiple entries
  100.  *
  101.  * Auth_PGuid_field    Name of the field containing the username
  102.  * Auth_PGpwd_field     Fieldname for the passwords
  103.  * Auth_PGgid_field    Fieldname for the groupname
  104.  *
  105.  * Auth_PG_nopasswd    <on|off>
  106.  *            skip password comparison if passwd field is
  107.  *            empty.
  108.  *
  109.  * Auth_PGpwd_whereclause  
  110.  *                      Add this sql fragement to the end of the
  111.  *            SQL select statement on the password table.
  112.  *                      It would be going onto the end of a where 
  113.  *            clause so it should start with a conjunctive
  114.  *                      like 'and' or 'or'.
  115.  *
  116.  * Auth_PGgrp_whereclause  
  117.  *                      Add this sql fragement to the end of the
  118.  *            SQL select statement on the group table.
  119.  *                      It would be going onto the end of a where 
  120.  *            clause so it should start with a conjunctive
  121.  *                      like 'and' or 'or'.
  122.  *
  123.  *
  124.  * Adam Sussman (asussman@vidya.com) Feb, 1996
  125.  *
  126.  * see http://epoch.cs.berkeley.edu:8000/postgres95/
  127.  *
  128.  *
  129.  * Version 0.0  (Feb 1996) First release (adaptation from mod_auth_msql.c v0.5)
  130.  *       0.1  (Mar 1996) Correct PGgid_field command
  131.  *       0.2  (Mar 1996) Added Auth_PGpwd_whereclause and Auth_PGgrp_whereclause
  132.  *
  133.  */
  134.  
  135. #include "httpd.h"
  136. #include "http_config.h"
  137. #include "http_core.h"
  138. #include "http_log.h"
  139. #include "http_protocol.h"
  140. #include <libpq-fe.h>
  141. #undef palloc
  142.  
  143. typedef struct  {
  144.  
  145.     char *auth_pg_host;
  146.     char *auth_pg_database;
  147.     char *auth_pg_port;
  148.     char *auth_pg_options;
  149.  
  150.     char *auth_pg_pwd_table;
  151.     char *auth_pg_grp_table;
  152.  
  153.     char *auth_pg_pwd_field;
  154.     char *auth_pg_uname_field;
  155.     char *auth_pg_grp_field;
  156.  
  157.     int auth_pg_nopasswd;
  158.  
  159.     char *auth_pg_pwd_whereclause;
  160.     char *auth_pg_grp_whereclause;
  161.  
  162. } pg_auth_config_rec;
  163.  
  164. void *create_pg_auth_dir_config (pool *p, char *d)
  165. {
  166.     return pcalloc (p, sizeof(pg_auth_config_rec));
  167.  
  168. }
  169.  
  170. static
  171. char *set_passwd_flag (cmd_parms *cmd, pg_auth_config_rec *sec, int arg) {
  172.     sec->auth_pg_nopasswd=arg;
  173.     return NULL;
  174. }
  175.  
  176. char *pg_set_string_slot (cmd_parms *cmd, char *struct_ptr, char *arg)
  177. {
  178.  
  179.     int offset = (int)cmd->info; 
  180.     *(char **)(struct_ptr + offset) = pstrdup (cmd->pool, arg);
  181.     /* do we want to check anything ? */
  182.     return NULL;
  183. }
  184.  
  185. command_rec pg_auth_cmds[] = {
  186. { "Auth_PGhost", pg_set_string_slot,
  187.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_host),
  188.     OR_AUTHCFG, TAKE1, "The Host must be set to something" },
  189.  
  190. { "Auth_PGdatabase", pg_set_string_slot,
  191.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_database),
  192.     OR_AUTHCFG, TAKE1, "The Database field must be set to something. " },
  193.  
  194. { "Auth_PGport", pg_set_string_slot,
  195.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_port),
  196.     OR_AUTHCFG, TAKE1, "You must specify the postmaster port. " },
  197.  
  198. { "Auth_PGoptions", pg_set_string_slot,
  199.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_options),
  200.     OR_AUTHCFG, TAKE1, "You must give an option string. " },
  201.  
  202. { "Auth_PGpwd_table", pg_set_string_slot,
  203.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_pwd_table),
  204.     OR_AUTHCFG, TAKE1, "You must give a password table name" },
  205.  
  206. { "Auth_PGgrp_table", pg_set_string_slot,
  207.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_grp_table),
  208.     OR_AUTHCFG, TAKE1, "If you want to use groups, you must give a group table name" },
  209.  
  210. { "Auth_PGpwd_field", pg_set_string_slot,
  211.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_pwd_field),
  212.     OR_AUTHCFG, TAKE1, "The Password-field name must be set to something" },
  213.  
  214. { "Auth_PGuid_field", pg_set_string_slot,
  215.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_uname_field),
  216.     OR_AUTHCFG, TAKE1, "The UserID field name must be set to something" },
  217.  
  218. { "Auth_PGgid_field", pg_set_string_slot,
  219.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_grp_field),
  220.     OR_AUTHCFG, TAKE1, 
  221.     "GID field name must be set to something if you want to use groups" },
  222.  
  223. { "Auth_PG_nopasswd", set_passwd_flag, NULL, OR_AUTHCFG, FLAG, 
  224.     "Limited to 'on' or 'off'" },
  225.  
  226. { "Auth_PGgrp_whereclause", pg_set_string_slot,
  227.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_grp_whereclause),
  228.     OR_AUTHCFG, RAW_ARGS,
  229.     "You must give an SQL fragement that can be attached to the end of a where clause" },
  230.  
  231. { "Auth_PGpwd_whereclause", pg_set_string_slot,
  232.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_pwd_whereclause),
  233.     OR_AUTHCFG, RAW_ARGS,
  234.     "You must give an SQL fragement that can be attached to the end of a where clause" },
  235.  
  236. { NULL }
  237. };
  238.  
  239. module pg95_auth_module;
  240.  
  241. char pg_errstr[MAX_STRING_LEN];
  242.          /* global errno to be able to handle config/sql 
  243.          * failures separately
  244.          */
  245.  
  246. /* get the password for uname=user, and copy it
  247.  * into r. Assume that user is a string and stored
  248.  * as such in the pg95 database
  249.  */
  250. char *do_pg_query(request_rec *r, char *query, pg_auth_config_rec *sec) {
  251.  
  252.         PGconn        *pg_conn;
  253.     PGresult    *pg_result;
  254.  
  255.     char        *val;
  256.      char         *result=NULL;
  257.  
  258.     pg_errstr[0]='\0';
  259.  
  260.  
  261.     pg_conn = PQsetdb(sec->auth_pg_host, sec->auth_pg_port, sec->auth_pg_options,
  262.              NULL, sec->auth_pg_database);
  263.  
  264.     if (PQstatus(pg_conn) != CONNECTION_OK) {
  265.         sprintf(pg_errstr, "%s", PQerrorMessage(pg_conn));
  266.         return NULL;
  267.     }
  268.  
  269.     pg_result = PQexec(pg_conn, query);
  270.  
  271.     if (pg_result == NULL)
  272.     {
  273.         sprintf(pg_errstr, "%s", PQerrorMessage(pg_conn));
  274.         PQfinish(pg_conn);
  275.         return NULL;
  276.     }
  277.  
  278.     if (PQresultStatus(pg_result) == PGRES_EMPTY_QUERY) {
  279.         PQclear(pg_result);
  280.         PQfinish(pg_conn);
  281.         return NULL;
  282.     }
  283.  
  284.     if (PQresultStatus(pg_result) != PGRES_TUPLES_OK) {
  285.         sprintf(pg_errstr, "%s", PQerrorMessage(pg_conn));
  286.         PQclear(pg_result);
  287.         PQfinish(pg_conn);
  288.         return NULL;
  289.     }
  290.  
  291.     if (PQntuples(pg_result) == 1) {
  292.         val = PQgetvalue(pg_result, 0, 0);
  293.         if (val == NULL) {
  294.             sprintf(pg_errstr, "%s", PQerrorMessage(pg_conn));
  295.             PQclear(pg_result);
  296.             PQfinish(pg_conn);
  297.             return NULL;
  298.         }
  299.  
  300.         if (!(result = (char*)palloc(r->pool, strlen(val)+1))) {
  301.             sprintf (pg_errstr, "Could not get memory for Postgres query.");
  302.             PQclear(pg_result);
  303.             PQfinish(pg_conn);
  304.             return NULL;
  305.         }
  306.  
  307.         strcpy(result, val);
  308.     }
  309.  
  310.     /* ignore errors here ! */
  311.     PQclear(pg_result);
  312.     PQfinish(pg_conn);
  313.     return result;
  314. }
  315.     
  316. char *get_pg_pw(request_rec *r, char *user, pg_auth_config_rec *sec) {
  317.       char         query[MAX_STRING_LEN];
  318.  
  319.     if (
  320.         (!sec->auth_pg_pwd_table) ||
  321.         (!sec->auth_pg_pwd_field) ||
  322.         (!sec->auth_pg_uname_field)
  323.        ) {
  324.         sprintf(pg_errstr,
  325.             "PG: Missing parameters for password lookup: %s%s%s",
  326.             (sec->auth_pg_pwd_table ? "" : "Password table "),
  327.             (sec->auth_pg_pwd_field ? "" : "Password field name "),
  328.             (sec->auth_pg_uname_field ? "" : "UserID field name ")
  329.             );
  330.         return NULL;
  331.         };
  332.  
  333.         sprintf(query,"select %s from %s where %s='%s'",
  334.         sec->auth_pg_pwd_field,
  335.         sec->auth_pg_pwd_table,
  336.         sec->auth_pg_uname_field,
  337.         user);
  338.  
  339.     if (sec->auth_pg_pwd_whereclause)
  340.         sprintf(query, "%s %s", query, sec->auth_pg_pwd_whereclause);
  341.  
  342.     return do_pg_query(r,query,sec);
  343. }       
  344.  
  345. char *get_pg_grp(request_rec *r, char *group,char *user, pg_auth_config_rec *sec) {
  346.       char         query[MAX_STRING_LEN];
  347.  
  348.     if (
  349.         (!sec->auth_pg_grp_table) ||
  350.         (!sec->auth_pg_grp_field) ||
  351.         (!sec->auth_pg_uname_field)
  352.        ) {
  353.         sprintf(pg_errstr,
  354.             "PG: Missing parameters for password lookup: %s%s%s",
  355.             (sec->auth_pg_grp_table ? "" : "Group table "),
  356.             (sec->auth_pg_grp_field ? "" : "GroupID field name "),
  357.             (sec->auth_pg_uname_field ? "" : "UserID field name ")
  358.             );
  359.         return NULL;
  360.         };
  361.  
  362.         sprintf(query,"select %s from %s where %s='%s' and %s='%s'",
  363.         sec->auth_pg_grp_field,
  364.         sec->auth_pg_grp_table,
  365.         sec->auth_pg_uname_field,user,
  366.         sec->auth_pg_grp_field,group
  367.         );
  368.  
  369.     if (sec->auth_pg_grp_whereclause)
  370.         sprintf(query, "%s %s", query, sec->auth_pg_grp_whereclause);
  371.  
  372.     return do_pg_query(r,query,sec);
  373. }       
  374.  
  375.  
  376. int pg_authenticate_basic_user (request_rec *r)
  377. {
  378.     pg_auth_config_rec *sec =
  379.       (pg_auth_config_rec *)get_module_config (r->per_dir_config,
  380.                         &pg95_auth_module);
  381.     conn_rec *c = r->connection;
  382.     char *sent_pw, *real_pw;
  383.     int res;
  384.     
  385.     pg_errstr[0]='\0';
  386.  
  387.     if ((res = get_basic_auth_pw (r, &sent_pw)))
  388.         return res;
  389.  
  390.     /* if *password* checking is configured in any way, i.e. then
  391.      * handle it, if not decline and leave it to the next in line..  
  392.      * We do not check on dbase, group, userid or host name, as it is
  393.      * perfectly possible to only do group control and leave
  394.      * user control to the next (dbm) guy in line.
  395.      */
  396.     if (
  397.         (!sec->auth_pg_pwd_table) && 
  398.         (!sec->auth_pg_pwd_field) 
  399.      ) return DECLINED;
  400.  
  401.     if(!(real_pw = get_pg_pw(r, c->user, sec ))) {
  402.     if ( pg_errstr[0] ) {
  403.         res = SERVER_ERROR;
  404.         } else {
  405.             sprintf(pg_errstr,"PG: Password for user %s not found", c->user);
  406.         note_basic_auth_failure (r);
  407.         res = AUTH_REQUIRED;
  408.         };
  409.     log_reason (pg_errstr, r->filename, r);
  410.     return res;
  411.     }    
  412.  
  413.     /* allow no password, if the flag is set and the password
  414.      * is empty. But be sure to log this.
  415.      */
  416.  
  417.     if ((sec->auth_pg_nopasswd) && (!strlen(real_pw))) {
  418.         sprintf(pg_errstr,"PG: user %s: Empty password accepted",c->user);
  419.     log_reason (pg_errstr, r->uri, r);
  420.     return OK;
  421.     };
  422.  
  423.     /* if the flag is off however, keep that kind of stuff at
  424.      * an arms length.
  425.      */
  426.     if ((!strlen(real_pw)) || (!strlen(sent_pw))) {
  427.         sprintf(pg_errstr,"PG: user %s: Empty Password(s) Rejected",c->user);
  428.     log_reason (pg_errstr, r->uri, r);
  429.     note_basic_auth_failure (r);
  430.     return AUTH_REQUIRED;
  431.     };
  432.  
  433.     /* anyone know where the prototype for crypt is? */
  434.     if(strcmp(real_pw,(char *)crypt(sent_pw,real_pw))) {
  435.         sprintf(pg_errstr,"PG user %s: password mismatch",c->user);
  436.     log_reason (pg_errstr, r->uri, r);
  437.     note_basic_auth_failure (r);
  438.     return AUTH_REQUIRED;
  439.     }
  440.     return OK;
  441. }
  442.     
  443. /* Checking ID */
  444.     
  445. int pg_check_auth(request_rec *r) {
  446.     pg_auth_config_rec *sec =
  447.       (pg_auth_config_rec *)get_module_config (r->per_dir_config,
  448.                         &pg95_auth_module);
  449.     char *user = r->connection->user;
  450.     int m = r->method_number;
  451.  
  452.  
  453.     array_header *reqs_arr = requires (r);
  454.     require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL;
  455.  
  456.     register int x,res;
  457.     char *t, *w;
  458.  
  459.     pg_errstr[0]='\0';
  460.  
  461.     /* if we cannot do it; leave it to some other guy 
  462.      */
  463.     if ((!sec->auth_pg_grp_table)&&(!sec->auth_pg_grp_field)) 
  464.     return DECLINED;
  465.  
  466.     if (!reqs_arr) return DECLINED;
  467.     
  468.     for(x=0; x < reqs_arr->nelts; x++) {
  469.       
  470.     if (! (reqs[x].method_mask & (1 << m))) continue;
  471.     
  472.         t = reqs[x].requirement;
  473.         w = getword(r->pool, &t, ' ');
  474.     
  475.         if(!strcmp(w,"valid-user"))
  476.             return OK;
  477.  
  478.         if(!strcmp(w,"user")) {
  479.             while(t[0]) {
  480.                 w = getword_conf (r->pool, &t);
  481.                 if(!strcmp(user,w))
  482.                     return OK;
  483.             }
  484.         }
  485.  
  486.         if (!strcmp(w,"group")) {
  487.        /* look up the membership for each of the groups in the table */
  488.            while(t[0]) {
  489.                 if (get_pg_grp(r,getword(r->pool, &t, ' '),user,sec)) {
  490.             return OK;
  491.             };
  492.                };
  493.        if (pg_errstr[0]) {
  494.         res = SERVER_ERROR;
  495.         } else {
  496.                sprintf(pg_errstr,"user %s not in right groups (%s) ",user,w);
  497.                note_basic_auth_failure(r);
  498.         res = AUTH_REQUIRED;
  499.         };
  500.        log_reason (pg_errstr, r->filename, r);
  501.        return res;
  502.            }
  503.         }
  504.     
  505.     return DECLINED;
  506. }
  507.  
  508.  
  509. module pg95_auth_module = {
  510.    STANDARD_MODULE_STUFF,
  511.    NULL,            /* initializer */
  512.    create_pg_auth_dir_config,    /* dir config creater */
  513.    NULL,            /* dir merger --- default is to override */
  514.    NULL,            /* server config */
  515.    NULL,            /* merge server config */
  516.    pg_auth_cmds,        /* command table */
  517.    NULL,            /* handlers */
  518.    NULL,            /* filename translation */
  519.    pg_authenticate_basic_user,    /* check_user_id */
  520.    pg_check_auth,        /* check auth */
  521.    NULL,            /* check access */
  522.    NULL,            /* type_checker */
  523.    NULL,            /* pre-run fixups */
  524.    NULL                /* logger */
  525. };
  526.