void jaxer_add_env_vars(request_rec * r) { /* * Add additonal vars that are needed by jaxer. * REMOTE_USER * REMOTE_HOST * STATUS_CODE * HTTPS */ apr_table_t *env = r->subprocess_env; jaxer_dir_conf *config = ap_get_module_config(r->per_dir_config, &jaxer_module); int is_ip; int ssl_on; const char * ru = ap_get_remote_logname(r); #ifndef APACHE1_3 const char * rh = ap_get_remote_host(r->connection, config, REMOTE_NAME, &is_ip); #else const char * rh = ap_get_remote_host(r->connection, config, REMOTE_NAME); #endif if (ru) apr_table_setn(env, "REMOTE_USER", ru); // else // apr_table_setn(env, "REMOTE_USER", ""); if (rh && !is_ip) ap_table_setn(env, "REMOTE_HOST", rh); ap_table_setn(env, "STATUS_CODE", ap_psprintf(r->pool, "%d", r->status)); ssl_on = jaxer_conn_is_https(r->connection); ap_table_setn(env, "HTTPS", ap_psprintf(r->pool, "%s", (ssl_on != 0)? "on" : "off" )); }
static int psx_auth_fail(request_rec *r, qEnvApache *renv) { // this is kinda wrong.... but for now we keep it.... if (!r->header_only) { CStr resp = renv->GetCtx()->Eval("http-noauth"); if (!resp.IsEmpty()) { qStrBuf bufin(resp); qStrBuf bufout; renv->GetCtx()->ParseTry(&bufin, &bufout); ap_custom_response(r, HTTP_UNAUTHORIZED, bufout.GetBuffer()); } } if (!ap_auth_type(r)) { ap_table_setn(r->err_headers_out, r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate", ap_pstrcat(r->pool, "Basic realm=\"", ap_auth_name(r), "\"", NULL)); } else { ap_note_basic_auth_failure(r); } renv->Free(); ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, AP2STATUS r, "returning unauthorized: %d, status : %d", HTTP_UNAUTHORIZED, r->status); return HTTP_UNAUTHORIZED; }
static void *make_config_log_state(pool *p, server_rec *s) { multi_log_state *mls; mls = (multi_log_state *) ap_palloc(p, sizeof(multi_log_state)); mls->config_logs = ap_make_array(p, 1, sizeof(config_log_state)); mls->default_format_string = NULL; mls->default_format = NULL; mls->server_config_logs = NULL; mls->formats = ap_make_table(p, 4); ap_table_setn(mls->formats, "CLF", DEFAULT_LOG_FORMAT); return mls; }
static int mva_translate(request_rec *r) { mva_sconf_t *conf; const char *name, *map, *uri; mva_mode_e mode; const char *cgi; conf = (mva_sconf_t *) ap_get_module_config(r->server->module_config, &vhost_alias_module); cgi = NULL; if (conf->cgi_root) { cgi = strstr(r->uri, "cgi-bin/"); if (cgi && (cgi != r->uri + strspn(r->uri, "/"))) { cgi = NULL; } } if (cgi) { mode = conf->cgi_root_mode; map = conf->cgi_root; uri = cgi + strlen("cgi-bin"); } else if (r->uri[0] == '/') { mode = conf->doc_root_mode; map = conf->doc_root; uri = r->uri; } else { return DECLINED; } if (mode == VHOST_ALIAS_NAME) { name = ap_get_server_name(r); } else if (mode == VHOST_ALIAS_IP) { name = r->connection->local_ip; } else { return DECLINED; } vhost_alias_interpolate(r, name, map, uri); if (cgi) { /* see is_scriptaliased() in mod_cgi */ r->handler = "cgi-script"; ap_table_setn(r->notes, "alias-forced-type", r->handler); } return OK; }
/* * Set the default logfile format, or define a nickname for a format string. */ static const char *log_format(cmd_parms *cmd, void *dummy, char *fmt, char *name) { const char *err_string = NULL; multi_log_state *mls = ap_get_module_config(cmd->server->module_config, &config_log_module); /* * If we were given two arguments, the second is a name to be given to the * format. This syntax just defines the nickname - it doesn't actually * make the format the default. */ if (name != NULL) { parse_log_string(cmd->pool, fmt, &err_string); if (err_string == NULL) { ap_table_setn(mls->formats, name, fmt); } } else { mls->default_format_string = fmt; mls->default_format = parse_log_string(cmd->pool, fmt, &err_string); } return err_string; }
static table *groups_for_user(pool *p, char *user, char *grpfile) { configfile_t *f; table *grps = ap_make_table(p, 15); pool *sp; char l[MAX_STRING_LEN]; const char *group_name, *ll, *w; if (!(f = ap_pcfg_openfile(p, grpfile))) { /*add? aplog_error(APLOG_MARK, APLOG_ERR, NULL, "Could not open group file: %s", grpfile);*/ return NULL; } sp = ap_make_sub_pool(p); while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) { if ((l[0] == '#') || (!l[0])) continue; ll = l; ap_clear_pool(sp); group_name = ap_getword(sp, &ll, ':'); while (ll[0]) { w = ap_getword_conf(sp, &ll); if (!strcmp(w, user)) { ap_table_setn(grps, ap_pstrdup(p, group_name), "in"); break; } } } ap_cfg_closefile(f); ap_destroy_pool(sp); return grps; }
int isapi_handler (request_rec *r) { LPEXTENSION_CONTROL_BLOCK ecb = ap_pcalloc(r->pool, sizeof(struct _EXTENSION_CONTROL_BLOCK)); HSE_VERSION_INFO *pVer = ap_pcalloc(r->pool, sizeof(HSE_VERSION_INFO)); HINSTANCE isapi_handle; BOOL (*isapi_version)(HSE_VERSION_INFO *); /* entry point 1 */ DWORD (*isapi_entry)(LPEXTENSION_CONTROL_BLOCK); /* entry point 2 */ BOOL (*isapi_term)(DWORD); /* optional entry point 3 */ isapi_cid *cid = ap_pcalloc(r->pool, sizeof(isapi_cid)); table *e = r->subprocess_env; DWORD read; char *p; int retval; int res; /* Use similar restrictions as CGIs */ if (!(ap_allow_options(r) & OPT_EXECCGI)) return FORBIDDEN; if (r->finfo.st_mode == 0) return NOT_FOUND; if (S_ISDIR(r->finfo.st_mode)) return FORBIDDEN; if (!(isapi_handle = ap_os_dso_load(r->filename))) { ap_log_rerror(APLOG_MARK, APLOG_ALERT, r, "ISAPI Could not load DLL: %s", r->filename); return SERVER_ERROR; } if (!(isapi_version = (void *)(ap_os_dso_sym(isapi_handle, "GetExtensionVersion")))) { ap_log_rerror(APLOG_MARK, APLOG_ALERT, r, "DLL could not load GetExtensionVersion(): %s", r->filename); ap_os_dso_unload(isapi_handle); return SERVER_ERROR; } if (!(isapi_entry = (void *)(ap_os_dso_sym(isapi_handle, "HttpExtensionProc")))) { ap_log_rerror(APLOG_MARK, APLOG_ALERT, r, "DLL could not load HttpExtensionProc(): %s", r->filename); ap_os_dso_unload(isapi_handle); return SERVER_ERROR; } isapi_term = (void *)(ap_os_dso_sym(isapi_handle, "TerminateExtension")); /* Run GetExtensionVersion() */ if (!(*isapi_version)(pVer)) { ap_log_rerror(APLOG_MARK, APLOG_ALERT, r, "ISAPI GetExtensionVersion() failed: %s", r->filename); ap_os_dso_unload(isapi_handle); return SERVER_ERROR; } /* Set up variables. There are a couple of special cases for ISAPI. * XXX: These were taken verbatim from GetServerVariable, and should * be reviewed carefully. */ ap_add_common_vars(r); ap_add_cgi_vars(r); ap_table_setn(r->subprocess_env, "UNMAPPED_REMOTE_USER", "REMOTE_USER"); ap_table_setn(r->subprocess_env, "SERVER_PORT_SECURE", "0"); ap_table_setn(r->subprocess_env, "URL", r->uri); /* Set up connection ID */ ecb->ConnID = (HCONN)cid; cid->ecb = ecb; cid->r = r; cid->status = 0; ecb->cbSize = sizeof(struct _EXTENSION_CONTROL_BLOCK); ecb->dwVersion = MAKELONG(0, 2); ecb->dwHttpStatusCode = 0; strcpy(ecb->lpszLogData, ""); ecb->lpszMethod = ap_pstrdup(r->pool, r->method); ecb->lpszQueryString = ap_pstrdup(r->pool, ap_table_get(e, "QUERY_STRING")); ecb->lpszPathInfo = ap_pstrdup(r->pool, ap_table_get(e, "PATH_INFO")); ecb->lpszPathTranslated = ap_pstrdup(r->pool, ap_table_get(e, "PATH_TRANSLATED")); ecb->lpszContentType = ap_pstrdup(r->pool, ap_table_get(e, "CONTENT_TYPE")); /* Set up client input */ if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) { if (isapi_term) (*isapi_term)( 2 /* HSE_TERM_MUST_UNLOAD */); ap_os_dso_unload(isapi_handle); return retval; } if (ap_should_client_block(r)) { /* Time to start reading the appropriate amount of data, * and allow the administrator to tweak the number * TODO: add the httpd.conf option for ReadAheadBuffer. */ if (r->remaining) { ecb->cbTotalBytes = r->remaining; if (ecb->cbTotalBytes > ReadAheadBuffer) ecb->cbAvailable = ReadAheadBuffer; else ecb->cbAvailable = ecb->cbTotalBytes; } else { ecb->cbTotalBytes = 0xffffffff; ecb->cbAvailable = ReadAheadBuffer; } ecb->lpbData = ap_pcalloc(r->pool, ecb->cbAvailable + 1); p = ecb->lpbData; read = 0; while (read < ecb->cbAvailable && ((res = ap_get_client_block(r, ecb->lpbData + read, ecb->cbAvailable - read)) > 0)) { read += res; } if (res < 0) { if (isapi_term) (*isapi_term)(HSE_TERM_MUST_UNLOAD); ap_os_dso_unload(isapi_handle); return SERVER_ERROR; } /* Although its not to spec, IIS seems to null-terminate * its lpdData string. So we will too. * * XXX: This must be an issue... backing out the null * from the count of bytes. */ if (res == 0) ecb->cbAvailable = ecb->cbTotalBytes = read; else ecb->cbAvailable = read; ecb->lpbData[read] = '\0'; } else { ecb->cbTotalBytes = 0; ecb->cbAvailable = 0; ecb->lpbData = NULL; } /* Set up the callbacks */ ecb->GetServerVariable = &GetServerVariable; ecb->WriteClient = &WriteClient; ecb->ReadClient = &ReadClient; ecb->ServerSupportFunction = &ServerSupportFunction; /* All right... try and load the sucker */ retval = (*isapi_entry)(ecb); /* Set the status (for logging) */ if (ecb->dwHttpStatusCode) r->status = ecb->dwHttpStatusCode; /* Check for a log message - and log it */ if (ecb->lpszLogData && strcmp(ecb->lpszLogData, "")) ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "ISAPI: %s: %s", ecb->lpszLogData, r->filename); /* Soak up any remaining input */ if (r->remaining > 0) { char argsbuffer[HUGE_STRING_LEN]; while (ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0); } /* All done with the DLL... get rid of it */ if (isapi_term) (*isapi_term)(HSE_TERM_MUST_UNLOAD); ap_os_dso_unload(isapi_handle); switch(retval) { case 0: /* Strange, but MS isapi accepts this as success */ case HSE_STATUS_SUCCESS: case HSE_STATUS_SUCCESS_AND_KEEP_CONN: /* Ignore the keepalive stuff; Apache handles it just fine without * the ISA's "advice". */ if (cid->status) /* We have a special status to return */ return cid->status; return OK; case HSE_STATUS_PENDING: /* We don't support this */ if (LogNotSupported) ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r, "ISAPI asynchronous I/O not supported: %s", r->filename); case HSE_STATUS_ERROR: default: return SERVER_ERROR; } }
static int suphp_handler(request_rec *r) { suphp_conf *sconf; suphp_conf *dconf; #ifdef SUPHP_USE_USERGROUP char *ud_user = NULL; char *ud_group = NULL; int ud_success = 0; #endif struct stat finfo; int rv; char *auth_user = NULL; char *auth_pass = NULL; pool *p; BUFF *script_in, *script_out, *script_err; const char *handler; sconf = ap_get_module_config(r->server->module_config, &suphp_module); dconf = ap_get_module_config(r->per_dir_config, &suphp_module); p = r->main ? r->main->pool : r->pool; /* only handle request if mod_suphp is active for this handler */ /* check only first byte of value (second has to be \0) */ if (r->handler != NULL) { handler = r->handler; } else { handler = r->content_type; } if ((ap_table_get(dconf->handlers, handler) == NULL)) { if ((ap_table_get(sconf->handlers, handler) == NULL) || (*(ap_table_get(sconf->handlers, handler)) == '0')) { return DECLINED; } } else if (*(ap_table_get(dconf->handlers, handler)) == '0') { return DECLINED; } /* check if suPHP is enabled for this request */ if (((sconf->engine != SUPHP_ENGINE_ON) && (dconf->engine != SUPHP_ENGINE_ON)) || ((sconf->engine == SUPHP_ENGINE_ON) && (dconf->engine == SUPHP_ENGINE_OFF))) return DECLINED; /* check if file is existing and accessible */ rv = stat(ap_pstrdup(p, r->filename), &finfo); if (rv == 0) { ; /* do nothing */ } else if (errno == EACCES) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "access to %s denied", r->filename); return HTTP_FORBIDDEN; } else if (errno == ENOENT || errno == ENOTDIR) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "File does not exist: %s", r->filename); return HTTP_NOT_FOUND; } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "could not get fileinfo: %s", r->filename); return HTTP_NOT_FOUND; } #ifdef SUPHP_USE_USERGROUP if ((sconf->target_user == NULL || sconf->target_group == NULL) && (dconf->target_user == NULL || dconf->target_group == NULL)) { /* Identify mod_userdir request As Apache 1.3 does not yet provide a clean way to see whether a request was handled by mod_userdir, we assume this is true for any request beginning with ~ */ int ud_success = 0; /* set to 1 on success */ if (!strncmp("/~", r->uri, 2)) { char *username = ap_pstrdup(r->pool, r->uri + 2); char *pos = strchr(username, '/'); if (pos) { *pos = 0; if (strlen(username)) { struct passwd *pw; struct group *gr; gid_t gid; char *grpname; if ((pw = getpwnam(username)) != NULL) { gid = pw->pw_gid; if ((gr = getgrgid(gid)) != NULL) { grpname = gr->gr_name; } else { if ((grpname = ap_palloc(r->pool, 16)) == NULL) { return HTTP_INTERNAL_SERVER_ERROR; } ap_snprintf(grpname, 16, "#%ld", (long) gid); } ud_user = username; ud_group = grpname; ud_success = 1; } } } } if (!ud_success) { /* This is not a userdir request and user/group are not set, so log the error and return */ ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "No user or group set - set suPHP_UserGroup"); return HTTP_INTERNAL_SERVER_ERROR; } } #endif /* SUPHP_USE_USERGROUP */ /* prepare environment for new process */ ap_add_common_vars(r); ap_add_cgi_vars(r); ap_table_unset(r->subprocess_env, "SUPHP_PHP_CONFIG"); ap_table_unset(r->subprocess_env, "SUPHP_AUTH_USER"); ap_table_unset(r->subprocess_env, "SUPHP_AUTH_PW"); #ifdef SUPHP_USE_USERGROUP ap_table_unset(r->subprocess_env, "SUPHP_USER"); ap_table_unset(r->subprocess_env, "SUPHP_GROUP"); ap_table_unset(r->subprocess_env, "SUPHP_USERDIR_USER"); ap_table_unset(r->subprocess_env, "SUPHP_USERDIR_GROUP"); #endif /* SUPHP_USE_USERGROUP */ if (dconf->php_config) { ap_table_set(r->subprocess_env, "SUPHP_PHP_CONFIG", dconf->php_config); } ap_table_set(r->subprocess_env, "SUPHP_HANDLER", handler); if (r->headers_in) { const char *auth; auth = ap_table_get(r->headers_in, "Authorization"); if (auth && auth[0] != 0 && strncmp(auth, "Basic ", 6) == 0) { char *user; char *pass; user = ap_pbase64decode(p, auth + 6); if (user) { pass = strchr(user, ':'); if (pass) { *pass++ = '\0'; auth_user = ap_pstrdup(p, user); auth_pass = ap_pstrdup(p, pass); } } } } if (auth_user && auth_pass) { ap_table_setn(r->subprocess_env, "SUPHP_AUTH_USER", auth_user); ap_table_setn(r->subprocess_env, "SUPHP_AUTH_PW", auth_pass); } #ifdef SUPHP_USE_USERGROUP if (dconf->target_user) { ap_table_set(r->subprocess_env, "SUPHP_USER", dconf->target_user); } else if (sconf->target_user) { ap_table_set(r->subprocess_env, "SUPHP_USER", sconf->target_user); } else { ap_table_set(r->subprocess_env, "SUPHP_USER", ud_user); } if (dconf->target_group) { ap_table_set(r->subprocess_env, "SUPHP_GROUP", dconf->target_group); } else if (sconf->target_group) { ap_table_set(r->subprocess_env, "SUPHP_GROUP", sconf->target_group); } else { ap_table_set(r->subprocess_env, "SUPHP_GROUP", ud_group); } if (ud_success) { ap_table_set(r->subprocess_env, "SUPHP_USERDIR_USER", ud_user); ap_table_set(r->subprocess_env, "SUPHP_USERDIR_GROUP", ud_group); } #endif /* SUPHP_USE_USERGROUP */ /* Fork child process */ if (!ap_bspawn_child(p, suphp_child, (void *) r, kill_after_timeout, &script_in, &script_out, &script_err)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "couldn't spawn child process for: %s", r->filename); return HTTP_INTERNAL_SERVER_ERROR; } /* Transfer request body to script */ if ((rv = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK) { /* Call failed, return status */ return rv; } if (ap_should_client_block(r)) { char buffer[HUGE_STRING_LEN]; int len_read; ap_hard_timeout("reading request body", r); while ((len_read = ap_get_client_block(r, buffer, HUGE_STRING_LEN)) > 0) { ap_reset_timeout(r); if (ap_bwrite(script_in, buffer, len_read) < len_read) { /* silly script stopped reading, soak up remaining message */ while (ap_get_client_block(r, buffer, HUGE_STRING_LEN) > 0) { /* dump it */ } break; } } ap_bflush(script_in); ap_kill_timeout(r); } ap_bclose(script_in); /* Transfer output from script to client */ if (script_out) { const char *location; char hbuffer[MAX_STRING_LEN]; char buffer[HUGE_STRING_LEN]; rv = ap_scan_script_header_err_buff(r, script_out, hbuffer); if (rv == HTTP_NOT_MODIFIED) { return rv; } else if (rv) { return HTTP_INTERNAL_SERVER_ERROR; } location = ap_table_get(r->headers_out, "Location"); if (location && r->status == 200) { /* Soak up all the script output */ ap_hard_timeout("reading from script", r); while (ap_bgets(buffer, HUGE_STRING_LEN, script_out) > 0) { continue; } ap_kill_timeout(r); ap_bclose(script_out); ap_bclose(script_err); if (location[0] == '/') { /* Redirect has always GET method */ r->method = ap_pstrdup(p, "GET"); r->method_number = M_GET; /* Remove Content-Length - redirect should not read * * request body */ ap_table_unset(r->headers_in, "Content-Length"); /* Do the redirect */ ap_internal_redirect_handler(location, r); return OK; } else { /* Script did not set status 302 - so it does not want * * to send its own body. Simply set redirect status */ return REDIRECT; } } /* Output headers and body */ ap_send_http_header(r); if (!r->header_only) { ap_send_fb(script_out, r); } ap_bclose(script_out); /* Errors have already been logged by child */ ap_bclose(script_err); } return OK; }
static int handle_request(request_rec *r) { tmcdreq_t tmcdreq, *reqp = &tmcdreq; tmcdresp_t *response = NULL; char *command; struct in_addr local_addr; struct in_addr remote_addr; struct sockaddr_in redir_client; int tmcd_status; int status = OK; char *status_line = NULL; char *args = NULL; char *function_args = NULL; char *p; char **argv = NULL; int argc, i; reqp->istcp = 1; reqp->isssl = 1; /* FIXME */ if (strcmp(r->handler, "tmcd")) { status = DECLINED; goto err; } #if 0 r->allowed |= (AP_METHOD_BIT << M_GET); if (r->method_number != M_GET) { status = DECLINED; goto err; } #endif memset(reqp, 0, sizeof(*reqp)); local_addr = r->connection->local_addr.sin_addr; remote_addr = r->connection->remote_addr.sin_addr; reqp->version = 1; /* FIXME need sane default */ tmcd_init(reqp, &local_addr, NULL); command = r->path_info; while (*command && *command == '/') { command++; } if (command[0] == '\0') { status = HTTP_BAD_REQUEST; goto err; } if (r->args) { args = malloc(strlen(r->args) + 1); if (args == NULL) { status = HTTP_INTERNAL_SERVER_ERROR; goto err; } strcpy(args, r->args); argv = make_argv(args, &argc, '&'); if (argv == NULL) { status = HTTP_INTERNAL_SERVER_ERROR; goto err; } for (i = 0; i < argc; i++) { /* Unescape the arguments */ p = args; while (*p) { if (*p == '+') *p = ' '; p++; } status = ap_unescape_url(args); if (status != OK) { goto err; } if (strncasecmp(argv[i], "version=", 8) == 0) { long version; char *end; version = strtol(argv[i] + 8, &end, 10); if (*end != '\0' || *(argv[i] + 8) == '\0') { status = HTTP_BAD_REQUEST; status_line = "Invalid Version"; goto err; } reqp->version = version; } else if (strncasecmp(argv[i], "redirect=", 9) == 0) { if (inet_pton(AF_INET, argv[i] + 9, &redir_client.sin_addr) <= 0) { status = HTTP_BAD_REQUEST; status_line = "Invalid IP Address"; goto err; } /* FIXME info message */ if (remote_addr.s_addr != local_addr.s_addr) { status = HTTP_FORBIDDEN; status_line = "Redirection Not Allowed"; goto err; } remote_addr = redir_client.sin_addr; } else if (strncasecmp(argv[i], "vnodeid=", 8) == 0) { if (strlen(argv[i] + 8) >= sizeof(reqp->vnodeid)) { status = HTTP_BAD_REQUEST; status_line = "Virtual Node ID Too Long"; goto err; } reqp->isvnode = 1; strcpy(reqp->vnodeid, argv[i] + 8); } else if (strncasecmp(argv[i], "args=", 5) == 0) { function_args = argv[i] + 5; } } } /* FIXME handle wanodekey */ if ((tmcd_status = iptonodeid(reqp, remote_addr, NULL))) { if (reqp->isvnode) { status_line = "Invalid Virtual Node"; } else { status_line = "Invalid Node"; } status = HTTP_NOT_FOUND; goto err; } if (reqp->tmcd_redirect[0]) { /* FIXME what if https should be used? */ /* FIXME do I need to specify the args should be passed too? */ char *uri = ap_psprintf(r->pool, "http://%s%s?%s", reqp->tmcd_redirect, r->uri, r->args); ap_table_setn(r->headers_out, "Location", uri); status = HTTP_MOVED_TEMPORARILY; goto done; } tmcd_status = tmcd_handle_request(reqp, &response, command, function_args); if (tmcd_status == TMCD_STATUS_OK) { r->content_type = response->type; ap_set_content_length(r, response->length); /* FIXME doctype */ ap_soft_timeout("tmcd response call trace", r); ap_send_http_header(r); ap_rprintf(r, "%s", response->data); ap_kill_timeout(r); status = OK; goto done; } else { switch(tmcd_status) { case TMCD_STATUS_UNKNOWN_COMMAND: status = HTTP_NOT_FOUND; status_line = "Unknown Command"; break; case TMCD_STATUS_REQUIRES_ENCRYPTION: status = HTTP_FORBIDDEN; status_line = "SSL Required"; break; case TMCD_STATUS_NODE_NOT_ALLOCATED: status = HTTP_FORBIDDEN; status_line = "Node Not Allocated"; break; case TMCD_STATUS_COMMAND_FAILED: status = HTTP_INTERNAL_SERVER_ERROR; if (response && response->data) { status_line = response->data; } break; case TMCD_STATUS_MALLOC_FAILED: status = HTTP_INTERNAL_SERVER_ERROR; break; } goto err; } err: done: if (argv) free(argv); if (args) free(args); if (response) tmcd_free_response(response); if (status_line) { r->status_line = ap_psprintf(r->pool, "%3.3u %s", status, status_line); } return status; }
API_EXPORT(void) ap_add_cgi_vars(request_rec *r) { table *e = r->subprocess_env; ap_table_setn(e, "GATEWAY_INTERFACE", "CGI/1.1"); ap_table_setn(e, "SERVER_PROTOCOL", r->protocol); ap_table_setn(e, "REQUEST_METHOD", r->method); ap_table_setn(e, "QUERY_STRING", r->args ? r->args : ""); ap_table_setn(e, "REQUEST_URI", original_uri(r)); /* Note that the code below special-cases scripts run from includes, * because it "knows" that the sub_request has been hacked to have the * args and path_info of the original request, and not any that may have * come with the script URI in the include command. Ugh. */ if (!strcmp(r->protocol, "INCLUDED")) { ap_table_setn(e, "SCRIPT_NAME", r->uri); if (r->path_info && *r->path_info) { ap_table_setn(e, "PATH_INFO", r->path_info); } } else if (!r->path_info || !*r->path_info) { ap_table_setn(e, "SCRIPT_NAME", r->uri); } else { int path_info_start = ap_find_path_info(r->uri, r->path_info); ap_table_setn(e, "SCRIPT_NAME", ap_pstrndup(r->pool, r->uri, path_info_start)); ap_table_setn(e, "PATH_INFO", r->path_info); } if (r->path_info && r->path_info[0]) { /* * To get PATH_TRANSLATED, treat PATH_INFO as a URI path. * Need to re-escape it for this, since the entire URI was * un-escaped before we determined where the PATH_INFO began. */ request_rec *pa_req; pa_req = ap_sub_req_lookup_uri(ap_escape_uri(r->pool, r->path_info), r); if (pa_req->filename) { #ifdef WIN32 char buffer[HUGE_STRING_LEN]; #endif char *pt = ap_pstrcat(r->pool, pa_req->filename, pa_req->path_info, NULL); #ifdef WIN32 /* We need to make this a real Windows path name */ GetFullPathName(pt, HUGE_STRING_LEN, buffer, NULL); ap_table_setn(e, "PATH_TRANSLATED", ap_pstrdup(r->pool, buffer)); #else ap_table_setn(e, "PATH_TRANSLATED", pt); #endif } ap_destroy_sub_req(pa_req); } }
static int check_speling(request_rec *r) { spconfig *cfg; char *good, *bad, *postgood, *url; int filoc, dotloc, urlen, pglen; DIR *dirp; struct DIR_TYPE *dir_entry; array_header *candidates = NULL; cfg = ap_get_module_config(r->per_dir_config, &speling_module); if (!cfg->enabled) { return DECLINED; } /* We only want to worry about GETs */ if (r->method_number != M_GET) { return DECLINED; } /* We've already got a file of some kind or another */ if (r->proxyreq != NOT_PROXY || (r->finfo.st_mode != 0)) { return DECLINED; } /* This is a sub request - don't mess with it */ if (r->main) { return DECLINED; } /* * The request should end up looking like this: * r->uri: /correct-url/mispelling/more * r->filename: /correct-file/mispelling r->path_info: /more * * So we do this in steps. First break r->filename into two pieces */ filoc = ap_rind(r->filename, '/'); /* * Don't do anything if the request doesn't contain a slash, or * requests "/" */ if (filoc == -1 || strcmp(r->uri, "/") == 0) { return DECLINED; } /* good = /correct-file */ good = ap_pstrndup(r->pool, r->filename, filoc); /* bad = mispelling */ bad = ap_pstrdup(r->pool, r->filename + filoc + 1); /* postgood = mispelling/more */ postgood = ap_pstrcat(r->pool, bad, r->path_info, NULL); urlen = strlen(r->uri); pglen = strlen(postgood); /* Check to see if the URL pieces add up */ if (strcmp(postgood, r->uri + (urlen - pglen))) { return DECLINED; } /* url = /correct-url */ url = ap_pstrndup(r->pool, r->uri, (urlen - pglen)); /* Now open the directory and do ourselves a check... */ dirp = ap_popendir(r->pool, good); if (dirp == NULL) { /* Oops, not a directory... */ return DECLINED; } candidates = ap_make_array(r->pool, 2, sizeof(misspelled_file)); dotloc = ap_ind(bad, '.'); if (dotloc == -1) { dotloc = strlen(bad); } while ((dir_entry = readdir(dirp)) != NULL) { sp_reason q; /* * If we end up with a "fixed" URL which is identical to the * requested one, we must have found a broken symlink or some such. * Do _not_ try to redirect this, it causes a loop! */ if (strcmp(bad, dir_entry->d_name) == 0) { ap_pclosedir(r->pool, dirp); return OK; } /* * miscapitalization errors are checked first (like, e.g., lower case * file, upper case request) */ else if (strcasecmp(bad, dir_entry->d_name) == 0) { misspelled_file *sp_new; sp_new = (misspelled_file *) ap_push_array(candidates); sp_new->name = ap_pstrdup(r->pool, dir_entry->d_name); sp_new->quality = SP_MISCAPITALIZED; } /* * simple typing errors are checked next (like, e.g., * missing/extra/transposed char) */ else if ((q = spdist(bad, dir_entry->d_name)) != SP_VERYDIFFERENT) { misspelled_file *sp_new; sp_new = (misspelled_file *) ap_push_array(candidates); sp_new->name = ap_pstrdup(r->pool, dir_entry->d_name); sp_new->quality = q; } /* * The spdist() should have found the majority of the misspelled * requests. It is of questionable use to continue looking for * files with the same base name, but potentially of totally wrong * type (index.html <-> index.db). * I would propose to not set the WANT_BASENAME_MATCH define. * 08-Aug-1997 <*****@*****.**> * * However, Alexei replied giving some reasons to add it anyway: * > Oh, by the way, I remembered why having the * > extension-stripping-and-matching stuff is a good idea: * > * > If you're using MultiViews, and have a file named foobar.html, * > which you refer to as "foobar", and someone tried to access * > "Foobar", mod_speling won't find it, because it won't find * > anything matching that spelling. With the extension-munging, * > it would locate "foobar.html". Not perfect, but I ran into * > that problem when I first wrote the module. */ else { #ifdef WANT_BASENAME_MATCH /* * Okay... we didn't find anything. Now we take out the hard-core * power tools. There are several cases here. Someone might have * entered a wrong extension (.htm instead of .html or vice * versa) or the document could be negotiated. At any rate, now * we just compare stuff before the first dot. If it matches, we * figure we got us a match. This can result in wrong things if * there are files of different content types but the same prefix * (e.g. foo.gif and foo.html) This code will pick the first one * it finds. Better than a Not Found, though. */ int entloc = ap_ind(dir_entry->d_name, '.'); if (entloc == -1) { entloc = strlen(dir_entry->d_name); } if ((dotloc == entloc) && !strncasecmp(bad, dir_entry->d_name, dotloc)) { misspelled_file *sp_new; sp_new = (misspelled_file *) ap_push_array(candidates); sp_new->name = ap_pstrdup(r->pool, dir_entry->d_name); sp_new->quality = SP_VERYDIFFERENT; } #endif } } ap_pclosedir(r->pool, dirp); if (candidates->nelts != 0) { /* Wow... we found us a mispelling. Construct a fixed url */ char *nuri; const char *ref; misspelled_file *variant = (misspelled_file *) candidates->elts; int i; ref = ap_table_get(r->headers_in, "Referer"); qsort((void *) candidates->elts, candidates->nelts, sizeof(misspelled_file), sort_by_quality); /* * Conditions for immediate redirection: * a) the first candidate was not found by stripping the suffix * AND b) there exists only one candidate OR the best match is not * ambiguous * then return a redirection right away. */ if (variant[0].quality != SP_VERYDIFFERENT && (candidates->nelts == 1 || variant[0].quality != variant[1].quality)) { nuri = ap_escape_uri(r->pool, ap_pstrcat(r->pool, url, variant[0].name, r->path_info, NULL)); if (r->parsed_uri.query) nuri = ap_pstrcat(r->pool, nuri, "?", r->parsed_uri.query, NULL); ap_table_setn(r->headers_out, "Location", ap_construct_url(r->pool, nuri, r)); ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_INFO, r, ref ? "Fixed spelling: %s to %s from %s" : "Fixed spelling: %s to %s", r->uri, nuri, ref); return HTTP_MOVED_PERMANENTLY; } /* * Otherwise, a "[300] Multiple Choices" list with the variants is * returned. */ else { pool *p; table *notes; pool *sub_pool; array_header *t; array_header *v; if (r->main == NULL) { p = r->pool; notes = r->notes; } else { p = r->main->pool; notes = r->main->notes; } sub_pool = ap_make_sub_pool(p); t = ap_make_array(sub_pool, candidates->nelts * 8 + 8, sizeof(char *)); v = ap_make_array(sub_pool, candidates->nelts * 5, sizeof(char *)); /* Generate the response text. */ *(const char **)ap_push_array(t) = "The document name you requested (<code>"; *(const char **)ap_push_array(t) = ap_escape_html(sub_pool, r->uri); *(const char **)ap_push_array(t) = "</code>) could not be found on this server.\n" "However, we found documents with names similar " "to the one you requested.<p>" "Available documents:\n<ul>\n"; for (i = 0; i < candidates->nelts; ++i) { char *vuri; const char *reason; reason = sp_reason_str[(int) (variant[i].quality)]; /* The format isn't very neat... */ vuri = ap_pstrcat(sub_pool, url, variant[i].name, r->path_info, (r->parsed_uri.query != NULL) ? "?" : "", (r->parsed_uri.query != NULL) ? r->parsed_uri.query : "", NULL); *(const char **)ap_push_array(v) = "\""; *(const char **)ap_push_array(v) = ap_escape_uri(sub_pool, vuri); *(const char **)ap_push_array(v) = "\";\""; *(const char **)ap_push_array(v) = reason; *(const char **)ap_push_array(v) = "\""; *(const char **)ap_push_array(t) = "<li><a href=\""; *(const char **)ap_push_array(t) = ap_escape_uri(sub_pool, vuri); *(const char **)ap_push_array(t) = "\">"; *(const char **)ap_push_array(t) = ap_escape_html(sub_pool, vuri); *(const char **)ap_push_array(t) = "</a> ("; *(const char **)ap_push_array(t) = reason; *(const char **)ap_push_array(t) = ")\n"; /* * when we have printed the "close matches" and there are * more "distant matches" (matched by stripping the suffix), * then we insert an additional separator text to suggest * that the user LOOK CLOSELY whether these are really the * files she wanted. */ if (i > 0 && i < candidates->nelts - 1 && variant[i].quality != SP_VERYDIFFERENT && variant[i + 1].quality == SP_VERYDIFFERENT) { *(const char **)ap_push_array(t) = "</ul>\nFurthermore, the following related " "documents were found:\n<ul>\n"; } } *(const char **)ap_push_array(t) = "</ul>\n"; /* If we know there was a referring page, add a note: */ if (ref != NULL) { *(const char **)ap_push_array(t) = "Please consider informing the owner of the " "<a href=\""; *(const char **)ap_push_array(t) = ap_escape_uri(sub_pool, ref); *(const char **)ap_push_array(t) = "\">referring page</a> " "about the broken link.\n"; } /* Pass our table to http_protocol.c (see mod_negotiation): */ ap_table_setn(notes, "variant-list", ap_array_pstrcat(p, t, 0)); ap_table_mergen(r->subprocess_env, "VARIANTS", ap_array_pstrcat(p, v, ',')); ap_destroy_pool(sub_pool); ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_INFO, r, ref ? "Spelling fix: %s: %d candidates from %s" : "Spelling fix: %s: %d candidates", r->uri, candidates->nelts, ref); return HTTP_MULTIPLE_CHOICES; } } return OK; }
static const char *set_user_dir(cmd_parms *cmd, void *dummy, char *arg) { userdir_config *s_cfg; char *username; const char *usernames = arg; char *kw = ap_getword_conf(cmd->pool, &usernames); table *usertable; s_cfg = (userdir_config *) ap_get_module_config(cmd->server->module_config, &userdir_module); /* * Let's do the comparisons once. */ if ((!strcasecmp(kw, "disable")) || (!strcasecmp(kw, "disabled"))) { /* * If there are no usernames specified, this is a global disable - we * need do no more at this point than record the fact. */ if (strlen(usernames) == 0) { s_cfg->globally_disabled = 1; return NULL; } usertable = s_cfg->disabled_users; } else if ((!strcasecmp(kw, "enable")) || (!strcasecmp(kw, "enabled"))) { /* * The "disable" keyword can stand alone or take a list of names, but * the "enable" keyword requires the list. Whinge if it doesn't have * it. */ if (strlen(usernames) == 0) { return "UserDir \"enable\" keyword requires a list of usernames"; } usertable = s_cfg->enabled_users; } else { /* * If the first (only?) value isn't one of our keywords, look at each * config 'word' for validity and copy the entire arg to the userdir * if all paths are valid. */ const char *userdirs = arg; while (*userdirs) { char *thisdir = ap_getword_conf(cmd->pool, &userdirs); if (!ap_os_is_path_absolute(thisdir) && !strchr(thisdir, ':')) { #if defined(WIN32) || defined(NETWARE) return "UserDir must specify an absolute redirect " "or absolute file path"; #else if (strchr(thisdir, '*')) { return "UserDir cannot specify '*' substitution within " "a relative path"; } #endif } } s_cfg->userdir = ap_pstrdup(cmd->pool, arg); #if defined(WIN32) || defined(OS2) || defined(NETWARE) /* These are incomplete paths, so we cannot canonicalize them yet. * but any backslashes will confuse the parser, later, so simply * change them to slash form. */ arg = s_cfg->userdir; while (arg = strchr(arg, '\\')) { *(arg++) = '/'; } #endif return NULL; } /* * Now we just take each word in turn from the command line and add it to * the appropriate table. */ while (*usernames) { username = ap_getword_conf(cmd->pool, &usernames); ap_table_setn(usertable, username, kw); } return NULL; }
static int translate_userdir(request_rec *r) { void *server_conf = r->server->module_config; const userdir_config *s_cfg = (userdir_config *) ap_get_module_config(server_conf, &userdir_module); char *name = r->uri; const char *userdirs = s_cfg->userdir; const char *w, *dname; char *redirect; struct stat statbuf; /* * If the URI doesn't match our basic pattern, we've nothing to do with * it. */ if ((s_cfg->userdir == NULL) || (name[0] != '/') || (name[1] != '~')) { return DECLINED; } dname = name + 2; w = ap_getword(r->pool, &dname, '/'); /* * The 'dname' funny business involves backing it up to capture the '/' * delimiting the "/~user" part from the rest of the URL, in case there * was one (the case where there wasn't being just "GET /~user HTTP/1.0", * for which we don't want to tack on a '/' onto the filename). */ if (dname[-1] == '/') { --dname; } /* * If there's no username, it's not for us. Ignore . and .. as well. */ if ((w[0] == '\0') || ((w[1] == '.') && ((w[2] == '\0') || ((w[2] == '.') && (w[3] == '\0'))))) { return DECLINED; } /* * Nor if there's an username but it's in the disabled list. */ if (ap_table_get(s_cfg->disabled_users, w) != NULL) { return DECLINED; } /* * If there's a global interdiction on UserDirs, check to see if this * name is one of the Blessed. */ if (s_cfg->globally_disabled && (ap_table_get(s_cfg->enabled_users, w) == NULL)) { return DECLINED; } /* * Special cases all checked, onward to normal substitution processing. */ while (*userdirs) { const char *userdir = ap_getword_conf(r->pool, &userdirs); char *filename = NULL; int is_absolute = ap_os_is_path_absolute(userdir); if (strchr(userdir, '*')) { /* token '*' embedded: */ char *x = ap_getword(r->pool, &userdir, '*'); if (is_absolute) { /* token '*' within absolute path * serves [UserDir arg-pre*][user][UserDir arg-post*] * /somepath/ * /somedir + /~smith -> /somepath/smith/somedir */ filename = ap_pstrcat(r->pool, x, w, userdir, NULL); } else if (strchr(x, ':')) { /* token '*' within a redirect path * serves [UserDir arg-pre*][user][UserDir arg-post*] * http://server/user/ * + /~smith/foo -> * http://server/user/smith/foo */ redirect = ap_pstrcat(r->pool, x, w, userdir, dname, NULL); ap_table_setn(r->headers_out, "Location", redirect); return REDIRECT; } else { /* Not a redirect, not an absolute path, '*' token: * serves [homedir]/[UserDir arg] * something/ * /public_html * Shouldn't happen, we trap for this in set_user_dir */ return DECLINED; } } else if (is_absolute) { /* An absolute path, no * token: * serves [UserDir arg]/[user] * /home + /~smith -> /home/smith */ if (userdir[strlen(userdir) - 1] == '/') filename = ap_pstrcat(r->pool, userdir, w, NULL); else filename = ap_pstrcat(r->pool, userdir, "/", w, NULL); } else if (strchr(userdir, ':')) { /* A redirect, not an absolute path, no * token: * serves [UserDir arg]/[user][dname] * http://server/ + /~smith/foo -> http://server/smith/foo */ if (userdir[strlen(userdir) - 1] == '/') { redirect = ap_pstrcat(r->pool, userdir, w, dname, NULL); } else { redirect = ap_pstrcat(r->pool, userdir, "/", w, dname, NULL); } ap_table_setn(r->headers_out, "Location", redirect); return REDIRECT; } else { /* Not a redirect, not an absolute path, no * token: * serves [homedir]/[UserDir arg] * e.g. /~smith -> /home/smith/public_html */ #if defined(WIN32) || defined(NETWARE) /* Need to figure out home dirs on NT and NetWare * Shouldn't happen here, though, we trap for this in set_user_dir */ return DECLINED; #else /* WIN32 & NetWare */ struct passwd *pw; if ((pw = getpwnam(w))) { #ifdef OS2 /* Need to manually add user name for OS/2 */ filename = ap_pstrcat(r->pool, pw->pw_dir, w, "/", userdir, NULL); #else filename = ap_pstrcat(r->pool, pw->pw_dir, "/", userdir, NULL); #endif } #endif /* WIN32 & NetWare */ } /* * Now see if it exists, or we're at the last entry. If we are at the * last entry, then use the filename generated (if there is one) * anyway, in the hope that some handler might handle it. This can be * used, for example, to run a CGI script for the user. */ if (filename && (!*userdirs || stat(filename, &statbuf) != -1)) { r->filename = ap_pstrcat(r->pool, filename, dname, NULL); /* when statbuf contains info on r->filename we can save a syscall * by copying it to r->finfo */ if (*userdirs && dname[0] == 0) { r->finfo = statbuf; } return OK; } } return DECLINED; }
static int ipblock_handler(request_rec *r, int lookup_uri) { #else static int ipblock_handler(request_rec *r) { #endif /* get configuration information */ ipblock_config *cfg = (ipblock_config *) ap_get_module_config(r->server->module_config, &ipblock_module); /* A limit value of 0 or less, by convention, means no limit. */ if (cfg->limit <= 0) return DECLINED; /* loop index variables */ int i; int j; /* running count of number of connections from this address */ int ip_count = 0; #ifdef APACHE2 /* scoreboard data structure */ worker_score *ws_record; #else /* scoreboard data structure */ short_score score_record; #endif /* We decline to handle subrequests: otherwise, in the next step we * could get into an infinite loop. */ if (!ap_is_initial_req(r)) { #ifdef APACHE2 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "SKIPPED: Not initial request"); #else ap_log_rerror(APLOG_MARK, APLOG_DEBUG, r, "SKIPPED: Not initial request"); #endif return DECLINED; } /* Count up the number of connections we are handling right now from this IP address */ #ifdef APACHE2 for (i = 0; i < server_limit; ++i) { for (j = 0; j < thread_limit; ++j) { ws_record = ap_get_scoreboard_worker(i, j); switch (ws_record->status) { case SERVER_BUSY_READ: case SERVER_BUSY_WRITE: case SERVER_BUSY_KEEPALIVE: case SERVER_BUSY_LOG: case SERVER_BUSY_DNS: case SERVER_CLOSING: case SERVER_GRACEFUL: if (strcmp(r->connection->remote_ip, ws_record->client) == 0) ip_count++; break; default: break; } } } #else for (i = 0; i < HARD_SERVER_LIMIT; ++i) { score_record = ap_scoreboard_image->servers[i]; switch (score_record.status) { case SERVER_BUSY_READ: case SERVER_BUSY_WRITE: case SERVER_BUSY_KEEPALIVE: case SERVER_BUSY_DNS: case SERVER_GRACEFUL: if ((strcmp(r->connection->remote_ip, score_record.client) == 0) #ifdef RECORD_FORWARD || (strcmp(ap_table_get(r->headers_in, "X-Forwarded-For"), score_record.fwdclient) == 0) #endif ) { ip_count++; } break; case SERVER_DEAD: case SERVER_READY: case SERVER_STARTING: case SERVER_BUSY_LOG: break; } } #endif /* APACHE2 */ #ifdef APACHE2 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, #else ap_log_rerror(APLOG_MARK, APLOG_DEBUG, r, #endif "vhost: %s uri: %s current: %d limit: %d", r->server->server_hostname, r->uri, ip_count, cfg->limit); if (ip_count > cfg->limit) { #ifdef APACHE2 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Rejected, too many connections from this host."); #else ap_log_rerror(APLOG_MARK, APLOG_INFO, r, "Rejected, too many connections from this host."); #endif /* set an environment variable */ #ifdef APACHE2 apr_table_setn(r->subprocess_env, "BLOCKIP", "1"); #else ap_table_setn(r->subprocess_env, "BLOCKIP", "1"); #endif char *args[4]; args[0] = cfg->cmd; args[1] = r->connection->remote_ip; #ifdef APACHE2 args[2] = apr_psprintf(r->pool, "%d %d %s%s", (int) ip_count, (int) cfg->limit, r->server->server_hostname, r->uri); #else args[2] = ap_psprintf(r->pool, "%d %d %s%s", (int) ip_count, (int) cfg->limit, r->server->server_hostname, r->uri); #endif args[3] = NULL; execve(cfg->cmd, args, NULL); /* return 503 */ return HTTP_SERVICE_UNAVAILABLE; } return OK; }