/* * Copyright 1995, 1998 Perforce Software. * * This file is part of WebKeeper, a perforce client apache module. * * License is hereby granted to use this software and distribute it * freely, as long as this copyright notice is retained and modifications * are clearly marked. * * ALL WARRANTIES ARE HEREBY DISCLAIMED. * * $Id: //guest/seiwald/webkeeper/mod_webkeep.c#3 $ */ /* * mod_webkeep.c: the apache side glue (in C) to the Perforce client * * This module by Perforce Software, from a template by the Apache Group. */ #include "httpd.h" #include "http_config.h" #include "mod_webkeep.h" typedef struct { char *real; char *fake; } alias_entry; typedef struct { array_header *aliases; WebKeepConnect p4; } alias_server_conf; module webkeep_module; static void *create_webkeep_config (pool *p, server_rec *s) { alias_server_conf *a; a = (alias_server_conf *)ap_pcalloc (p, sizeof(alias_server_conf)); a->aliases = ap_make_array (p, 20, sizeof(alias_entry)); a->p4.port = 0; a->p4.user = 0; a->p4.pass = 0; a->p4.client = 0; return a; } static void *merge_webkeep_config (pool *p, void *basev, void *overridesv) { alias_server_conf *a, *b, *o; a = (alias_server_conf *)ap_pcalloc (p, sizeof(alias_server_conf)); b = (alias_server_conf *)basev; o = (alias_server_conf *)overridesv; a->aliases = ap_append_arrays (p, o->aliases, b->aliases); a->p4.port = o->p4.port ? o->p4.port : a->p4.port ? a->p4.port : b->p4.port; a->p4.user = o->p4.user ? o->p4.user : a->p4.user ? a->p4.user : b->p4.user; a->p4.pass = o->p4.pass ? o->p4.pass : a->p4.pass ? a->p4.pass : b->p4.pass; a->p4.client = o->p4.client ? o->p4.client : a->p4.client ? a->p4.client : b->p4.client; return a; } static const char *add_webkeep(cmd_parms *cmd, void *dummy, char *f, char *r) { server_rec *s = cmd->server; alias_server_conf *conf; alias_entry *new; conf = (alias_server_conf *) ap_get_module_config(s->module_config,&webkeep_module); new = ap_push_array (conf->aliases); /* XX r can NOT be relative to DocumentRoot here... compat bug. */ new->fake = f; new->real = r; return NULL; } static const char *port_webkeep(cmd_parms *cmd, void *d, char *f) { server_rec *s = cmd->server; alias_server_conf *conf; conf = (alias_server_conf *) ap_get_module_config(s->module_config,&webkeep_module); conf->p4.port = f; return NULL; } static const char *user_webkeep(cmd_parms *cmd, void *d, char *f) { server_rec *s = cmd->server; alias_server_conf *conf; conf = (alias_server_conf *) ap_get_module_config(s->module_config,&webkeep_module); conf->p4.user = f; return NULL; } static const char *passwd_webkeep(cmd_parms *cmd, void *d, char *f) { server_rec *s = cmd->server; alias_server_conf *conf; conf = (alias_server_conf *) ap_get_module_config(s->module_config,&webkeep_module); conf->p4.pass = f; return NULL; } static const char *client_webkeep(cmd_parms *cmd, void *d, char *f) { server_rec *s = cmd->server; alias_server_conf *conf; conf = (alias_server_conf *) ap_get_module_config(s->module_config,&webkeep_module); conf->p4.client = f; return NULL; } static command_rec alias_cmds[] = { { "WebKeepAlias", add_webkeep, NULL, RSRC_CONF, TAKE2, "a fakename and a depot name"}, { "WebKeepPort", port_webkeep, NULL, RSRC_CONF, TAKE1, "a TCP/IP host:port"}, { "WebKeepUser", user_webkeep, NULL, RSRC_CONF, TAKE1, "a Perforce user name"}, { "WebKeepPasswd", passwd_webkeep, NULL, RSRC_CONF, TAKE1, "a Perforce user password"}, { "WebKeepClient", client_webkeep, NULL, RSRC_CONF, TAKE1, "a Perforce client name"}, { NULL } }; static int alias_matches (char *uri, char *alias_fakename) { char *end_fakename = alias_fakename + strlen (alias_fakename); char *aliasp = alias_fakename, *urip = uri; while (aliasp < end_fakename) { if (*aliasp == '/') { /* any number of '/' in the alias matches any number in * the supplied URI, but there must be at least one... */ if (*urip != '/') return 0; while (*aliasp == '/') ++ aliasp; while (*urip == '/') ++ urip; } else if ( aliasp == end_fakename - 1 && *aliasp == '$') { /* a $ at the end of the fakename means it must match * the IRI exactly: i.e. no initial substring match. */ if (*urip != 0) return 0; ++ aliasp; } else { /* Other characters are compared literally */ if (*urip++ != *aliasp++) return 0; } } /* Check last alias path component matched all the way */ if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/') return 0; /* Return number of characters from URI which matched (may be * greater than length of alias, since we may have matched * doubled slashes) */ return urip - uri; } static int translate_webkeep(request_rec *r) { int i; void *sconf; alias_server_conf *conf; alias_entry *entries; if (r->uri[0] != '/' && r->uri[0] != '\0') return BAD_REQUEST; sconf = r->server->module_config; conf = (alias_server_conf *)ap_get_module_config(sconf, &webkeep_module); entries = (alias_entry *)conf->aliases->elts; for (i = 0; i < conf->aliases->nelts; ++i) { alias_entry *p = &entries[i]; int l = alias_matches (r->uri, p->fake); if (l > 0) { /* * We stash this under webkeep-path, instead of r->filename, * because (a) we have to communicate to our handle_webkeep * that this is one of ours and (b) because filename gets * mangled by the access checking code. There must be a * way around this, but it is buried in the minds of the * apache writers. */ ap_table_set( r->notes, "webkeep-path", ap_pstrcat(r->pool, p->real, r->uri + l, NULL) ); return OK; } } return DECLINED; } /* Webkeeper glue */ /* * Expected protocol: * * Success: * data block with filename/type * one or more text blocks * * Error: * error block */ void webKeepData( WebKeepPrinter *printer, int isBinary ) { request_rec *r = (request_rec *)printer->closure; if( !r->content_type && isBinary ) r->content_type = "application/octet-stream"; /* Now that we've seen the header, we clear the status */ printer->status = OK; ap_send_http_header( r ); } void webKeepError( WebKeepPrinter *printer, char *buf ) { const char *realm; request_rec *r = (request_rec *)printer->closure; /* Recognise various permission problems, and */ /* try to get them to authorize. */ ap_log_reason(buf, r->uri, r); if ( !strstr( buf, "permission" ) && !strstr( buf, "protected namespace" ) && !strstr( buf, "password" ) ) { printer->status = NOT_FOUND; return; } /* Set WWW-Authenticate header */ r->connection->ap_auth_type = "Basic"; realm = printer->p4->port ? printer->p4->port : "perforce"; ap_table_setn( r->err_headers_out, r->proxyreq == STD_PROXY ? "Proxy-Authenticate" : "WWW-Authenticate", ap_pstrcat( r->pool, "Basic realm=\"", realm, "\"", NULL )); /* And return 401 Authorization Required */ printer->status = AUTH_REQUIRED; } void webKeepText( WebKeepPrinter *printer, char *buf, int len ) { request_rec *r = (request_rec *)printer->closure; while( len-- ) ap_rputc( *buf++, r ); } /* The formal handler... */ static int handle_webkeep (request_rec *r) { void *sconf; alias_server_conf *conf; WebKeepPrinter printer; const char *depotPath; const char *user = 0; const char *passwd = 0; const char *auth_line; /* For us? */ if (r->method_number != M_GET) return DECLINED; if (!( depotPath = ap_table_get(r->notes, "webkeep-path") ) ) return DECLINED; /* The mulberry bush. */ sconf = r->server->module_config; conf = (alias_server_conf *)ap_get_module_config(sconf, &webkeep_module); /* User user/passwd if provided in basic auth scheme. */ /* Otherwise, use configured user/passwd. */ if( (auth_line = ap_table_get(r->headers_in, "Authorization")) != 0 ) { if (strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic")) { return AUTH_REQUIRED; } while (*auth_line== ' ' || *auth_line== '\t') auth_line++; passwd = ap_pbase64decode(r->pool, auth_line); user = ap_getword_nulls (r->connection->pool, &passwd, ':'); } /* Start off with NOT_FOUND; cleared once we get the data block */ printer.status = NOT_FOUND; printer.closure = (void *)r; printer.data = webKeepData; printer.text = webKeepText; printer.error = webKeepError; printer.p4 = &conf->p4; webKeepPrint( depotPath, user, passwd, &printer ); return printer.status; } handler_rec webkeep_handlers[] = { { "*/*", handle_webkeep }, { NULL } }; module webkeep_module = { STANDARD_MODULE_STUFF, NULL, /* initializer */ NULL, /* dir config creater */ NULL, /* dir merger --- default is to override */ create_webkeep_config, /* server config */ merge_webkeep_config, /* merge server configs */ alias_cmds, /* command table */ webkeep_handlers, /* handlers */ translate_webkeep, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ NULL /* logger */ };
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#3 | 903 | Perforce staff |
Fix webkeeper's 401 (authentication required) message to include the necessary WWW-Authenticate message, using Steve Vance's invaluable code. This allows the authenticate-via-perforce mechanism to work with less tolerant browsers. |
||
#2 | 525 | Perforce staff |
Upgrade to apache 1.3 (just added ap_ to symbols). Support for passing Basic authentication info through as username/passwd. |
||
#1 | 524 | Perforce staff | Branch for upgrading to webkeeper 1.3. | ||
//guest/perforce_software/webkeeper/mod_webkeep.c | |||||
#1 | 46 | Perforce maintenance | Add WebKeeper source. |