PUBLIC int HTMIME_contentType (HTRequest * request, HTResponse * response, char * token, char * value) { char * field; if ((field = HTNextField(&value)) != NULL) { /* Get the Content-Type */ char *lc = field; while ((*lc = TOLOWER(*lc))) lc++; HTResponse_setFormat(response, HTAtom_for(field)); /* Get all the parameters to the Content-Type */ { char * param; while ((field = HTNextField(&value)) != NULL && (param = HTNextField(&value)) != NULL) { lc = field; while ((*lc = TOLOWER(*lc))) lc++; lc = param; while ((*lc = TOLOWER(*lc))) lc++; HTResponse_addFormatParam(response, field, param); } } } return HT_OK; }
PUBLIC int HTMIME_cacheControl (HTRequest * request, HTResponse * response, char * token, char * value) { /* ** Walk through the set of cache-control directives and add them to the ** response association list for cache control directives */ char * name_val; while ((name_val = HTNextPair(&value)) != NULL) { char * name = HTNextField(&name_val); char * val = HTNextField(&name_val); if (name) HTResponse_addCacheControl(response, name, val ? val : ""); } return HT_OK; }
/* ** Find the next s-expression token from a string of characters. ** We return the name of this expression and the param points to the ** parameters. ** ** NOTE: The string has been mutilated by '/0's */ char* HTNextSExp (char** exp, char** param) { char* p = *exp; char* name = NULL; if (!exp || !*exp) return NULL; while (*p && isspace((int) *p)) p++; /* Strip leading white space */ if (!*p) { *exp = p; return NULL; /* No field */ } if (*p == '{') { /* Open bracket */ int cnt = 1; /* ** Look for name of this expression. If we find a token then search ** for the rest of the expression and remove the end '}' */ p++; if ((name = HTNextField(&p)) == NULL) return NULL; while (*p && isspace((int) *p)) p++; *param = p; while (*p) { if (*p == '{') cnt++; if (*p == '}') cnt--; if (!cnt) { *p = '\0'; break; } p++; } } return name; }
PUBLIC int HTMIME_contentLength (HTRequest * request, HTResponse * response, char * token, char * value) { char * field; if ((field = HTNextField(&value)) != NULL) HTResponse_setLength(response, atol(field)); return HT_OK; }
PUBLIC int HTMIME_contentRange (HTRequest * request, HTResponse * response, char * token, char * value) { char * field; if ((field = HTNextField(&value))) HTResponse_addRange(response, field, value); return HT_OK; }
PUBLIC char * HTResponse_etag (HTResponse * me) { if (me && me->headers) { char * value = HTAssocList_findObject(me->headers, "etag"); char * etag = HTNextField(&value); return etag; } return NULL; }
PUBLIC int HTMIME_authenticate (HTRequest * request, HTResponse * response, char * token, char * value) { char * scheme = HTNextField(&value); if (scheme) { HTResponse_addChallenge(response, scheme, value); HTResponse_setScheme(response, scheme); } return HT_OK; }
PUBLIC int HTMIME_contentTransferEncoding (HTRequest * request, HTResponse * response, char * token, char * value) { char * field; if ((field = HTNextField(&value)) != NULL) { char *lc = field; while ((*lc = TOLOWER(*lc))) lc++; HTResponse_setContentTransferEncoding(response, HTAtom_for(field)); } return HT_OK; }
/* ** Scan the request line for METHOD, URI and VERSION ** Returns: HT_OK if 1.x request and OK ** HT_LOADED if 0.9 request and OK ** HT_ERROR if invalid request line */ PRIVATE int ParseRequest (HTStream * me) { HTRequest * client = HTList_firstObject(me->http->clients); char * line = HTChunk_data(me->buffer); char * method_str = HTNextField(&line); char * request_uri = HTNextField(&line); char * version_str = HTNextField(&line); HTMethod method; /* Check if method is allowed */ if (!method_str || (method = HTMethod_enum(method_str))==METHOD_INVALID) { HTRequest_addError(client, ERR_FATAL, NO, HTERR_NOT_ALLOWED, NULL, 0, "ParseRequest"); return HT_ERROR; } HTRequest_setMethod(client, method); /* Find an anchor for the request URI */ if (request_uri) { char * uri = HTParse(request_uri, "file:", PARSE_ALL); HTRequest_setAnchor(client, HTAnchor_findAddress(uri)); HT_FREE(uri); } else { HTRequest_addError(client, ERR_FATAL, NO, HTERR_BAD_REQUEST, NULL, 0, "ParseRequest"); return HT_ERROR; } /* Get ready to get the rest of the request */ if (version_str) { me->target = HTStreamStack(WWW_MIME_HEAD, HTRequest_debugFormat(client), HTRequest_debugStream(client), client, NO); return HT_OK; } else { HTRequest_addError(client, ERR_FATAL, NO, HTERR_BAD_VERSION, NULL, 0, "ParseRequest"); return HT_ERROR; } }
PUBLIC int HTMIME_connection (HTRequest * request, HTResponse * response, char * token, char * value) { /* ** Walk through the set of connection directives and add them to the ** response association list for connection directives */ char * name_val; while ((name_val = HTNextPair(&value)) != NULL) { char * name = HTNextField(&name_val); char * val = HTNextField(&name_val); /* ** If we have a name then look if it is concerning persistent ** connections. If so, then we handle it here, otherwise we leave it ** to somebody else by simply adding it to the list of connection ** tokens. */ if (name) { HTNet * net = HTRequest_net(request); HTHost * host = HTNet_host(net); if (!strcasecomp(name, "close")) { /* HTTP/1.1 */ HTTRACE(STREAM_TRACE, "MIMEParser.. Close received...\n"); HTHost_setCloseNotification(host, YES); } else if (!strcasecomp(name, "keep-alive")) { /* HTTP/1.0 */ /* ** In case this is an HTTP/1.1 server sending keep-alive then ** ignore it. */ if (HTHost_version(host) < HTTP_11) { HTNet_setPersistent(net, YES, HT_TP_SINGLE); HTTRACE(STREAM_TRACE, "MIMEParser.. HTTP/1.0 Keep Alive\n"); } else HTTRACE(STREAM_TRACE, "MIMEParser.. HTTP/1.0 Keep Alive ignored\n"); } else HTResponse_addConnection(response, name, val ? val : ""); } } return HT_OK; }
/* ** Content MD5 */ PUBLIC char * HTAnchor_md5 (HTParentAnchor * me) { if (me) { if (me->content_md5) return *me->content_md5 ? me->content_md5 : NULL; if (me->headers) { char * value = HTAssocList_findObject(me->headers, "content-md5"); char * md5; if ((md5 = HTNextField(&value))) StrAllocCopy(me->content_md5,md5); return me->content_md5; } } return NULL; }
/* ** Title */ PUBLIC const char * HTAnchor_title (HTParentAnchor * me) { if (me) { if (me->title) return *me->title ? me->title : NULL; if (me->headers) { char * value = HTAssocList_findObject(me->headers, "title"); char * title; if ((title = HTNextField(&value))) StrAllocCopy(me->title, title); return me->title; } } return NULL; }
/* ** Derived from */ PUBLIC char * HTAnchor_derived (HTParentAnchor * me) { if (me) { if (me->derived_from) return *me->derived_from ? me->derived_from : NULL; if (me->headers) { char * value = HTAssocList_findObject(me->headers, "derived-from"); char * derived_from; if ((derived_from = HTNextField(&value))) StrAllocCopy(me->derived_from, derived_from); return me->derived_from; } } return NULL; }
/* ** Version */ PUBLIC char * HTAnchor_version (HTParentAnchor * me) { if (me) { if (me->version) return *me->version ? me->version : NULL; if (me->headers) { char * value = HTAssocList_findObject(me->headers, "version"); char * version; if ((version = HTNextField(&value))) StrAllocCopy(me->version, version); return me->version; } } return NULL; }
/* ** Entity Tag */ PUBLIC char * HTAnchor_etag (HTParentAnchor * me) { if (me) { if (me->etag) return *me->etag ? me->etag : NULL; if (me->headers) { char * value = HTAssocList_findObject(me->headers, "etag"); char * etag; if ((etag = HTNextField(&value))) StrAllocCopy(me->etag, etag); return me->etag; } } return me ? me->etag : NULL; }
/* ** Content Language */ PUBLIC HTList * HTAnchor_language (HTParentAnchor * me) { if (me) { if (me->content_language == NULL && me->headers) { char * value = HTAssocList_findObject(me->headers, "content-language"); char * field; if (!me->content_language) me->content_language = HTList_new(); while ((field = HTNextField(&value)) != NULL) { char * lc = field; while ((*lc = TOLOWER(*lc))) lc++; HTList_addObject(me->content_language, HTAtom_for(field)); } } return me->content_language; } return NULL; }
/* ** Allowed methods (Allow) */ PUBLIC HTMethod HTAnchor_allow (HTParentAnchor * me) { if (me) { if (me->allow == 0 && me->headers) { char * value = HTAssocList_findObject(me->headers, "allow"); char * field; /* ** We treat methods allowed on this object as case insensitive ** in case we receive the information over the net - that is - ** in the Allow header. */ while ((field = HTNextField(&value)) != NULL) { HTMethod new_method; if ((new_method = HTMethod_enum(field)) != METHOD_INVALID) me->allow |= new_method; } } return me->allow; } return METHOD_INVALID; }
/* * This function parses the authentication tokens from * the server when the server is requesting HTTP digest * authentication. The tokens are required to generate * a valid authentication response in future HTTP * requests. */ static EST_ERROR est_io_parse_auth_tokens (EST_CTX *ctx, char *hdr) { int rv = EST_ERR_NONE; char *p = hdr; char *token = NULL; char *value = NULL; int diff; errno_t safec_rc; /* * header will come in with the basic or digest field still on the front. * skip over it. */ token = HTNextField(&p); while ((token = HTNextField(&p))) { if (!est_strcasecmp_s(token, "realm")) { if ((value = HTNextField(&p))) { if (EOK != strncpy_s(ctx->realm, MAX_REALM, value, MAX_REALM)) { rv = EST_ERR_INVALID_TOKEN; } } else { rv = EST_ERR_INVALID_TOKEN; } } else if (!est_strcasecmp_s(token, "nonce")) { if ((value = HTNextField(&p))) { if (EOK != strncpy_s(ctx->s_nonce, MAX_NONCE, value, MAX_NONCE)) { rv = EST_ERR_INVALID_TOKEN; } } else { rv = EST_ERR_INVALID_TOKEN; } } else if (!est_strcasecmp_s(token, "qop")) { if ((value = HTNextField(&p))) { if (value[0] == '\0') { EST_LOG_WARN("Unsupported qop value: %s", value); } else { safec_rc = memcmp_s(value, sizeof("auth"), "auth", sizeof("auth"), &diff); if (safec_rc != EOK) { EST_LOG_INFO("memcmp_s error 0x%xO\n", safec_rc); } if (diff && (safec_rc == EOK)) { EST_LOG_WARN("Unsupported qop value: %s", value); } } } else { rv = EST_ERR_INVALID_TOKEN; } } else if (!est_strcasecmp_s(token, "algorithm")) { if ((value = HTNextField(&p)) && est_strcasecmp_s(value, "md5")) { EST_LOG_ERR("Unsupported digest algorithm: %s", value); /* ** We only support MD5 for the moment */ rv = EST_ERR_INVALID_TOKEN; } } else if (!est_strcasecmp_s(token, "error")) { if ((value = HTNextField(&p))) { if (EOK != strncpy_s(ctx->token_error, MAX_TOKEN_ERROR, value, MAX_TOKEN_ERROR)) { rv = EST_ERR_INVALID_TOKEN; } } else { rv = EST_ERR_INVALID_TOKEN; } } else if (!est_strcasecmp_s(token, "error_description")) { if ((value = HTNextField(&p))) { if (EOK != strncpy_s(ctx->token_error_desc, MAX_TOKEN_ERROR_DESC, value, MAX_TOKEN_ERROR_DESC)) { rv = EST_ERR_INVALID_TOKEN; } } else { rv = EST_ERR_INVALID_TOKEN; } } else { EST_LOG_WARN("Unsupported auth token ignored: %s", token); } if (rv == EST_ERR_INVALID_TOKEN) { memzero_s(ctx->s_nonce, MAX_NONCE+1); break; } } return (rv); }
/* * This function parses the authentication tokens from * the server when the server is requesting HTTP digest * authentication. The tokens are required to generate * a valid authentication response in future HTTP * requests. */ static EST_ERROR est_io_parse_auth_tokens (EST_CTX *ctx, char *hdr) { int rv = EST_ERR_NONE; char *p = hdr; char *token = NULL; char *value = NULL; /* * header will come in with the basic or digest field still on the front. * skip over it. */ token = HTNextField(&p); while ((token = HTNextField(&p))) { if (!strcasecmp(token, "realm")) { if ((value = HTNextField(&p))) { strncpy(ctx->realm, value, MAX_REALM); } else { rv = EST_ERR_INVALID_TOKEN; } } else if (!strcasecmp(token, "nonce")) { if ((value = HTNextField(&p))) { strncpy(ctx->s_nonce, value, MAX_NONCE); } else { rv = EST_ERR_INVALID_TOKEN; } } else if (!strcasecmp(token, "qop")) { if ((value = HTNextField(&p))) { if (strcmp(value, "auth")) { EST_LOG_WARN("Unsupported qop value: %s", value); } } else { rv = EST_ERR_INVALID_TOKEN; } } else if (!strcasecmp(token, "algorithm")) { if ((value = HTNextField(&p)) && strcasecmp(value, "md5")) { EST_LOG_ERR("Unsupported digest algorithm: %s", value); /* ** We only support MD5 for the moment */ rv = EST_ERR_INVALID_TOKEN; } } else if (!strcasecmp(token, "error")) { if ((value = HTNextField(&p))) { if (!strncpy(ctx->token_error, value, MAX_TOKEN_ERROR)) { rv = EST_ERR_INVALID_TOKEN; } } else { rv = EST_ERR_INVALID_TOKEN; } } else if (!strcasecmp(token, "error_description")) { if ((value = HTNextField(&p))) { if (!strncpy(ctx->token_error_desc, value, MAX_TOKEN_ERROR_DESC)) { rv = EST_ERR_INVALID_TOKEN; } } else { rv = EST_ERR_INVALID_TOKEN; } } else { EST_LOG_WARN("Unsupported auth token ignored: %s", token); } if (rv == EST_ERR_INVALID_TOKEN) { memset(ctx->s_nonce, 0, MAX_NONCE); break; } } return (rv); }
/* Load one line of configuration ** ------------------------------ ** ** Call this, for example, to load a X resource with config info. ** ** returns 0 OK, < 0 syntax error. */ PUBLIC int HTSetConfiguration ARGS1(CONST char *, config) { HTRuleOp op; char * line = NULL; char * pointer = line; char *word1, *word2, *word3; float quality, secs, secs_per_byte; int status; StrAllocCopy(line, config); { char * p = strchr(line, '#'); /* Chop off comments */ if (p) *p = 0; } pointer = line; word1 = HTNextField(&pointer); if (!word1) { free(line); return 0; } ; /* Comment only or blank */ word2 = HTNextField(&pointer); word3 = HTNextField(&pointer); if (!word2) { fprintf(stderr, "HTRule: Insufficient operands: %s\n", line); free(line); return -2; /*syntax error */ } if (0==strcasecomp(word1, "suffix") || 0==strcasecomp(word1, "addtype")) { char * encoding = HTNextField(&pointer); if (pointer) status = sscanf(pointer, "%f", &quality); else status = 0; HTAddType(word2, word3, encoding ? encoding : "binary", status >= 1? quality : 1.0); } else if (0==strcasecomp(word1, "addencoding")) { if (pointer) status = sscanf(pointer, "%f", &quality); else status = 0; HTAddEncoding(word2, word3, status >= 1 ? quality : 1.0); } else if (0==strcasecomp(word1, "addlanguage")) { if (pointer) status = sscanf(pointer, "%f", &quality); else status = 0; HTAddLanguage(word2, word3, status >= 1 ? quality : 1.0); } else if (0==strcasecomp(word1, "presentation")) { if (pointer) status = sscanf(pointer, "%f%f%f", &quality, &secs, &secs_per_byte); else status = 0; if (!HTConversions) HTConversions = HTList_new(); HTSetPresentation(HTConversions, word2, word3, status >= 1? quality : 1.0, status >= 2 ? secs : 0.0, status >= 3 ? secs_per_byte : 0.0 ); } else { op = 0==strcasecomp(word1, "map") ? HT_Map : 0==strcasecomp(word1, "pass") ? HT_Pass : 0==strcasecomp(word1, "fail") ? HT_Fail : HT_Invalid; if (op==HT_Invalid) { CTRACE(stderr, "HTRule: Bad rule `%s'\n", config); } else { HTAddRule(op, word2, word3); } } free(line); return 0; }
/* Load one line of configuration ** ------------------------------ ** Call this, for example, to load a X resource with config info. ** Returns YES if line OK, else NO */ PUBLIC BOOL HTRule_parseLine (HTList * list, const char * config) { HTRuleOp op; char * line = NULL; char * ptr; char * word1, * word2, * word3; int status; if (!config) return NO; if ((ptr = strchr(config, '#'))) *ptr = '\0'; StrAllocCopy(line, config); /* Get our own copy */ ptr = line; HTTRACE(APP_TRACE, "Rule Parse.. `%s\'\n" _ config ? config : "<null>"); if ((word1 = HTNextField(&ptr)) == NULL) { /* Empty line */ HT_FREE(line); return YES; } if ((word2 = HTNextField(&ptr)) == NULL) { HTTRACE(APP_TRACE, "Rule Parse.. Insufficient operands: `%s\'\n" _ line); HT_FREE(line); return NO; } word3 = HTNextField(&ptr); /* Look for things we recognize */ if (!strcasecomp(word1, "addtype")) { double quality; char * encoding = HTNextField(&ptr); status = ptr ? sscanf(ptr, "%lf", &quality) : 0; HTBind_add(word2, /* suffix */ word3, /* type */ encoding ? encoding : "binary", /* encoding */ NULL, /* cte */ NULL, /* language */ status >= 1? quality : 1.0); /* quality */ } else if (!strcasecomp(word1, "addencoding")) { double quality; status = ptr ? sscanf(ptr, "%lf", &quality) : 0; HTBind_addEncoding(word2, word3, status >= 1 ? quality : 1.0); } else if (!strcasecomp(word1, "addlanguage")) { double quality; status = ptr ? sscanf(ptr, "%lf", &quality) : 0; HTBind_addLanguage(word2, word3, status >= 1 ? quality : 1.0); } else if (!strcasecomp(word1, "presentation")) { HTList * converters = HTFormat_conversion(); double quality, secs, secs_per_byte; status = ptr ? sscanf(ptr,"%lf%lf%lf",&quality,&secs,&secs_per_byte):0; HTPresentation_add(converters, word2, word3, NULL, status >= 1 ? quality : 1.0, status >= 2 ? secs : 0.0, status >= 3 ? secs_per_byte : 0.0); } else if (!strcasecomp(word1, "proxy")) { HTProxy_add(word2, word3); } else if (!strcasecomp(word1, "noproxy")) { int port = 0; status = ptr ? sscanf(ptr, "%d", &port) : 0; HTNoProxy_add(word2, word3, port); } else if (!strcasecomp(word1, "gateway")) { HTGateway_add(word2, word3); } else { op = 0==strcasecomp(word1, "map") ? HT_Map : 0==strcasecomp(word1, "pass") ? HT_Pass : 0==strcasecomp(word1, "fail") ? HT_Fail : HT_Invalid; if (op == HT_Invalid) { HTTRACE(APP_TRACE, "Rule Parse.. Bad or unknown: `%s'\n" _ config); } else HTRule_add(list, op, word2, word3); } HT_FREE(line); return YES; }
int main (int argc, char ** argv) { HTSQL * sql = NULL; char * sqlserver = DEFAULT_SQL_SERVER; char * sqldb = DEFAULT_SQL_DB; char * sqluser = DEFAULT_SQL_USER; char * sqlpw = DEFAULT_SQL_PW; char * cvsuser = DEFAULT_CVS_USER; time_t cvsdate = -1; FILE * fin = stdin; char * input_buffer[BUFSIZE]; HTChunk * loginfo = HTChunk_new(BUFSIZE); int arg = 0; BOOL create_db = YES; /* Initiate libwww */ HTLibInit(APP_NAME, APP_VERSION); /* Scan command line for parameters */ for (arg=1; arg<argc; arg++) { if (*argv[arg] == '-') { if (!strcmp(argv[arg], "-h") || !strcmp(argv[arg], "-?")) { VersionInfo(); Cleanup(0, sql, loginfo); } else if (!strcmp(argv[arg], "-v")) { HTSetTraceMessageMask("q"); } else if (!strcmp(argv[arg], "-nocreate")) { create_db = NO; } else if (!strncmp(argv[arg], "-sqldb", 5)) { sqldb = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : DEFAULT_SQL_DB; } else if (!strncmp(argv[arg], "-sqlpassword", 5)) { sqlpw = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : DEFAULT_SQL_PW; } else if (!strncmp(argv[arg], "-sqlserver", 5)) { sqlserver = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : DEFAULT_SQL_SERVER; } else if (!strncmp(argv[arg], "-sqluser", 5)) { sqluser = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : DEFAULT_SQL_USER; } else if (!strncmp(argv[arg], "-cvsuser", 5)) { cvsuser = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : DEFAULT_CVS_USER; } else if (!strncmp(argv[arg], "-cvsdate", 5)) { cvsdate = (arg+1 < argc && *argv[arg+1] != '-') ? HTParseTime(argv[++arg], NULL, NO) : -1; } else { fprintf(stderr, "Bad Argument (%s)\n", argv[arg]); } } else { fprintf(stderr, "Bad Argument (%s)\n", argv[arg]); } } /* Get an SQL object */ if ((sql = HTSQL_new(sqlserver, sqluser, sqlpw, 0)) == NULL) Cleanup(-1, sql, loginfo); /* Connect to the SQL server */ if (HTSQL_connect(sql) != YES) Cleanup(-1, sql, loginfo); /* Select our database */ if (HTSQL_selectDB(sql, sqldb) != YES) Cleanup(-1, sql, loginfo); /* Create our tables */ if (create_db) createTables(sql, 0); /* Read the arguments from stdin */ for (;;) { int status = fread(input_buffer, 1, BUFSIZE, fin); if (status < 0) Cleanup(-1, sql, loginfo); if (status == 0) break; HTChunk_putb(loginfo, (const char *) input_buffer, status); } /* Parse the input chunk */ { char * ptr = HTChunk_data(loginfo); char * noop1 = HTNextField(&ptr); char * noop2 = HTNextField(&ptr); char * root = HTNextField(&ptr); char * operation = NULL; char * files = NULL; char * comment = NULL; int comment_id = -1; int user_id = -1; char * p, * q; #ifdef HT_REENTRANT char *lasts; /* For strtok_r */ #endif /* Find shared log message and get id */ if ((q = HTStrCaseStr(ptr, "\nLog Message:")) != NULL) { comment = q+14; *q = '\0'; } if ((comment_id = add_comment(sql, comment)) < 0) Cleanup(-1, sql, loginfo); /* Add/find user and get id */ if ((user_id = add_user(sql, cvsuser)) < 0) Cleanup(-1, sql, loginfo); /* For each operation, find the files involved */ while ((q = HTStrCaseStr(ptr, " Files:")) != NULL) { /* Find the operation */ files = q+9; for (p=q; p>HTChunk_data(loginfo) && *p && *p!='\n'; p--); p++; operation = HTNextField(&p); /* Find the next line */ if ((q = strchr(files, '\n')) != NULL) { *q++ = '\0'; ptr = q; } /* Create the query */ if (operation && files && comment) { char * file; int location_id = -1; #ifdef HT_REENTRANT if ((file = strtok_r(files, DELIMITERS, &lasts)) != NULL) { #else if ((file = strtok(files, DELIMITERS)) != NULL) { #endif /* HT_REENTRANT */ do { char * path = NULL; StrAllocMCopy(&path, root, "/", file, NULL); /* Add/find location and get id */ if ((location_id = add_location(sql, path)) < 0) { Cleanup(-1, sql, loginfo); break; } #if 0 fprintf(stderr, "location: `%s\', user: `%s\', operation: `%s\', comment: `%s\'\n", path, cvsuser, operation, comment); #endif /* Add log entry */ { char buf[16384]; char * query = HTSQL_printf(buf, 16384, "insert into %s values (%u,%u,%T,%S,%u)", DEFAULT_SQL_LOG_TABLE, location_id, user_id, cvsdate, operation, comment_id); if (HTSQL_query(sql, query) != YES) { Cleanup(-1, sql, loginfo); break; } } HT_FREE(path); #ifdef HT_REENTRANT } while ((file = (char *) strtok_r(NULL, DELIMITERS, &lasts)) != NULL); #else } while ((file = strtok(NULL, DELIMITERS)) != NULL); #endif /* HT_REENTRANT */ } } } } return 0; }
/* Translate by rules HTTranslate() * ------------------ * * The most recently defined rules are applied first. * * On entry, * required points to a string whose equivalent value is needed * On exit, * returns the address of the equivalent string allocated from * the heap which the CALLER MUST FREE. If no translation * occurred, then it is a copy of the original. * NEW FEATURES: * When a "protect" or "defprot" rule is matched, * a call to HTAA_setCurrentProtection() or * HTAA_setDefaultProtection() is made to notify * the Access Authorization module that the file is * protected, and so it knows how to handle it. * -- AL */ char *HTTranslate(const char *required) { rule *r; char *current = NULL; char *msgtmp = NULL; const char *pMsg; int proxy_none_flag = 0; int permitredir_flag = 0; StrAllocCopy(current, required); HTAA_clearProtections(); /* Reset from previous call -- AL */ for (r = rules; r; r = r->next) { char *p = r->pattern; int m = 0; /* Number of characters matched against wildcard */ const char *q = current; for (; *p && *q; p++, q++) { /* Find first mismatch */ if (*p != *q) break; } if (*p == '*') { /* Match up to wildcard */ m = strlen(q) - strlen(p + 1); /* Amount to match to wildcard */ if (m < 0) continue; /* tail is too short to match */ if (0 != strcmp(q + m, p + 1)) continue; /* Tail mismatch */ } else /* Not wildcard */ if (*p != *q) continue; /* plain mismatch: go to next rule */ if (!rule_cond_ok(r)) /* check condition, next rule if false - kw */ continue; switch (r->op) { /* Perform operation */ #ifdef ACCESS_AUTH case HT_DefProt: case HT_Protect: { char *local_copy = NULL; char *p2; char *eff_ids = NULL; char *prot_file = NULL; CTRACE((tfp, "HTRule: `%s' matched %s %s: `%s'\n", current, (r->op == HT_Protect ? "Protect" : "DefProt"), "rule, setup", (r->equiv ? r->equiv : (r->op == HT_Protect ? "DEFAULT" : "NULL!!")))); if (r->equiv) { StrAllocCopy(local_copy, r->equiv); p2 = local_copy; prot_file = HTNextField(&p2); eff_ids = HTNextField(&p2); } if (r->op == HT_Protect) HTAA_setCurrentProtection(current, prot_file, eff_ids); else HTAA_setDefaultProtection(current, prot_file, eff_ids); FREE(local_copy); /* continue translating rules */ } break; #endif /* ACCESS_AUTH */ case HT_UserMsg: /* Produce message immediately */ LYFixCursesOn("show rule message:"); HTUserMsg2((r->equiv ? r->equiv : "Rule: %s"), current); break; case HT_InfoMsg: /* Produce messages immediately */ case HT_Progress: case HT_Alert: LYFixCursesOn("show rule message:"); /* and fall through */ case HT_AlwaysAlert: pMsg = r->equiv ? r->equiv : (r->op == HT_AlwaysAlert) ? "%s" : "Rule: %s"; if (strchr(pMsg, '%')) { HTSprintf0(&msgtmp, pMsg, current); pMsg = msgtmp; } switch (r->op) { /* Actually produce message */ case HT_InfoMsg: HTInfoMsg(pMsg); break; case HT_Progress: HTProgress(pMsg); break; case HT_Alert: HTAlert(pMsg); break; case HT_AlwaysAlert: HTAlwaysAlert("Rule alert:", pMsg); break; default: break; } FREE(msgtmp); break; case HT_PermitRedir: /* Set special flag */ permitredir_flag = 1; CTRACE((tfp, "HTRule: Mark for redirection permitted\n")); break; case HT_Pass: /* Authorised */ if (!r->equiv) { if (proxy_none_flag) { char *temp = NULL; StrAllocCopy(temp, "NoProxy="); StrAllocCat(temp, current); FREE(current); current = temp; } CTRACE((tfp, "HTRule: Pass `%s'\n", current)); return current; } /* Else fall through ...to map and pass */ case HT_Map: case HT_Redirect: case HT_RedirectPerm: if (*p == *q) { /* End of both strings, no wildcard */ CTRACE((tfp, "For `%s' using `%s'\n", current, r->equiv)); StrAllocCopy(current, r->equiv); /* use entire translation */ } else { char *ins = strchr(r->equiv, '*'); /* Insertion point */ if (ins) { /* Consistent rule!!! */ char *temp = NULL; HTSprintf0(&temp, "%.*s%.*s%s", (int) (ins - r->equiv), r->equiv, m, q, ins + 1); CTRACE((tfp, "For `%s' using `%s'\n", current, temp)); FREE(current); current = temp; /* Use this */ } else { /* No insertion point */ char *temp = NULL; StrAllocCopy(temp, r->equiv); CTRACE((tfp, "For `%s' using `%s'\n", current, temp)); FREE(current); current = temp; /* Use this */ } /* If no insertion point exists */ } if (r->op == HT_Pass) { if (proxy_none_flag) { char *temp = NULL; StrAllocCopy(temp, "NoProxy="); StrAllocCat(temp, current); FREE(current); current = temp; } CTRACE((tfp, "HTRule: ...and pass `%s'\n", current)); return current; } else if (r->op == HT_Redirect) { CTRACE((tfp, "HTRule: ...and redirect to `%s'\n", current)); redirecting_url = current; HTPermitRedir = (BOOL) (permitredir_flag == 1); return (char *) 0; } else if (r->op == HT_RedirectPerm) { CTRACE((tfp, "HTRule: ...and redirect like 301 to `%s'\n", current)); redirecting_url = current; permanent_redirection = TRUE; HTPermitRedir = (BOOL) (permitredir_flag == 1); return (char *) 0; } break; case HT_UseProxy: if (r->equiv && 0 == strcasecomp(r->equiv, "none")) { CTRACE((tfp, "For `%s' will not use proxy\n", current)); proxy_none_flag = 1; } else if (proxy_none_flag) { CTRACE((tfp, "For `%s' proxy server ignored: %s\n", current, NONNULL(r->equiv))); } else { char *temp = NULL; StrAllocCopy(temp, "Proxied="); StrAllocCat(temp, r->equiv); StrAllocCat(temp, current); CTRACE((tfp, "HTRule: proxy server found: %s\n", NONNULL(r->equiv))); FREE(current); return temp; } break; case HT_Invalid: case HT_Fail: /* Unauthorised */ CTRACE((tfp, "HTRule: *** FAIL `%s'\n", current)); FREE(current); return (char *) 0; } /* if tail matches ... switch operation */ } /* loop over rules */ if (proxy_none_flag) { char *temp = NULL; StrAllocCopy(temp, "NoProxy="); StrAllocCat(temp, current); FREE(current); return temp; } return current; }
/* Load one line of configuration * ------------------------------ * * Call this, for example, to load a X resource with config info. * * returns 0 OK, < 0 syntax error. */ int HTSetConfiguration(char *config) { HTRuleOp op; char *line = NULL; char *pointer = line; char *word1; const char *word2; const char *word3; const char *cond_op = NULL; const char *cond = NULL; float quality, secs, secs_per_byte; int maxbytes; int status; StrAllocCopy(line, config); { char *p = strchr(line, '#'); /* Chop off comments */ if (p) *p = 0; } pointer = line; word1 = HTNextField(&pointer); if (!word1) { FREE(line); return 0; }; /* Comment only or blank */ word2 = HTNextField(&pointer); if (0 == strcasecomp(word1, "defprot") || 0 == strcasecomp(word1, "protect")) word3 = pointer; /* The rest of the line to be parsed by AA module */ else word3 = HTNextField(&pointer); /* Just the next word */ if (!word2) { fprintf(stderr, "HTRule: %s %s\n", RULE_NEEDS_DATA, line); FREE(line); return -2; /*syntax error */ } if (0 == strcasecomp(word1, "suffix")) { char *encoding = HTNextField(&pointer); if (pointer) status = sscanf(pointer, "%f", &quality); else status = 0; HTSetSuffix(word2, word3, encoding ? encoding : "binary", status >= 1 ? quality : (float) 1.0); } else if (0 == strcasecomp(word1, "presentation")) { if (pointer) status = sscanf(pointer, "%f%f%f%d", &quality, &secs, &secs_per_byte, &maxbytes); else status = 0; HTSetPresentation(word2, word3, NULL, status >= 1 ? quality : 1.0, status >= 2 ? secs : 0.0, status >= 3 ? secs_per_byte : 0.0, status >= 4 ? maxbytes : 0, mediaCFG); } else if (0 == strncasecomp(word1, "htbin", 5) || 0 == strncasecomp(word1, "bindir", 6)) { StrAllocCopy(HTBinDir, word2); /* Physical /htbin location */ } else if (0 == strncasecomp(word1, "search", 6)) { StrAllocCopy(HTSearchScript, word2); /* Search script name */ } else { op = 0 == strcasecomp(word1, "map") ? HT_Map : 0 == strcasecomp(word1, "pass") ? HT_Pass : 0 == strcasecomp(word1, "fail") ? HT_Fail : 0 == strcasecomp(word1, "redirect") ? HT_Redirect : 0 == strncasecomp(word1, "redirectperm", 12) ? HT_RedirectPerm : 0 == strcasecomp(word1, "redirecttemp") ? HT_Redirect : 0 == strcasecomp(word1, "permitredirection") ? HT_PermitRedir : 0 == strcasecomp(word1, "useproxy") ? HT_UseProxy : 0 == strcasecomp(word1, "alert") ? HT_Alert : 0 == strcasecomp(word1, "alwaysalert") ? HT_AlwaysAlert : 0 == strcasecomp(word1, "progress") ? HT_Progress : 0 == strcasecomp(word1, "usermsg") ? HT_UserMsg : 0 == strcasecomp(word1, "infomsg") ? HT_InfoMsg : 0 == strcasecomp(word1, "defprot") ? HT_DefProt : 0 == strcasecomp(word1, "protect") ? HT_Protect : HT_Invalid; if (op == HT_Invalid) { fprintf(stderr, "HTRule: %s '%s'\n", RULE_INCORRECT, config); } else { switch (op) { case HT_Fail: /* never a or other 2nd parameter */ case HT_PermitRedir: cond_op = word3; if (cond_op && *cond_op) { word3 = NULL; cond = HTNextField(&pointer); } break; case HT_Pass: /* possibly a URL2 */ if (word3 && (!strcasecomp(word3, "if") || !strcasecomp(word3, "unless"))) { cond_op = word3; word3 = NULL; cond = HTNextField(&pointer); break; } /* else fall through */ case HT_Map: /* always a URL2 (or other 2nd parameter) */ case HT_Redirect: case HT_RedirectPerm: case HT_UseProxy: cond_op = HTNextField(&pointer); /* check for extra status word in "Redirect" */ if (op == HT_Redirect && 0 == strcasecomp(word1, "redirect") && cond_op && strcasecomp(cond_op, "if") && strcasecomp(cond_op, "unless")) { if (0 == strcmp(word2, "301") || 0 == strcasecomp(word2, "permanent")) { op = HT_RedirectPerm; } else if (!(0 == strcmp(word2, "302") || 0 == strcmp(word2, "303") || 0 == strcasecomp(word2, "temp") || 0 == strcasecomp(word2, "seeother"))) { CTRACE((tfp, "Rule: Ignoring `%s' in Redirect\n", word2)); } word2 = word3; word3 = cond_op; /* cond_op isn't condition op after all */ cond_op = HTNextField(&pointer); } if (cond_op && *cond_op) cond = HTNextField(&pointer); break; case HT_Progress: case HT_InfoMsg: case HT_UserMsg: case HT_Alert: case HT_AlwaysAlert: cond_op = HTNextField(&pointer); if (cond_op && *cond_op) cond = HTNextField(&pointer); if (word3) { /* Fix string with too may %s - kw */ const char *cp = word3; char *cp1, *cp2; while ((cp1 = strchr(cp, '%'))) { if (cp1[1] == '\0') { *cp1 = '\0'; break; } else if (cp1[1] == '%') { cp = cp1 + 2; continue; } else while ((cp2 = strchr(cp1 + 2, '%'))) { if (cp2[1] == '\0') { *cp2 = '\0'; break; } else if (cp2[1] == '%') { cp1 = cp2; } else { *cp2 = '?'; /* replace bad % */ cp1 = cp2; } } break; } } break; default: break; } if (cond_op && cond && *cond && !strcasecomp(cond_op, "unless")) { cond_op = "unless"; } else if (cond_op && cond && *cond && !strcasecomp(cond_op, "if")) { cond_op = "if"; } else if (cond_op || cond) { fprintf(stderr, "HTRule: %s '%s'\n", RULE_INCORRECT, config); FREE(line); /* syntax error, condition is a mess - kw */ return -2; /* NB unrecognized cond passes here - kw */ } if (cond && !strncasecomp(cond, "redirected", strlen(cond))) { cond = "redirected"; /* recognized, canonical case - kw */ } else if (cond && strlen(cond) >= 8 && !strncasecomp(cond, "userspecified", strlen(cond))) { cond = "userspec"; /* also allow abbreviation - kw */ } HTAddRule(op, word2, word3, cond_op, cond); } } FREE(line); return 0; }
/* ** This function maintains backwards compatibility with the old ** environment variables and searches for the most common values: ** http, ftp, news, wais, and gopher */ PUBLIC void HTProxy_getEnvVar (void) { char buf[80]; static const char *accesslist[] = { "http", "ftp", "news", "wais", "gopher", NULL }; const char **access = accesslist; HTTRACE(PROT_TRACE, "Proxy....... Looking for environment variables\n"); while (*access) { BOOL found = NO; char *gateway=NULL; char *proxy=NULL; /* Search for proxy gateways */ if (found == NO) { strcpy(buf, *access); strcat(buf, "_proxy"); if ((proxy = (char *) getenv(buf)) && *proxy) { HTProxy_add(*access, proxy); found = YES; } /* Try the same with upper case */ if (found == NO) { char * up = buf; while ((*up = TOUPPER(*up))) up++; if ((proxy = (char *) getenv(buf)) && *proxy) { HTProxy_add(*access, proxy); found = YES; } } } /* As a last resort, search for gateway servers */ if (found == NO) { strcpy(buf, "WWW_"); strcat(buf, *access); strcat(buf, "_GATEWAY"); if ((gateway = (char *) getenv(buf)) && *gateway) { HTGateway_add(*access, gateway); found = YES; } } ++access; } /* Search for `noproxy' directive */ { char *noproxy = getenv("no_proxy"); if (noproxy && *noproxy) { char *str = NULL; char *strptr; char *name; StrAllocCopy(str, noproxy); /* Get copy we can mutilate */ strptr = str; while ((name = HTNextField(&strptr)) != NULL) { char *portstr = strchr(name, ':'); unsigned port=0; if (portstr) { *portstr++ = '\0'; if (*portstr) port = (unsigned) atoi(portstr); } /* Register it for all access methods */ HTNoProxy_add(name, NULL, port); } HT_FREE(str); } } }