home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 8 / CDACTUAL8.iso / share / os2 / varios / apache / mod_dige.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-07  |  9.8 KB  |  357 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.  * ITS 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.  * mod_digest: MD5 digest authentication
  57.  * 
  58.  * by Alexei Kosut <akosut@nueva.pvt.k12.ca.us>
  59.  * based on mod_auth, by Rob McCool and Robert S. Thau
  60.  *
  61.  */
  62.  
  63. #include "httpd.h"
  64. #include "http_config.h"
  65. #include "http_core.h"
  66. #include "http_log.h"
  67. #include "http_protocol.h"
  68. #include "util_md5.h"
  69.  
  70. typedef struct digest_config_struct {
  71.     char *pwfile;
  72. } digest_config_rec;
  73.  
  74. typedef struct digest_header_struct {
  75.     char *username;
  76.     char *realm;
  77.     char *nonce;
  78.     char *requested_uri;
  79.     char *digest;
  80. } digest_header_rec;
  81.  
  82. void *create_digest_dir_config (pool *p, char *d)
  83. {
  84.     return pcalloc (p, sizeof(digest_config_rec));
  85. }
  86.  
  87. command_rec digest_cmds[] = {
  88. { "AuthDigestFile", set_string_slot,
  89.     (void*)XtOffsetOf(digest_config_rec,pwfile), OR_AUTHCFG, TAKE1, NULL },
  90. { NULL }
  91. };
  92.  
  93. module digest_module;
  94.  
  95. char *get_hash(request_rec *r, char *user, char *auth_pwfile)
  96. {
  97.     FILE *f;
  98.     char l[MAX_STRING_LEN];
  99.     char *rpw, *w, *x;
  100.  
  101.     if(!(f=pfopen(r->pool, auth_pwfile, "r"))) {
  102.         log_reason ("Could not open password file", auth_pwfile, r);
  103.     return NULL;
  104.     }
  105.     while(!(cfg_getline(l,MAX_STRING_LEN,f))) {
  106.         if((l[0] == '#') || (!l[0])) continue;
  107.     rpw = l;
  108.         w = getword(r->pool, &rpw, ':');
  109.     x = getword(r->pool, &rpw, ':');
  110.  
  111.         if(x && w && !strcmp(user,w) && !strcmp(auth_name(r), x)) {
  112.         pfclose(r->pool, f);
  113.             return pstrdup (r->pool, rpw);
  114.     }
  115.     }
  116.     pfclose(r->pool, f);
  117.     return NULL;
  118. }
  119.  
  120. /* Parse the Authorization header, if it exists */
  121.  
  122. int get_digest_rec(request_rec *r, digest_header_rec *response) {
  123.   char *auth_line = table_get(r->headers_in, "Authorization");
  124.   int l;
  125.   int s = 0, vk = 0, vv = 0;
  126.   char *t, *key, *value;
  127.  
  128.   if (!(t = auth_type(r)) || strcasecmp(t, "Digest"))
  129.     return DECLINED;
  130.  
  131.   if (!auth_name (r)) {
  132.     log_reason ("need AuthName", r->uri, r);
  133.     return SERVER_ERROR;
  134.   }
  135.  
  136.   if (!auth_line) {
  137.     note_digest_auth_failure (r);
  138.     return AUTH_REQUIRED;
  139.   }
  140.  
  141.   if (strcmp(getword (r->pool, &auth_line, ' '), "Digest")) {
  142.     /* Client tried to authenticate using wrong auth scheme */
  143.     log_reason ("client used wrong authentication scheme", r->uri, r);
  144.     note_digest_auth_failure (r);
  145.     return AUTH_REQUIRED;
  146.   }
  147.  
  148.   l = strlen(auth_line);
  149.  
  150.   key=palloc(r->pool,l);
  151.   value=palloc(r->pool,l);
  152.  
  153.   /* There's probably a better way to do this, but for the time being... */
  154.  
  155. #define D_KEY 0
  156. #define D_VALUE 1
  157. #define D_STRING 2
  158. #define D_EXIT -1
  159.  
  160.   while (s != D_EXIT) {
  161.     switch (s) {
  162.     case D_STRING:
  163.       if (auth_line[0] == '\"') {
  164.     s = D_VALUE;
  165.       }
  166.       else {
  167.     value[vv] = auth_line[0];
  168.     vv++;
  169.       }
  170.       auth_line++;
  171.       break;
  172.  
  173.     case D_VALUE:
  174.       if (isalnum(auth_line[0])) {
  175.     value[vv] = auth_line[0];
  176.     vv++;
  177.       }
  178.       else if (auth_line[0] == '\"') {
  179.     s = D_STRING;
  180.       }
  181.       else {
  182.     value[vv] = '\0';
  183.  
  184.     if (!strcasecmp(key, "username"))
  185.       response->username = pstrdup(r->pool, value);
  186.     else if (!strcasecmp(key, "realm"))
  187.       response->realm = pstrdup(r->pool, value);
  188.     else if (!strcasecmp(key, "nonce"))
  189.       response->nonce = pstrdup(r->pool, value);
  190.     else if (!strcasecmp(key, "uri"))
  191.       response->requested_uri = pstrdup(r->pool, value);
  192.     else if (!strcasecmp(key, "response"))
  193.       response->digest = pstrdup(r->pool, value);
  194.  
  195.     vv = 0;
  196.     s = D_KEY;
  197.       }
  198.       auth_line++;
  199.       break;
  200.  
  201.     case D_KEY:
  202.       if (isalnum(auth_line[0])) {
  203.     key[vk] = auth_line[0];
  204.     vk++;
  205.       }
  206.       else if (auth_line[0] == '=') {
  207.     key[vk] = '\0';
  208.     vk = 0;
  209.     s = D_VALUE;
  210.       }
  211.       auth_line++;
  212.       break;
  213.     }
  214.  
  215.     if (auth_line[-1] == '\0')
  216.       s = D_EXIT;
  217.   }
  218.  
  219.   if (!response->username || !response->realm || !response->nonce ||
  220.       !response->requested_uri || !response->digest) {
  221.     note_digest_auth_failure (r);
  222.     return AUTH_REQUIRED;
  223.   }
  224.  
  225.   r->connection->user = response->username;
  226.   r->connection->auth_type = "Digest";
  227.  
  228.   return OK;
  229. }
  230.  
  231. /* The actual MD5 code... whee */
  232.  
  233. char *find_digest(request_rec *r, digest_header_rec *h, char *a1) {
  234.   return md5(r->pool,
  235.          (unsigned char *)pstrcat(r->pool, a1, ":", h->nonce, ":", 
  236.               md5(r->pool,
  237.                   (unsigned char *)pstrcat(r->pool,r->method,":",
  238.                                h->requested_uri,NULL)),
  239.                       NULL));
  240. }
  241.  
  242. /* These functions return 0 if client is OK, and proper error status
  243.  * if not... either AUTH_REQUIRED, if we made a check, and it failed, or
  244.  * SERVER_ERROR, if things are so totally confused that we couldn't
  245.  * figure out how to tell if the client is authorized or not.
  246.  *
  247.  * If they return DECLINED, and all other modules also decline, that's
  248.  * treated by the server core as a configuration error, logged and
  249.  * reported as such.
  250.  */
  251.  
  252. /* Determine user ID, and check if it really is that user, for HTTP
  253.  * basic authentication...
  254.  */
  255.  
  256. int authenticate_digest_user (request_rec *r)
  257. {
  258.     digest_config_rec *sec =
  259.       (digest_config_rec *)get_module_config (r->per_dir_config,
  260.                           &digest_module);
  261.     digest_header_rec *response = pcalloc (r->pool, sizeof(digest_header_rec));
  262.     conn_rec *c = r->connection;
  263.     char *a1;
  264.     char errstr[MAX_STRING_LEN];
  265.     int res;
  266.     
  267.     if ((res = get_digest_rec (r, response))) return res;
  268.     
  269.     if(!sec->pwfile) 
  270.         return DECLINED;
  271.     
  272.     if (!(a1 = get_hash(r, c->user, sec->pwfile))) {
  273.         sprintf(errstr,"user %s not found",c->user);
  274.     log_reason (errstr, r->uri, r);
  275.     note_digest_auth_failure (r);
  276.     return AUTH_REQUIRED;
  277.     }
  278.     /* anyone know where the prototype for crypt is? */
  279.     if(strcmp(response->digest, find_digest(r, response, a1))) {
  280.         sprintf(errstr,"user %s: password mismatch",c->user);
  281.     log_reason (errstr, r->uri, r);
  282.     note_digest_auth_failure (r);
  283.     return AUTH_REQUIRED;
  284.     }
  285.     return OK;
  286. }
  287.     
  288. /* Checking ID */
  289.     
  290. int digest_check_auth (request_rec *r) {
  291.     char *user = r->connection->user;
  292.     int m = r->method_number;
  293.     int method_restricted = 0;    
  294.     register int x;
  295.     char *t, *w;
  296.     array_header *reqs_arr;
  297.     require_line *reqs;
  298.  
  299.     if (!(t = auth_type(r)) || strcasecmp(t, "Digest"))
  300.       return DECLINED;
  301.  
  302.     reqs_arr = requires (r);
  303.     /* If there is no "requires" directive, 
  304.      * then any user will do.
  305.      */
  306.     if (!reqs_arr)
  307.         return OK;
  308.     reqs = (require_line *)reqs_arr->elts;
  309.  
  310.     for(x=0; x < reqs_arr->nelts; x++) {
  311.       
  312.     if (! (reqs[x].method_mask & (1 << m))) continue;
  313.     
  314.         method_restricted = 1;
  315.  
  316.     t = reqs[x].requirement;
  317.         w = getword(r->pool, &t, ' ');
  318.         if(!strcmp(w,"valid-user"))
  319.             return OK;
  320.         else if(!strcmp(w,"user")) {
  321.             while(t[0]) {
  322.                 w = getword_conf (r->pool, &t);
  323.                 if(!strcmp(user,w))
  324.                     return OK;
  325.             }
  326.       }
  327.     else
  328.       return DECLINED;
  329.     }
  330.     
  331.     if (!method_restricted)
  332.       return OK;
  333.  
  334.     note_digest_auth_failure(r);
  335.     return AUTH_REQUIRED;
  336. }
  337.  
  338. module digest_module = {
  339.    STANDARD_MODULE_STUFF,
  340.    NULL,            /* initializer */
  341.    create_digest_dir_config,    /* dir config creater */
  342.    NULL,            /* dir merger --- default is to override */
  343.    NULL,            /* server config */
  344.    NULL,            /* merge server config */
  345.    digest_cmds,            /* command table */
  346.    NULL,            /* handlers */
  347.    NULL,            /* filename translation */
  348.    authenticate_digest_user,    /* check_user_id */
  349.    digest_check_auth,        /* check auth */
  350.    NULL,            /* check access */
  351.    NULL,            /* type_checker */
  352.    NULL,            /* fixups */
  353.    NULL                /* logger */
  354. };
  355.  
  356.  
  357.