#include "httpd.h"  
#include "http_config.h"  
#include "http_request.h"  
#include "http_protocol.h"  
#include "http_core.h"  
#include "http_main.h" 
#include "http_log.h"  
 
/* 
 * C version of chapter 6's Apache::AuthAny
 * plus util_requires_dump() code from chapter 11
 */ 

/* 
 * configure like so:
 * 
 * LoadModule authany_module modules/mod_authany.so
 * <Location /test>
 * AuthType Basic 
 * AuthName AuthAny 
 * require valid-user 
 * </Location>
 */

#define comma_or_newline(value) \
if(value) fprintf(stderr, ", "); \
else      fprintf(stderr, "\n");

static char *request_methods[] = {
    "GET","PUT","POST","DELETE","CONNECT","OPTIONS","TRACE",
    "PATCH","PROPFIND","PROPPATCH","MKCOL","COPY","MOVE","LOCK","UNLOCK",NULL
};

static void requires_dump(request_rec *r)
{
    const array_header *requires = ap_requires(r);
    require_line *rq;
    int x;

    if (!requires) {
	fprintf(stderr, 
		"requires: there are no requirements for this request\n");
	return;
    }

    rq = (require_line *) requires->elts;

    for (x = 0; x < requires->nelts; x++) {
	const char *line, *requirement;
	int i;

	fprintf(stderr, "requires: limited to request methods: ");
	for(i=0; request_methods[i]; i++) {
	    if (rq[x].method_mask & (1 << i)) 
		fprintf(stderr, "%s ", request_methods[i]);
	}
	fprintf(stderr, "\n");

	line = rq[x].requirement;
	requirement = ap_getword(r->pool, &line, ' ');

	if (!strcmp(requirement, "valid-user")) {
	    fprintf(stderr, "requires: any valid-user allowed here.\n");
	    return;
	}

	if (!strcmp(requirement, "user")) {
	    fprintf(stderr, "requires: allowed users: ");
	    while (line[0]) {
		requirement = ap_getword_conf(r->pool, &line);
		fprintf(stderr, "`%s'", requirement);
		comma_or_newline(line[0]);
	    }
	}

	else if (!strcmp(requirement, "group")) {
	    fprintf(stderr, "requires: allowed groups: ");
	    while (line[0]) {
		requirement = ap_getword_conf(r->pool, &line);
		fprintf(stderr, "`%s'", requirement);
		comma_or_newline(line[0]);
	    }
	}
    }
}

/* do not accept empty "" strings */
#define strtrue(s) (s && *s)

static int authany_handler(request_rec *r)
{
     const char *sent_pw; 
     int rc = ap_get_basic_auth_pw(r, &sent_pw); 
     if(rc != OK) return rc;

     requires_dump(r);

     if(!(strtrue(r->connection->user) && strtrue(sent_pw))) {
	 ap_note_basic_auth_failure(r);  
	 ap_log_reason("Both a username and password must be provided", 
		       r->uri, r);  
	 return HTTP_UNAUTHORIZED;
     }

     return OK;
}

module MODULE_VAR_EXPORT authany_module = {
    STANDARD_MODULE_STUFF, 
    NULL,                  /* module initializer                  */
    NULL,                  /* create per-dir    config structures */
    NULL,                  /* merge  per-dir    config structures */
    NULL,                  /* create per-server config structures */
    NULL,                  /* merge  per-server config structures */
    NULL,                  /* table of config file commands       */
    NULL,                  /* [#8] MIME-typed-dispatched handlers */
    NULL,                  /* [#1] URI to filename translation    */
    authany_handler,       /* [#4] validate user id from request  */
    NULL,                  /* [#5] check if the user is ok _here_ */
    NULL,                  /* [#3] check access by host address   */
    NULL,                  /* [#6] determine MIME type            */
    NULL,                  /* [#7] pre-run fixups                 */
    NULL,                  /* [#9] log a transaction              */
    NULL,                  /* [#2] header parser                  */
    NULL,                  /* child_init                          */
    NULL,                  /* child_exit                          */
    NULL                   /* [#0] post read-request              */
};

