home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 25 / CDROM25.iso / Share / linux / apache / contrib / modules / probably_obsolete / mod_auth_pg95.c.orig < prev    next >
Encoding:
Text File  |  1998-06-11  |  15.4 KB  |  525 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. char *set_passwd_flag (cmd_parms *cmd, pg_auth_config_rec *sec, int arg) {
  171.     sec->auth_pg_nopasswd=arg;
  172.     return NULL;
  173. }
  174.  
  175. char *pg_set_string_slot (cmd_parms *cmd, char *struct_ptr, char *arg)
  176. {
  177.  
  178.     int offset = (int)cmd->info; 
  179.     *(char **)(struct_ptr + offset) = pstrdup (cmd->pool, arg);
  180.     /* do we want to check anything ? */
  181.     return NULL;
  182. }
  183.  
  184. command_rec pg_auth_cmds[] = {
  185. { "Auth_PGhost", pg_set_string_slot,
  186.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_host),
  187.     OR_AUTHCFG, TAKE1, "The Host must be set to something" },
  188.  
  189. { "Auth_PGdatabase", pg_set_string_slot,
  190.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_database),
  191.     OR_AUTHCFG, TAKE1, "The Database field must be set to something. " },
  192.  
  193. { "Auth_PGport", pg_set_string_slot,
  194.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_port),
  195.     OR_AUTHCFG, TAKE1, "You must specify the postmaster port. " },
  196.  
  197. { "Auth_PGoptions", pg_set_string_slot,
  198.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_options),
  199.     OR_AUTHCFG, TAKE1, "You must give an option string. " },
  200.  
  201. { "Auth_PGpwd_table", pg_set_string_slot,
  202.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_pwd_table),
  203.     OR_AUTHCFG, TAKE1, "You must give a password table name" },
  204.  
  205. { "Auth_PGgrp_table", pg_set_string_slot,
  206.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_grp_table),
  207.     OR_AUTHCFG, TAKE1, "If you want to use groups, you must give a group table name" },
  208.  
  209. { "Auth_PGpwd_field", pg_set_string_slot,
  210.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_pwd_field),
  211.     OR_AUTHCFG, TAKE1, "The Password-field name must be set to something" },
  212.  
  213. { "Auth_PGuid_field", pg_set_string_slot,
  214.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_uname_field),
  215.     OR_AUTHCFG, TAKE1, "The UserID field name must be set to something" },
  216.  
  217. { "Auth_PGgid_field", pg_set_string_slot,
  218.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_grp_field),
  219.     OR_AUTHCFG, TAKE1, 
  220.     "GID field name must be set to something if you want to use groups" },
  221.  
  222. { "Auth_PG_nopasswd", set_passwd_flag, NULL, OR_AUTHCFG, FLAG, 
  223.     "Limited to 'on' or 'off'" },
  224.  
  225. { "Auth_PGgrp_whereclause", pg_set_string_slot,
  226.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_grp_whereclause),
  227.     OR_AUTHCFG, RAW_ARGS,
  228.     "You must give an SQL fragement that can be attached to the end of a where clause" },
  229.  
  230. { "Auth_PGpwd_whereclause", pg_set_string_slot,
  231.     (void*)XtOffsetOf(pg_auth_config_rec, auth_pg_pwd_whereclause),
  232.     OR_AUTHCFG, RAW_ARGS,
  233.     "You must give an SQL fragement that can be attached to the end of a where clause" },
  234.  
  235. { NULL }
  236. };
  237.  
  238. module pg95_auth_module;
  239.  
  240. char pg_errstr[MAX_STRING_LEN];
  241.          /* global errno to be able to handle config/sql 
  242.          * failures separately
  243.          */
  244.  
  245. /* get the password for uname=user, and copy it
  246.  * into r. Assume that user is a string and stored
  247.  * as such in the pg95 database
  248.  */
  249. char *do_pg_query(request_rec *r, char *query, pg_auth_config_rec *sec) {
  250.  
  251.         PGconn        *pg_conn;
  252.     PGresult    *pg_result;
  253.  
  254.     char        *val;
  255.      char         *result=NULL;
  256.  
  257.     pg_errstr[0]='\0';
  258.  
  259.  
  260.     pg_conn = PQsetdb(sec->auth_pg_host, sec->auth_pg_port, sec->auth_pg_options,
  261.              NULL, sec->auth_pg_database);
  262.  
  263.     if (PQstatus(pg_conn) != CONNECTION_OK) {
  264.         sprintf(pg_errstr, "%s", PQerrorMessage(pg_conn));
  265.         return NULL;
  266.     }
  267.  
  268.     pg_result = PQexec(pg_conn, query);
  269.  
  270.     if (pg_result == NULL)
  271.     {
  272.         sprintf(pg_errstr, "%s", PQerrorMessage(pg_conn));
  273.         PQfinish(pg_conn);
  274.         return NULL;
  275.     }
  276.  
  277.     if (PQresultStatus(pg_result) == PGRES_EMPTY_QUERY) {
  278.         PQclear(pg_result);
  279.         PQfinish(pg_conn);
  280.         return NULL;
  281.     }
  282.  
  283.     if (PQresultStatus(pg_result) != PGRES_TUPLES_OK) {
  284.         sprintf(pg_errstr, "%s", PQerrorMessage(pg_conn));
  285.         PQclear(pg_result);
  286.         PQfinish(pg_conn);
  287.         return NULL;
  288.     }
  289.  
  290.     if (PQntuples(pg_result) == 1) {
  291.         val = PQgetvalue(pg_result, 0, 0);
  292.         if (val == NULL) {
  293.             sprintf(pg_errstr, "%s", PQerrorMessage(pg_conn));
  294.             PQclear(pg_result);
  295.             PQfinish(pg_conn);
  296.             return NULL;
  297.         }
  298.  
  299.         if (!(result = (char*)palloc(r->pool, strlen(val)+1))) {
  300.             sprintf (pg_errstr, "Could not get memory for Postgres query.");
  301.             PQclear(pg_result);
  302.             PQfinish(pg_conn);
  303.             return NULL;
  304.         }
  305.  
  306.         strcpy(result, val);
  307.     }
  308.  
  309.     /* ignore errors here ! */
  310.     PQclear(pg_result);
  311.     PQfinish(pg_conn);
  312.     return result;
  313. }
  314.     
  315. char *get_pg_pw(request_rec *r, char *user, pg_auth_config_rec *sec) {
  316.       char         query[MAX_STRING_LEN];
  317.  
  318.     if (
  319.         (!sec->auth_pg_pwd_table) ||
  320.         (!sec->auth_pg_pwd_field) ||
  321.         (!sec->auth_pg_uname_field)
  322.        ) {
  323.         sprintf(pg_errstr,
  324.             "PG: Missing parameters for password lookup: %s%s%s",
  325.             (sec->auth_pg_pwd_table ? "" : "Password table "),
  326.             (sec->auth_pg_pwd_field ? "" : "Password field name "),
  327.             (sec->auth_pg_uname_field ? "" : "UserID field name ")
  328.             );
  329.         return NULL;
  330.         };
  331.  
  332.         sprintf(query,"select %s from %s where %s='%s'",
  333.         sec->auth_pg_pwd_field,
  334.         sec->auth_pg_pwd_table,
  335.         sec->auth_pg_uname_field,
  336.         user);
  337.  
  338.     if (sec->auth_pg_pwd_whereclause)
  339.         sprintf(query, "%s %s", query, sec->auth_pg_pwd_whereclause);
  340.  
  341.     return do_pg_query(r,query,sec);
  342. }       
  343.  
  344. char *get_pg_grp(request_rec *r, char *group,char *user, pg_auth_config_rec *sec) {
  345.       char         query[MAX_STRING_LEN];
  346.  
  347.     if (
  348.         (!sec->auth_pg_grp_table) ||
  349.         (!sec->auth_pg_grp_field) ||
  350.         (!sec->auth_pg_uname_field)
  351.        ) {
  352.         sprintf(pg_errstr,
  353.             "PG: Missing parameters for password lookup: %s%s%s",
  354.             (sec->auth_pg_grp_table ? "" : "Group table "),
  355.             (sec->auth_pg_grp_field ? "" : "GroupID field name "),
  356.             (sec->auth_pg_uname_field ? "" : "UserID field name ")
  357.             );
  358.         return NULL;
  359.         };
  360.  
  361.         sprintf(query,"select %s from %s where %s='%s' and %s='%s'",
  362.         sec->auth_pg_grp_field,
  363.         sec->auth_pg_grp_table,
  364.         sec->auth_pg_uname_field,user,
  365.         sec->auth_pg_grp_field,group
  366.         );
  367.  
  368.     if (sec->auth_pg_grp_whereclause)
  369.         sprintf(query, "%s %s", sec->auth_pg_grp_whereclause);
  370.  
  371.     return do_pg_query(r,query,sec);
  372. }       
  373.  
  374.  
  375. int pg_authenticate_basic_user (request_rec *r)
  376. {
  377.     pg_auth_config_rec *sec =
  378.       (pg_auth_config_rec *)get_module_config (r->per_dir_config,
  379.                         &pg95_auth_module);
  380.     conn_rec *c = r->connection;
  381.     char *sent_pw, *real_pw, *colon_pw;
  382.     int res;
  383.     
  384.     pg_errstr[0]='\0';
  385.  
  386.     if ((res = get_basic_auth_pw (r, &sent_pw)))
  387.         return res;
  388.  
  389.     /* if *password* checking is configured in any way, i.e. then
  390.      * handle it, if not decline and leave it to the next in line..  
  391.      * We do not check on dbase, group, userid or host name, as it is
  392.      * perfectly possible to only do group control and leave
  393.      * user control to the next (dbm) guy in line.
  394.      */
  395.     if (
  396.         (!sec->auth_pg_pwd_table) && 
  397.         (!sec->auth_pg_pwd_field) 
  398.      ) return DECLINED;
  399.  
  400.     if(!(real_pw = get_pg_pw(r, c->user, sec ))) {
  401.     if ( pg_errstr[0] ) {
  402.         res = SERVER_ERROR;
  403.         } else {
  404.             sprintf(pg_errstr,"PG: Password for user %s not found", c->user);
  405.         note_basic_auth_failure (r);
  406.         res = AUTH_REQUIRED;
  407.         };
  408.     log_reason (pg_errstr, r->filename, r);
  409.     return res;
  410.     }    
  411.  
  412.     /* allow no password, if the flag is set and the password
  413.      * is empty. But be sure to log this.
  414.      */
  415.  
  416.     if ((sec->auth_pg_nopasswd) && (!strlen(real_pw))) {
  417.         sprintf(pg_errstr,"PG: user %s: Empty password accepted",c->user);
  418.     log_reason (pg_errstr, r->uri, r);
  419.     return OK;
  420.     };
  421.  
  422.     /* if the flag is off however, keep that kind of stuff at
  423.      * an arms length.
  424.      */
  425.     if ((!strlen(real_pw)) || (!strlen(sent_pw))) {
  426.         sprintf(pg_errstr,"PG: user %s: Empty Password(s) Rejected",c->user);
  427.     log_reason (pg_errstr, r->uri, r);
  428.     note_basic_auth_failure (r);
  429.     return AUTH_REQUIRED;
  430.     };
  431.  
  432.     /* anyone know where the prototype for crypt is? */
  433.     if(strcmp(real_pw,(char *)crypt(sent_pw,real_pw))) {
  434.         sprintf(pg_errstr,"PG user %s: password mismatch",c->user);
  435.     log_reason (pg_errstr, r->uri, r);
  436.     note_basic_auth_failure (r);
  437.     return AUTH_REQUIRED;
  438.     }
  439.     return OK;
  440. }
  441.     
  442. /* Checking ID */
  443.     
  444. int pg_check_auth(request_rec *r) {
  445.     pg_auth_config_rec *sec =
  446.       (pg_auth_config_rec *)get_module_config (r->per_dir_config,
  447.                         &pg95_auth_module);
  448.     char *user = r->connection->user;
  449.     int m = r->method_number;
  450.  
  451.  
  452.     array_header *reqs_arr = requires (r);
  453.     require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL;
  454.  
  455.     register int x,res;
  456.     char *t, *w;
  457.  
  458.     pg_errstr[0]='\0';
  459.  
  460.     /* if we cannot do it; leave it to some other guy 
  461.      */
  462.     if ((!sec->auth_pg_grp_table)&&(!sec->auth_pg_grp_field)) 
  463.     return DECLINED;
  464.  
  465.     if (!reqs_arr) return DECLINED;
  466.     
  467.     for(x=0; x < reqs_arr->nelts; x++) {
  468.       
  469.     if (! (reqs[x].method_mask & (1 << m))) continue;
  470.     
  471.         t = reqs[x].requirement;
  472.         w = getword(r->pool, &t, ' ');
  473.     
  474.         if(!strcmp(w,"valid-user"))
  475.             return OK;
  476.  
  477.         if(!strcmp(w,"user")) {
  478.             while(t[0]) {
  479.                 w = getword_conf (r->pool, &t);
  480.                 if(!strcmp(user,w))
  481.                     return OK;
  482.             }
  483.         }
  484.  
  485.         if (!strcmp(w,"group")) {
  486.        /* look up the membership for each of the groups in the table */
  487.            while(t[0]) {
  488.                 if (get_pg_grp(r,getword(r->pool, &t, ' '),user,sec)) {
  489.             return OK;
  490.             };
  491.                };
  492.        if (pg_errstr[0]) {
  493.         res = SERVER_ERROR;
  494.         } else {
  495.                sprintf(pg_errstr,"user %s not in right groups (%s) ",user,w);
  496.                note_basic_auth_failure(r);
  497.         res = AUTH_REQUIRED;
  498.         };
  499.        log_reason (pg_errstr, r->filename, r);
  500.        return res;
  501.            }
  502.         }
  503.     
  504.     return DECLINED;
  505. }
  506.  
  507.  
  508. module pg95_auth_module = {
  509.    STANDARD_MODULE_STUFF,
  510.    NULL,            /* initializer */
  511.    create_pg_auth_dir_config,    /* dir config creater */
  512.    NULL,            /* dir merger --- default is to override */
  513.    NULL,            /* server config */
  514.    NULL,            /* merge server config */
  515.    pg_auth_cmds,        /* command table */
  516.    NULL,            /* handlers */
  517.    NULL,            /* filename translation */
  518.    pg_authenticate_basic_user,    /* check_user_id */
  519.    pg_check_auth,        /* check auth */
  520.    NULL,            /* check access */
  521.    NULL,            /* type_checker */
  522.    NULL,            /* pre-run fixups */
  523.    NULL                /* logger */
  524. };
  525.