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" )); }
void ssl_scache_shmht_status(server_rec *s, pool *p, void (*func)(char *, void *), void *arg) { SSLModConfigRec *mc = myModConfig(); void *vpKey; void *vpData; int nKey; int nData; int nElem; int nSize; int nAverage; nElem = 0; nSize = 0; ssl_mutex_on(s); if (table_first(mc->tSessionCacheDataTable, &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE) { do { if (vpKey == NULL || vpData == NULL) continue; nElem += 1; nSize += nData; } while (table_next(mc->tSessionCacheDataTable, &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE); } ssl_mutex_off(s); if (nSize > 0 && nElem > 0) nAverage = nSize / nElem; else nAverage = 0; func(ap_psprintf(p, "cache type: <b>SHMHT</b>, maximum size: <b>%d</b> bytes<br>", mc->nSessionCacheDataSize), arg); func(ap_psprintf(p, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize), arg); func(ap_psprintf(p, "average session size: <b>%d</b> bytes<br>", nAverage), arg); return; }
const char * fcgi_util_fs_is_path_ok(pool * const p, const char * const fs_path, struct stat *finfo) { const char *err; if (finfo == NULL) { finfo = (struct stat *)ap_palloc(p, sizeof(struct stat)); if (stat(fs_path, finfo) < 0) return ap_psprintf(p, "stat(%s) failed: %s", fs_path, strerror(errno)); } if (finfo->st_mode == 0) return ap_psprintf(p, "script not found or unable to stat()"); if (S_ISDIR(finfo->st_mode)) return ap_psprintf(p, "script is a directory!"); /* Let the wrapper determine what it can and can't execute */ if (! fcgi_wrapper) { #ifdef WIN32 err = fcgi_util_check_access(p, fs_path, finfo, _S_IEXEC, fcgi_user_id, fcgi_group_id); #else err = fcgi_util_check_access(p, fs_path, finfo, X_OK, fcgi_user_id, fcgi_group_id); #endif if (err) { return ap_psprintf(p, "access for server (uid %ld, gid %ld) not allowed: %s", (long)fcgi_user_id, (long)fcgi_group_id, err); } } return NULL; }
/******************************************************************************* * Create a directory to hold Unix/Domain sockets. */ const char *fcgi_config_make_dir(pool *tp, char *path) { struct stat finfo; const char *err = NULL; /* Is the directory spec'd correctly */ if (*path != '/') { return "path is not absolute (it must start with a \"/\")"; } else { int i = strlen(path) - 1; /* Strip trailing "/"s */ while(i > 0 && path[i] == '/') path[i--] = '\0'; } /* Does it exist? */ if (stat(path, &finfo) != 0) { /* No, but maybe we can create it */ #ifdef WIN32 if (mkdir(path) != 0) #else if (mkdir(path, S_IRWXU) != 0) #endif { return ap_psprintf(tp, "doesn't exist and can't be created: %s", strerror(errno)); } #ifndef WIN32 /* If we're root, we're gonna setuid/setgid so we need to chown */ if (geteuid() == 0 && chown(path, ap_user_id, ap_group_id) != 0) { return ap_psprintf(tp, "can't chown() to the server (uid %ld, gid %ld): %s", (long)ap_user_id, (long)ap_group_id, strerror(errno)); } #endif } else { /* Yes, is it a directory? */ if (!S_ISDIR(finfo.st_mode)) return "isn't a directory!"; /* Can we RWX in there? */ #ifdef WIN32 err = fcgi_util_check_access(tp, NULL, &finfo, _S_IREAD | _S_IWRITE | _S_IEXEC, fcgi_user_id, fcgi_group_id); #else err = fcgi_util_check_access(tp, NULL, &finfo, R_OK | W_OK | X_OK, fcgi_user_id, fcgi_group_id); #endif if (err != NULL) { return ap_psprintf(tp, "access for server (uid %ld, gid %ld) failed: %s", (long)fcgi_user_id, (long)fcgi_group_id, err); } } return NULL; }
static void save_conn_info(request_rec *r) { conn_rec *c = r->connection; local_addr = ap_psprintf(c->pool, "%pI", &c->local_addr); remote_addr = ap_psprintf(c->pool, "%pI", &c->remote_addr); ap_register_cleanup(c->pool, NULL, clear_conn_info, ap_null_cleanup); }
/** * gets request URL */ static char *get_request_url(request_rec *r) { const char *args = r->args; if ((args != NULL) && (args[0] != '\0')) { am_web_log_debug("query args :%s", args); return ap_psprintf(r->pool, "%s://%s:%u%s?%s", ap_http_method(r), r->hostname, r->server->port, r->uri, args); } else { return ap_psprintf(r->pool, "%s://%s:%u%s", ap_http_method(r), r->hostname, r->server->port, r->uri); } }
/******************************************************************************* * Get the next configuration directive argument, & return an u_short. * The pool arg should be temporary storage. */ static const char *get_u_short(pool *p, const char **arg, u_short *num, u_short min) { char *ptr; long tmp; const char *txt = ap_getword_conf(p, arg); if (*txt == '\0') { return "\"\""; } tmp = strtol(txt, &ptr, 10); if (*ptr != '\0') { return ap_pstrcat(p, "\"", txt, "\" must be a positive integer", NULL); } if (tmp < min || tmp > USHRT_MAX) { return ap_psprintf(p, "\"%u\" must be >= %u and < %u", *num, min, USHRT_MAX); } *num = (u_short) tmp; return NULL; }
static void aurora_init(server_rec *s, pool *p) { STRLEN len = 0; SV *version; char *serverstring; version = perl_get_sv("Aurora::VERSION", TRUE | GV_ADDMULTI); serverstring = ap_psprintf(p, "Aurora/%s", SvPV(version, len)); ap_add_version_component(serverstring); }
/* ** dav_fs_save_locknull_list: Saves contents of pbuf into the ** locknull file for dirpath. */ static dav_error * dav_fs_save_locknull_list(pool *p, const char *dirpath, dav_buffer *pbuf) { const char *pathname; int fd; dav_error *err = NULL; if (pbuf->buf == NULL) return NULL; dav_fs_ensure_state_dir(p, dirpath); pathname = ap_pstrcat(p, dirpath, dirpath[strlen(dirpath) - 1] == '/' ? "" : "/", DAV_FS_STATE_DIR "/" DAV_FS_LOCK_NULL_FILE, NULL); if (pbuf->cur_len == 0) { /* delete the file if cur_len == 0 */ if (remove(pathname) != 0) { return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, ap_psprintf(p, "Error removing %s", pathname)); } return NULL; } if ((fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, DAV_FS_MODE_FILE)) == -1) { return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, ap_psprintf(p, "Error opening %s for writing", pathname)); } if (write(fd, pbuf->buf, pbuf->cur_len) != pbuf->cur_len) { err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, ap_psprintf(p, "Error writing %i bytes to %s", pbuf->cur_len, pathname)); } close(fd); return err; }
const char *fcgi_config_new_auth_server(cmd_parms * cmd, void * dircfg, const char *fs_path, const char * compat) { fcgi_dir_config * dir_config = (fcgi_dir_config *) dircfg; pool * const tp = cmd->temp_pool; char * auth_server; #ifdef APACHE2 if (apr_filepath_merge(&auth_server, "", fs_path, 0, cmd->pool)) return ap_psprintf(tp, "%s %s: invalid filepath", cmd->cmd->name, fs_path); #else auth_server = (char *) ap_os_canonical_filename(cmd->pool, fs_path); #endif auth_server = ap_server_root_relative(cmd->pool, auth_server); /* Make sure its already configured or at least a candidate for dynamic */ if (fcgi_util_fs_get_by_id(auth_server, fcgi_util_get_server_uid(cmd->server), fcgi_util_get_server_gid(cmd->server)) == NULL) { const char *err = fcgi_util_fs_is_path_ok(tp, auth_server, NULL); if (err) return ap_psprintf(tp, "%s: \"%s\" %s", cmd->cmd->name, auth_server, err); } if (compat && strcasecmp(compat, "-compat")) return ap_psprintf(cmd->temp_pool, "%s: unknown option: \"%s\"", cmd->cmd->name, compat); switch((long)cmd->info) { case FCGI_AUTH_TYPE_AUTHENTICATOR: dir_config->authenticator = auth_server; dir_config->authenticator_options |= (compat) ? FCGI_COMPAT : 0; break; case FCGI_AUTH_TYPE_AUTHORIZER: dir_config->authorizer = auth_server; dir_config->authorizer_options |= (compat) ? FCGI_COMPAT : 0; break; case FCGI_AUTH_TYPE_ACCESS_CHECKER: dir_config->access_checker = auth_server; dir_config->access_checker_options |= (compat) ? FCGI_COMPAT : 0; break; } return NULL; }
/* ** dav_fs_load_locknull_list: Returns a dav_buffer dump of the locknull file ** for the given directory. */ static dav_error * dav_fs_load_locknull_list(pool *p, const char *dirpath, dav_buffer *pbuf) { struct stat finfo; int fd; dav_error *err = NULL; dav_buffer_init(p, pbuf, dirpath); if (pbuf->buf[pbuf->cur_len - 1] == '/') pbuf->buf[--pbuf->cur_len] = '\0'; dav_buffer_place(p, pbuf, "/" DAV_FS_STATE_DIR "/" DAV_FS_LOCK_NULL_FILE); /* reset this in case we leave w/o reading into the buffer */ pbuf->cur_len = 0; if ((fd = open(pbuf->buf, O_RDONLY | O_BINARY)) == -1) { return NULL; } if (fstat(fd, &finfo) == -1) { err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, ap_psprintf(p, "Opened but could not stat file %s", pbuf->buf)); goto loaderror; } dav_set_bufsize(p, pbuf, finfo.st_size); if (read(fd, pbuf->buf, finfo.st_size) != finfo.st_size) { err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, ap_psprintf(p, "Failure reading locknull file " "for %s", dirpath)); /* just in case the caller disregards the returned error */ pbuf->cur_len = 0; goto loaderror; } loaderror: close(fd); return err; }
static const char *log_bytes_sent(request_rec *r, char *a) { if (!r->sent_bodyct) { return "0"; } else { long int bs; ap_bgetopt(r->connection->client, BO_BYTECT, &bs); return ap_psprintf(r->pool, "%ld", bs); } }
/******************************************************************************* * Configure uid, gid, user, group, username for wrapper. */ const char * fcgi_util_fs_set_uid_n_gid(pool *p, fcgi_server *s, uid_t uid, gid_t gid) { #ifndef WIN32 struct passwd *pw; struct group *gr; if (fcgi_wrapper == NULL) return NULL; if (uid == 0 || gid == 0) { return "invalid uid or gid, see the -user and -group options"; } s->uid = uid; pw = getpwuid(uid); if (pw == NULL) { return ap_psprintf(p, "getpwuid() couldn't determine the username for uid '%ld', " "you probably need to modify the User directive: %s", (long)uid, strerror(errno)); } s->user = ap_pstrdup(p, pw->pw_name); s->username = s->user; s->gid = gid; gr = getgrgid(gid); if (gr == NULL) { return ap_psprintf(p, "getgrgid() couldn't determine the group name for gid '%ld', " "you probably need to modify the Group directive: %s", (long)gid, strerror(errno)); } s->group = ap_pstrdup(p, gr->gr_name); #endif /* !WIN32 */ return NULL; }
/******************************************************************************* * Get the next configuration directive argument, & return a float. * The pool arg should be temporary storage. */ static const char *get_float(pool *p, const char **arg, float *num, float min, float max) { char *ptr; const char *val = ap_getword_conf(p, arg); if (*val == '\0') return "\"\""; *num = (float) strtod(val, &ptr); if (*ptr != '\0') return ap_pstrcat(p, "\"", val, "\" is not a floating point number", NULL); if (*num < min || *num > max) return ap_psprintf(p, "\"%f\" is not between %f and %f", *num, min, max); return NULL; }
/******************************************************************************* * Get the next configuration directive argument, & return an u_int. * The pool arg should be temporary storage. */ static const char *get_u_int(pool *p, const char **arg, u_int *num, u_int min) { char *ptr; const char *val = ap_getword_conf(p, arg); if (*val == '\0') return "\"\""; *num = (u_int)strtol(val, &ptr, 10); if (*ptr != '\0') return ap_pstrcat(p, "\"", val, "\" must be a positive integer", NULL); else if (*num < min) return ap_psprintf(p, "\"%u\" must be >= %u", *num, min); return NULL; }
static const char *get_int(pool *p, const char **arg, int *num, int min) { char *cp; const char *val = ap_getword_conf(p, arg); if (*val == '\0') { return "\"\""; } *num = (int) strtol(val, &cp, 10); if (*cp != '\0') { return ap_pstrcat(p, "can't parse ", "\"", val, "\"", NULL); } else if (*num < min) { return ap_psprintf(p, "\"%d\" must be >= %d", *num, min); } return NULL; }
char *ApacheUtil_expires(pool *p, char *time_str, int type) { time_t when; struct tm *tms; int sep = (type == EXPIRES_HTTP) ? ' ' : '-'; if (!time_str) { return NULL; } when = expire_calc(time_str); if (!when) { return ap_pstrdup(p, time_str); } tms = gmtime(&when); return ap_psprintf(p, "%s, %.2d%c%s%c%.2d %.2d:%.2d:%.2d GMT", ap_day_snames[tms->tm_wday], tms->tm_mday, sep, ap_month_snames[tms->tm_mon], sep, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, tms->tm_sec); }
/******************************************************************************* * Enable, disable, or specify the path to a wrapper used to invoke all * FastCGI applications. */ const char *fcgi_config_set_wrapper(cmd_parms *cmd, void *dummy, const char *arg) { #ifdef WIN32 return ap_psprintf(cmd->temp_pool, "the %s directive is not supported on WIN", cmd->cmd->name); #else const char *err = NULL; const char * const name = cmd->cmd->name; pool * const tp = cmd->temp_pool; char * wrapper = NULL; err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err) { return err; } if (fcgi_wrapper) { return ap_psprintf(tp, "%s was already set to \"%s\"", name, fcgi_wrapper); } err = fcgi_config_set_fcgi_uid_n_gid(1); if (err != NULL) return ap_psprintf(tp, "%s %s: %s", name, arg, err); if (fcgi_servers != NULL) { return ap_psprintf(tp, "The %s command must preceed static FastCGI server definitions", name); } if (strcasecmp(arg, "Off") == 0) { fcgi_wrapper = NULL; return NULL; } if (strcasecmp(arg, "On") == 0) { wrapper = SUEXEC_BIN; } else { #ifdef APACHE2 if (apr_filepath_merge(&wrapper, "", arg, 0, cmd->pool)) return ap_psprintf(tp, "%s %s: invalid filepath", name, arg); #else wrapper = ap_os_canonical_filename(cmd->pool, (char *) arg); #endif wrapper = ap_server_root_relative(cmd->pool, wrapper); } err = fcgi_util_check_access(tp, wrapper, NULL, X_OK, fcgi_user_id, fcgi_group_id); if (err) { return ap_psprintf(tp, "%s: \"%s\" execute access for server " "(uid %ld, gid %ld) failed: %s", name, wrapper, (long) fcgi_user_id, (long) fcgi_group_id, err); } fcgi_wrapper = wrapper; return NULL; #endif /* !WIN32 */ }
static PyObject *req_add_handler(requestobject *self, PyObject *args) { char *handler; char *function; const char *dir = NULL; const char *currhand; if (! PyArg_ParseTuple(args, "ss|s", &handler, &function, &dir)) return NULL; if (! valid_handler(handler)) { PyErr_SetString(PyExc_IndexError, ap_psprintf(self->request_rec->pool, "Invalid handler: %s", handler)); return NULL; } /* which handler are we processing? */ currhand = ap_table_get(self->request_rec->notes, "python_handler"); if (strcmp(currhand, handler) == 0) { /* if it's the same as what's being added, then just append to hstack */ self->hstack = ap_pstrcat(self->request_rec->pool, self->hstack, function, NULL); if (dir) ap_table_set(self->request_rec->notes, ap_pstrcat(self->request_rec->pool, handler, "_dir", NULL), dir); } else { const char *existing; /* is there a handler like this in the notes already? */ existing = ap_table_get(self->request_rec->notes, handler); if (existing) { /* append the function to the list using the request pool */ ap_table_set(self->request_rec->notes, handler, ap_pstrcat(self->request_rec->pool, existing, " ", function, NULL)); if (dir) { char *s = ap_pstrcat(self->request_rec->pool, handler, "_dir", NULL); ap_table_set(self->request_rec->notes, s, dir); } } else { char *s; /* a completely new handler */ ap_table_set(self->request_rec->notes, handler, function); if (! dir) { /* * If no directory was explicitely specified, the new handler will * have the same directory associated with it as the handler * currently being processed. */ py_dir_config *conf; /* get config */ conf = (py_dir_config *) ap_get_module_config( self->request_rec->per_dir_config, &python_module); /* what's the directory for this handler? */ dir = ap_table_get(conf->dirs, currhand); /* * make a note that the handler's been added. * req_get_all_* rely on this to be faster */ ap_table_set(self->request_rec->notes, "py_more_directives", "1"); } s = ap_pstrcat(self->request_rec->pool, handler, "_dir", NULL); ap_table_set(self->request_rec->notes, s, dir); } } Py_INCREF(Py_None); return Py_None; }
static const char *log_server_port(request_rec *r, char *a) { return ap_psprintf(r->pool, "%u", r->server->port ? r->server->port : ap_default_port(r)); }
static const char *log_child_pid(request_rec *r, char *a) { return ap_psprintf(r->pool, "%ld", (long) getpid()); }
/******************************************************************************* * Configure a static FastCGI server. */ const char *fcgi_config_new_static_server(cmd_parms *cmd, void *dummy, const char *arg) { fcgi_server *s; pool *p = cmd->pool, *tp = cmd->temp_pool; const char *name = cmd->cmd->name; char *fs_path = ap_getword_conf(p, &arg); const char *option, *err; /* Allocate temp storage for the array of initial environment variables */ char **envp = ap_pcalloc(tp, sizeof(char *) * (MAX_INIT_ENV_VARS + 3)); unsigned int envc = 0; #ifdef WIN32 HANDLE mutex; #endif err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_DIR_LOC_FILE); if (err) { return err; } if (*fs_path == '\0') return "AppClass requires a pathname!?"; if ((err = fcgi_config_set_fcgi_uid_n_gid(1)) != NULL) return ap_psprintf(tp, "%s %s: %s", name, fs_path, err); #ifdef APACHE2 if (apr_filepath_merge(&fs_path, "", fs_path, 0, p)) return ap_psprintf(tp, "%s %s: invalid filepath", name, fs_path); #else fs_path = ap_os_canonical_filename(p, fs_path); #endif fs_path = ap_server_root_relative(p, fs_path); ap_getparents(fs_path); ap_no2slash(fs_path); /* See if we've already got one of these configured */ s = fcgi_util_fs_get_by_id(fs_path, fcgi_util_get_server_uid(cmd->server), fcgi_util_get_server_gid(cmd->server)); if (s != NULL) { if (fcgi_wrapper) { return ap_psprintf(tp, "%s: redefinition of a previously defined FastCGI " "server \"%s\" with uid=%ld and gid=%ld", name, fs_path, (long) fcgi_util_get_server_uid(cmd->server), (long) fcgi_util_get_server_gid(cmd->server)); } else { return ap_psprintf(tp, "%s: redefinition of a previously defined FastCGI server \"%s\"", name, fs_path); } } err = fcgi_util_fs_is_path_ok(tp, fs_path, NULL); if (err != NULL) { return ap_psprintf(tp, "%s: \"%s\" %s", name, fs_path, err); } s = fcgi_util_fs_new(p); s->fs_path = fs_path; s->directive = APP_CLASS_STANDARD; s->restartOnExit = TRUE; s->numProcesses = 1; #ifdef WIN32 /* TCP FastCGI applications require SystemRoot be present in the environment * Put it in both for consistency to the application */ fcgi_config_set_env_var(p, envp, &envc, "SystemRoot"); mutex = CreateMutex(NULL, FALSE, fs_path); if (mutex == NULL) { ap_log_error(FCGI_LOG_ALERT, fcgi_apache_main_server, "FastCGI: CreateMutex() failed"); return "failed to create FastCGI application accept mutex"; } SetHandleInformation(mutex, HANDLE_FLAG_INHERIT, TRUE); s->mutex_env_string = ap_psprintf(p, "_FCGI_MUTEX_=%ld", mutex); #endif /* Parse directive arguments */ while (*arg) { option = ap_getword_conf(tp, &arg); if (strcasecmp(option, "-processes") == 0) { if ((err = get_u_int(tp, &arg, &s->numProcesses, 1))) return invalid_value(tp, name, fs_path, option, err); } else if (strcasecmp(option, "-restart-delay") == 0) { if ((err = get_u_int(tp, &arg, &s->restartDelay, 0))) return invalid_value(tp, name, fs_path, option, err); } else if (strcasecmp(option, "-init-start-delay") == 0) { if ((err = get_int(tp, &arg, &s->initStartDelay, 0))) return invalid_value(tp, name, fs_path, option, err); } else if (strcasecmp(option, "-min-server-life") == 0) { if ((err = get_u_int(tp, &arg, &s->minServerLife, 0))) return invalid_value(tp, name, NULL, option, err); } else if (strcasecmp(option, "-priority") == 0) { if ((err = get_u_int(tp, &arg, &s->processPriority, 0))) return invalid_value(tp, name, fs_path, option, err); } else if (strcasecmp(option, "-listen-queue-depth") == 0) { if ((err = get_u_int(tp, &arg, &s->listenQueueDepth, 1))) return invalid_value(tp, name, fs_path, option, err); } else if (strcasecmp(option, "-appConnTimeout") == 0) { if ((err = get_u_int(tp, &arg, &s->appConnectTimeout, 0))) return invalid_value(tp, name, fs_path, option, err); } else if (strcasecmp(option, "-idle-timeout") == 0) { if ((err = get_u_int(tp, &arg, &s->idle_timeout, 1))) return invalid_value(tp, name, fs_path, option, err); } else if (strcasecmp(option, "-port") == 0) { if ((err = get_u_short(tp, &arg, &s->port, 1))) return invalid_value(tp, name, fs_path, option, err); } else if (strcasecmp(option, "-socket") == 0) { s->socket_path = ap_getword_conf(tp, &arg); if (*s->socket_path == '\0') return invalid_value(tp, name, fs_path, option, "\"\""); } else if (strcasecmp(option, "-initial-env") == 0) { if ((err = get_env_var(p, &arg, envp, &envc))) return invalid_value(tp, name, fs_path, option, err); } else if (strcasecmp(option, "-pass-header") == 0) { if ((err = get_pass_header(p, &arg, &s->pass_headers))) return invalid_value(tp, name, fs_path, option, err); } else if (strcasecmp(option, "-flush") == 0) { s->flush = 1; } else if (strcasecmp(option, "-nph") == 0) { s->nph = 1; } else if (strcasecmp(option, "-user") == 0) { #ifdef WIN32 return ap_psprintf(tp, "%s %s: the -user option isn't supported on WIN", name, fs_path); #else s->user = ap_getword_conf(tp, &arg); if (*s->user == '\0') return invalid_value(tp, name, fs_path, option, "\"\""); #endif } else if (strcasecmp(option, "-group") == 0) { #ifdef WIN32 return ap_psprintf(tp, "%s %s: the -group option isn't supported on WIN", name, fs_path); #else s->group = ap_getword_conf(tp, &arg); if (*s->group == '\0') return invalid_value(tp, name, fs_path, option, "\"\""); #endif } else { return ap_psprintf(tp, "%s %s: invalid option: %s", name, fs_path, option); } } /* while */ #ifndef WIN32 if (fcgi_wrapper) { if (s->group == NULL) { s->group = ap_psprintf(tp, "#%ld", (long)fcgi_util_get_server_gid(cmd->server)); } if (s->user == NULL) { s->user = ap_psprintf(p, "#%ld", (long)fcgi_util_get_server_uid(cmd->server)); } s->uid = ap_uname2id(s->user); s->gid = ap_gname2id(s->group); } else if (s->user || s->group) { ap_log_error(FCGI_LOG_WARN, cmd->server, "FastCGI: there is no " "fastcgi wrapper set, user/group options are ignored"); } if ((err = fcgi_util_fs_set_uid_n_gid(p, s, s->uid, s->gid))) { return ap_psprintf(tp, "%s %s: invalid user or group: %s", name, fs_path, err); } #endif /* !WIN32 */ if (s->socket_path != NULL && s->port != 0) { return ap_psprintf(tp, "%s %s: -port and -socket are mutually exclusive options", name, fs_path); } /* Move env array to a surviving pool */ s->envp = (char **)ap_pcalloc(p, sizeof(char *) * (envc + 4)); memcpy(s->envp, envp, sizeof(char *) * envc); /* Initialize process structs */ s->procs = fcgi_util_fs_create_procs(p, s->numProcesses); /* Build the appropriate sockaddr structure */ if (s->port != 0) { err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->socket_addr, &s->socket_addr_len, NULL, s->port); if (err != NULL) return ap_psprintf(tp, "%s %s: %s", name, fs_path, err); #ifdef WIN32 err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->dest_addr, &s->socket_addr_len, "localhost", s->port); if (err != NULL) return ap_psprintf(tp, "%s %s: %s", name, fs_path, err); #endif } else { if (s->socket_path == NULL) s->socket_path = fcgi_util_socket_hash_filename(tp, fs_path, s->user, s->group); if (fcgi_socket_dir == NULL) { #ifdef WIN32 fcgi_socket_dir = DEFAULT_SOCK_DIR; #else fcgi_socket_dir = ap_server_root_relative(p, DEFAULT_SOCK_DIR); #endif } s->socket_path = fcgi_util_socket_make_path_absolute(p, s->socket_path, 0); #ifndef WIN32 err = fcgi_util_socket_make_domain_addr(p, (struct sockaddr_un **)&s->socket_addr, &s->socket_addr_len, s->socket_path); if (err != NULL) return ap_psprintf(tp, "%s %s: %s", name, fs_path, err); #endif } /* Add it to the list of FastCGI servers */ fcgi_util_fs_add(s); return NULL; }
static const char *log_request_duration(request_rec *r, char *a) { return ap_psprintf(r->pool, "%ld", time(NULL) - r->request_time); }
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; }
static char *format_integer(pool *p, int i) { return ap_psprintf(p, "%d", i); }
/******************************************************************************* * Configure a static FastCGI server that is started/managed elsewhere. */ const char *fcgi_config_new_external_server(cmd_parms *cmd, void *dummy, const char *arg) { fcgi_server *s; pool * const p = cmd->pool, *tp = cmd->temp_pool; const char * const name = cmd->cmd->name; char *fs_path = ap_getword_conf(p, &arg); const char *option, *err; err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_DIR_LOC_FILE); if (err) { return err; } if (!*fs_path) { return ap_pstrcat(tp, name, " requires a path and either a -socket or -host option", NULL); } #ifdef APACHE2 if (apr_filepath_merge(&fs_path, "", fs_path, 0, p)) return ap_psprintf(tp, "%s %s: invalid filepath", name, fs_path); #else fs_path = ap_os_canonical_filename(p, fs_path); #endif fs_path = ap_server_root_relative(p, fs_path); ap_getparents(fs_path); ap_no2slash(fs_path); /* See if we've already got one of these bettys configured */ s = fcgi_util_fs_get_by_id(fs_path, fcgi_util_get_server_uid(cmd->server), fcgi_util_get_server_gid(cmd->server)); if (s != NULL) { if (fcgi_wrapper) { return ap_psprintf(tp, "%s: redefinition of a previously defined class \"%s\" " "with uid=%ld and gid=%ld", name, fs_path, (long) fcgi_util_get_server_uid(cmd->server), (long) fcgi_util_get_server_gid(cmd->server)); } else { return ap_psprintf(tp, "%s: redefinition of previously defined class \"%s\"", name, fs_path); } } s = fcgi_util_fs_new(p); s->fs_path = fs_path; s->directive = APP_CLASS_EXTERNAL; /* Parse directive arguments */ while (*arg != '\0') { option = ap_getword_conf(tp, &arg); if (strcasecmp(option, "-host") == 0) { if ((err = get_host_n_port(p, &arg, &s->host, &s->port))) return invalid_value(tp, name, fs_path, option, err); } else if (strcasecmp(option, "-socket") == 0) { s->socket_path = ap_getword_conf(tp, &arg); if (*s->socket_path == '\0') return invalid_value(tp, name, fs_path, option, "\"\""); } else if (strcasecmp(option, "-appConnTimeout") == 0) { if ((err = get_u_int(tp, &arg, &s->appConnectTimeout, 0))) return invalid_value(tp, name, fs_path, option, err); } else if (strcasecmp(option, "-idle-timeout") == 0) { if ((err = get_u_int(tp, &arg, &s->idle_timeout, 1))) return invalid_value(tp, name, fs_path, option, err); } else if (strcasecmp(option, "-nph") == 0) { s->nph = 1; } else if (strcasecmp(option, "-pass-header") == 0) { if ((err = get_pass_header(p, &arg, &s->pass_headers))) return invalid_value(tp, name, fs_path, option, err); } else if (strcasecmp(option, "-flush") == 0) { s->flush = 1; } else if (strcasecmp(option, "-user") == 0) { #ifdef WIN32 return ap_psprintf(tp, "%s %s: the -user option isn't supported on WIN", name, fs_path); #else s->user = ap_getword_conf(tp, &arg); if (*s->user == '\0') return invalid_value(tp, name, fs_path, option, "\"\""); #endif } else if (strcasecmp(option, "-group") == 0) { #ifdef WIN32 return ap_psprintf(tp, "%s %s: the -group option isn't supported on WIN", name, fs_path); #else s->group = ap_getword_conf(tp, &arg); if (*s->group == '\0') return invalid_value(tp, name, fs_path, option, "\"\""); #endif } else if (strcasecmp(option, "-fixPaths") == 0) { s->fixPaths = 1; } else { return ap_psprintf(tp, "%s %s: invalid option: %s", name, fs_path, option); } } /* while */ #ifndef WIN32 if (fcgi_wrapper) { if (s->group == NULL) { s->group = ap_psprintf(tp, "#%ld", (long)fcgi_util_get_server_gid(cmd->server)); } if (s->user == NULL) { s->user = ap_psprintf(p, "#%ld", (long)fcgi_util_get_server_uid(cmd->server)); } s->uid = ap_uname2id(s->user); s->gid = ap_gname2id(s->group); } else if (s->user || s->group) { ap_log_error(FCGI_LOG_WARN, cmd->server, "FastCGI: there is no " "fastcgi wrapper set, user/group options are ignored"); } if ((err = fcgi_util_fs_set_uid_n_gid(p, s, s->uid, s->gid))) { return ap_psprintf(tp, "%s %s: invalid user or group: %s", name, fs_path, err); } #endif /* !WIN32 */ /* Require one of -socket or -host, but not both */ if (s->socket_path != NULL && s->port != 0) { return ap_psprintf(tp, "%s %s: -host and -socket are mutually exclusive options", name, fs_path); } if (s->socket_path == NULL && s->port == 0) { return ap_psprintf(tp, "%s %s: -socket or -host option missing", name, fs_path); } /* Build the appropriate sockaddr structure */ if (s->port != 0) { err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->socket_addr, &s->socket_addr_len, s->host, s->port); if (err != NULL) return ap_psprintf(tp, "%s %s: %s", name, fs_path, err); } else { if (fcgi_socket_dir == NULL) { #ifdef WIN32 fcgi_socket_dir = DEFAULT_SOCK_DIR; #else fcgi_socket_dir = ap_server_root_relative(p, DEFAULT_SOCK_DIR); #endif } s->socket_path = fcgi_util_socket_make_path_absolute(p, s->socket_path, 0); #ifndef WIN32 err = fcgi_util_socket_make_domain_addr(p, (struct sockaddr_un **)&s->socket_addr, &s->socket_addr_len, s->socket_path); if (err != NULL) return ap_psprintf(tp, "%s %s: %s", name, fs_path, err); #endif } /* Add it to the list of FastCGI servers */ fcgi_util_fs_add(s); return NULL; }
API_EXPORT(void) ap_add_common_vars(request_rec *r) { table *e; server_rec *s = r->server; conn_rec *c = r->connection; const char *rem_logname; char *env_path; #if defined(WIN32) || defined(OS2) char *env_temp; #endif const char *host; array_header *hdrs_arr = ap_table_elts(r->headers_in); table_entry *hdrs = (table_entry *) hdrs_arr->elts; int i; char servbuf[NI_MAXSERV]; /* use a temporary table which we'll overlap onto * r->subprocess_env later */ e = ap_make_table(r->pool, 25 + hdrs_arr->nelts); /* First, add environment vars from headers... this is as per * CGI specs, though other sorts of scripting interfaces see * the same vars... */ for (i = 0; i < hdrs_arr->nelts; ++i) { if (!hdrs[i].key) { continue; } /* A few headers are special cased --- Authorization to prevent * rogue scripts from capturing passwords; content-type and -length * for no particular reason. */ if (!strcasecmp(hdrs[i].key, "Content-type")) { ap_table_addn(e, "CONTENT_TYPE", hdrs[i].val); } else if (!strcasecmp(hdrs[i].key, "Content-length")) { ap_table_addn(e, "CONTENT_LENGTH", hdrs[i].val); } /* * You really don't want to disable this check, since it leaves you * wide open to CGIs stealing passwords and people viewing them * in the environment with "ps -e". But, if you must... */ #ifndef SECURITY_HOLE_PASS_AUTHORIZATION else if (!strcasecmp(hdrs[i].key, "Authorization") || !strcasecmp(hdrs[i].key, "Proxy-Authorization")) { continue; } #endif else { ap_table_addn(e, http2env(r->pool, hdrs[i].key), hdrs[i].val); } } if (!(env_path = ap_pstrdup(r->pool, getenv("PATH")))) { env_path = DEFAULT_PATH; } #ifdef WIN32 if (env_temp = getenv("SystemRoot")) { ap_table_addn(e, "SystemRoot", env_temp); } if (env_temp = getenv("COMSPEC")) { ap_table_addn(e, "COMSPEC", env_temp); } if (env_temp = getenv("WINDIR")) { ap_table_addn(e, "WINDIR", env_temp); } #endif #ifdef OS2 if ((env_temp = getenv("COMSPEC")) != NULL) { ap_table_addn(e, "COMSPEC", env_temp); } if ((env_temp = getenv("ETC")) != NULL) { ap_table_addn(e, "ETC", env_temp); } if ((env_temp = getenv("DPATH")) != NULL) { ap_table_addn(e, "DPATH", env_temp); } if ((env_temp = getenv("PERLLIB_PREFIX")) != NULL) { ap_table_addn(e, "PERLLIB_PREFIX", env_temp); } #endif ap_table_addn(e, "PATH", env_path); ap_table_addn(e, "SERVER_SIGNATURE", ap_psignature("", r)); ap_table_addn(e, "SERVER_SOFTWARE", ap_get_server_version()); ap_table_addn(e, "SERVER_NAME", ap_escape_html(r->pool,ap_get_server_name(r))); ap_table_addn(e, "SERVER_ADDR", r->connection->local_ip); /* Apache */ ap_table_addn(e, "SERVER_PORT", ap_psprintf(r->pool, "%u", ap_get_server_port(r))); host = ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST); if (host) { ap_table_addn(e, "REMOTE_HOST", host); } ap_table_addn(e, "REMOTE_ADDR", c->remote_ip); ap_table_addn(e, "DOCUMENT_ROOT", ap_document_root(r)); /* Apache */ ap_table_addn(e, "SERVER_ADMIN", s->server_admin); /* Apache */ ap_table_addn(e, "SCRIPT_FILENAME", r->filename); /* Apache */ servbuf[0] = '\0'; if (!getnameinfo((struct sockaddr *)&c->remote_addr, #ifndef HAVE_SOCKADDR_LEN SA_LEN((struct sockaddr *)&c->remote_addr), #else c->remote_addr.ss_len, #endif NULL, 0, servbuf, sizeof(servbuf), NI_NUMERICSERV)){ ap_table_addn(e, "REMOTE_PORT", ap_pstrdup(r->pool, servbuf)); } if (c->user) { ap_table_addn(e, "REMOTE_USER", c->user); } if (c->ap_auth_type) { ap_table_addn(e, "AUTH_TYPE", c->ap_auth_type); } rem_logname = ap_get_remote_logname(r); if (rem_logname) { ap_table_addn(e, "REMOTE_IDENT", ap_pstrdup(r->pool, rem_logname)); } /* Apache custom error responses. If we have redirected set two new vars */ if (r->prev) { if (r->prev->args) { ap_table_addn(e, "REDIRECT_QUERY_STRING", r->prev->args); } if (r->prev->uri) { ap_table_addn(e, "REDIRECT_URL", r->prev->uri); } } ap_overlap_tables(r->subprocess_env, e, AP_OVERLAP_TABLES_SET); }
/******************************************************************************* * Determine if a process with uid/gid can access a file with mode permissions. */ const char * fcgi_util_check_access(pool *tp, const char * const path, const struct stat *statBuf, const int mode, const uid_t uid, const gid_t gid) { struct stat myStatBuf; if (statBuf == NULL) { if (stat(path, &myStatBuf) < 0) return ap_psprintf(tp, "stat(%s) failed: %s", path, strerror(errno)); statBuf = &myStatBuf; } #ifndef WIN32 /* If the uid owns the file, check the owner bits */ if (uid == statBuf->st_uid) { if (mode & R_OK && !(statBuf->st_mode & S_IRUSR)) return "read not allowed by owner"; if (mode & W_OK && !(statBuf->st_mode & S_IWUSR)) return "write not allowed by owner"; if (mode & X_OK && !(statBuf->st_mode & S_IXUSR)) return "execute not allowed by owner"; return NULL; } #else if (mode & _S_IREAD && !(statBuf->st_mode & _S_IREAD)) return "read not allowed"; if (mode & _S_IWRITE && !(statBuf->st_mode & _S_IWRITE)) return "write not allowed"; /* I don't think this works on FAT, but since I don't know how to check.. * if (mode & _S_IEXEC && !(statBuf->st_mode & _S_IEXEC)) * return "execute not allowed"; */ #endif #if !defined(__EMX__) && !defined(WIN32) /* If the gid is same as the file's group, check the group bits */ if (gid == statBuf->st_gid) { if (mode & R_OK && !(statBuf->st_mode & S_IRGRP)) return "read not allowed by group"; if (mode & W_OK && !(statBuf->st_mode & S_IWGRP)) return "write not allowed by group"; if (mode & X_OK && !(statBuf->st_mode & S_IXGRP)) return "execute not allowed by group"; return NULL; } /* Get the user membership for the file's group. If the * uid is a member, check the group bits. */ { const struct group * const gr = getgrgid(statBuf->st_gid); const struct passwd * const pw = getpwuid(uid); if (gr != NULL && pw != NULL) { char **user = gr->gr_mem; for ( ; *user != NULL; user++) { if (strcmp(*user, pw->pw_name) == 0) { if (mode & R_OK && !(statBuf->st_mode & S_IRGRP)) return "read not allowed by group"; if (mode & W_OK && !(statBuf->st_mode & S_IWGRP)) return "write not allowed by group"; if (mode & X_OK && !(statBuf->st_mode & S_IXGRP)) return "execute not allowed by group"; return NULL; } } } } /* That just leaves the other bits.. */ if (mode & R_OK && !(statBuf->st_mode & S_IROTH)) return "read not allowed"; if (mode & W_OK && !(statBuf->st_mode & S_IWOTH)) return "write not allowed"; if (mode & X_OK && !(statBuf->st_mode & S_IXOTH)) return "execute not allowed"; #endif return NULL; }
/* * This handles http:// URLs, and other URLs using a remote proxy over http * If proxyhost is NULL, then contact the server directly, otherwise * go via the proxy. * Note that if a proxy is used, then URLs other than http: can be accessed, * also, if we have trouble which is clearly specific to the proxy, then * we return DECLINED so that we can try another proxy. (Or the direct * route.) */ int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url, const char *proxyhost, int proxyport) { const char *strp; char *strp2; const char *err, *desthost; int i, j, sock,/* len,*/ backasswards; table *req_hdrs, *resp_hdrs; array_header *reqhdrs_arr; table_entry *reqhdrs_elts; BUFF *f; char buffer[HUGE_STRING_LEN]; char portstr[32]; pool *p = r->pool; int chunked = 0, destport = 0; char *destportstr = NULL; const char *urlptr = NULL; const char *datestr, *urlstr; struct addrinfo hints, *res, *res0; int error; int result, major, minor; const char *content_length; const char *peer; int destportstrtonum; const char *errstr; void *sconf = r->server->module_config; proxy_server_conf *conf = (proxy_server_conf *)ap_get_module_config(sconf, &proxy_module); struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts; struct nocache_entry *ncent = (struct nocache_entry *) conf->nocaches->elts; int nocache = 0; if (conf->cache.root == NULL) nocache = 1; /* We break the URL into host, port, path-search */ urlptr = strstr(url, "://"); if (urlptr == NULL) return HTTP_BAD_REQUEST; destport = DEFAULT_HTTP_PORT; urlptr += 3; ap_hook_use("ap::mod_proxy::http::handler::set_destport", AP_HOOK_SIG2(int,ptr), AP_HOOK_TOPMOST, &destport, r); ap_snprintf(portstr, sizeof(portstr), "%d", destport); destportstr = portstr; strp = strchr(urlptr, '/'); if (strp == NULL) { desthost = ap_pstrdup(p, urlptr); urlptr = "/"; } else { char *q = ap_palloc(p, strp - urlptr + 1); memcpy(q, urlptr, strp - urlptr); q[strp - urlptr] = '\0'; urlptr = strp; desthost = q; } if (*desthost == '['){ char *u = strrchr(desthost+1, ']'); if (u){ desthost++; *u = '\0'; if (*(u+1) == ':'){ /* [host]:xx */ strp2 = u+1; } else if (*(u+1) == '\0'){ /* [host] */ strp2 = NULL; } else return HTTP_BAD_REQUEST; } else return HTTP_BAD_REQUEST; } else strp2 = strrchr(desthost, ':'); if (strp2 != NULL) { *(strp2++) = '\0'; if (ap_isdigit(*strp2)) destportstr = strp2; } /* Make sure peer is always set to prevent a segfault in the SSL handler */ peer = desthost; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; error = getaddrinfo(desthost, destportstr, &hints, &res0); if (error && proxyhost == NULL) { return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, gai_strerror(error)); /* give up */ } /* check if ProxyBlock directive on this host */ for (i = 0; i < conf->noproxies->nelts; i++) { int fail; struct sockaddr_in *sin; fail = 0; if (npent[i].name != NULL && strstr(desthost, npent[i].name)) fail++; if (npent[i].name != NULL && strcmp(npent[i].name, "*") == 0) fail++; for (res = res0; res; res = res->ai_next) { switch (res->ai_family) { case AF_INET: sin = (struct sockaddr_in *)res->ai_addr; if (sin->sin_addr.s_addr == npent[i].addr.s_addr) fail++; break; } } if (fail) { if (res0 != NULL) freeaddrinfo(res0); return ap_proxyerror(r, HTTP_FORBIDDEN, "Connect to remote machine blocked"); } } if (proxyhost != NULL) { char pbuf[10]; if (res0 != NULL) freeaddrinfo(res0); ap_snprintf(pbuf, sizeof(pbuf), "%d", proxyport); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; error = getaddrinfo(proxyhost, pbuf, &hints, &res0); if (error) return DECLINED; /* try another */ } /* check if ProxyBlock directive on this host */ for (i = 0; i < conf->noproxies->nelts; i++) { peer = ap_psprintf(p, "%s:%s", desthost, destportstr); } /* * we have worked out who exactly we are going to connect to, now make * that connection... */ sock = i = -1; for (res = res0; res; res = res->ai_next) { sock = ap_psocket(p, res->ai_family, res->ai_socktype, res->ai_protocol); if (sock < 0) continue; if (conf->recv_buffer_size) { if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (const char *)&conf->recv_buffer_size, sizeof(int)) == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default"); } } i = ap_proxy_doconnect(sock, res->ai_addr, r); if (i == 0) break; ap_pclosesocket(p, sock); } freeaddrinfo(res0); if (i == -1) { if (proxyhost != NULL) return DECLINED; /* try again another way */ else return ap_proxyerror(r, HTTP_BAD_GATEWAY, ap_pstrcat(r->pool, "Could not connect to remote machine: ", strerror(errno), NULL)); } /* record request_time for HTTP/1.1 age calculation */ c->req_time = time(NULL); /* * build upstream-request headers by stripping r->headers_in from * connection specific headers. We must not remove the Connection: header * from r->headers_in, we still have to react to Connection: close */ req_hdrs = ap_copy_table(r->pool, r->headers_in); ap_proxy_clear_connection(r->pool, req_hdrs); /* * At this point, we start sending the HTTP/1.1 request to the remote * server (proxy or otherwise). */ f = ap_bcreate(p, B_RDWR | B_SOCKET); ap_bpushfd(f, sock, sock); { char *errmsg = NULL; ap_hook_use("ap::mod_proxy::http::handler::new_connection", AP_HOOK_SIG4(ptr,ptr,ptr,ptr), AP_HOOK_DECLINE(NULL), &errmsg, r, f, peer); if (errmsg != NULL) return ap_proxyerror(r, HTTP_BAD_GATEWAY, errmsg); } ap_hard_timeout("proxy send", r); ap_bvputs(f, r->method, " ", proxyhost ? url : urlptr, " HTTP/1.1" CRLF, NULL); { int rc = DECLINED; ap_hook_use("ap::mod_proxy::http::handler::write_host_header", AP_HOOK_SIG6(int,ptr,ptr,ptr,ptr,ptr), AP_HOOK_DECLINE(DECLINED), &rc, r, f, desthost, destportstr, destportstr); if (rc == DECLINED) { destportstrtonum = strtonum(destportstr, 0, 65535, &errstr); if (errstr) errx(1, "The destination port is %s: %s", errstr, destportstr); if (destportstr != NULL && destportstrtonum != destport) ap_bvputs(f, "Host: ", desthost, ":", destportstr, CRLF, NULL); else ap_bvputs(f, "Host: ", desthost, CRLF, NULL); } } if (conf->viaopt == via_block) { /* Block all outgoing Via: headers */ ap_table_unset(req_hdrs, "Via"); } else if (conf->viaopt != via_off) { /* Create a "Via:" request header entry and merge it */ i = ap_get_server_port(r); if (ap_is_default_port(i, r)) { strlcpy(portstr, "", sizeof(portstr)); } else { ap_snprintf(portstr, sizeof portstr, ":%d", i); } /* Generate outgoing Via: header with/without server comment: */ ap_table_mergen(req_hdrs, "Via", (conf->viaopt == via_full) ? ap_psprintf(p, "%d.%d %s%s (%s)", HTTP_VERSION_MAJOR(r->proto_num), HTTP_VERSION_MINOR(r->proto_num), ap_get_server_name(r), portstr, SERVER_BASEVERSION) : ap_psprintf(p, "%d.%d %s%s", HTTP_VERSION_MAJOR(r->proto_num), HTTP_VERSION_MINOR(r->proto_num), ap_get_server_name(r), portstr) ); } /* the X-* headers are only added if we are a reverse * proxy, otherwise we would be giving away private information. */ if (r->proxyreq == PROXY_PASS) { const char *buf; /* * Add X-Forwarded-For: so that the upstream has a chance to determine, * where the original request came from. */ ap_table_mergen(req_hdrs, "X-Forwarded-For", r->connection->remote_ip); /* Add X-Forwarded-Host: so that upstream knows what the * original request hostname was. */ if ((buf = ap_table_get(r->headers_in, "Host"))) { ap_table_mergen(req_hdrs, "X-Forwarded-Host", buf); } /* Add X-Forwarded-Server: so that upstream knows what the * name of this proxy server is (if there are more than one) * XXX: This duplicates Via: - do we strictly need it? */ ap_table_mergen(req_hdrs, "X-Forwarded-Server", r->server->server_hostname); } /* we don't yet support keepalives - but we will soon, I promise! */ ap_table_set(req_hdrs, "Connection", "close"); reqhdrs_arr = ap_table_elts(req_hdrs); reqhdrs_elts = (table_entry *)reqhdrs_arr->elts; for (i = 0; i < reqhdrs_arr->nelts; i++) { if (reqhdrs_elts[i].key == NULL || reqhdrs_elts[i].val == NULL /* * Clear out hop-by-hop request headers not to send: RFC2616 13.5.1 * says we should strip these headers: */ || !strcasecmp(reqhdrs_elts[i].key, "Host") /* Already sent */ || !strcasecmp(reqhdrs_elts[i].key, "Keep-Alive") || !strcasecmp(reqhdrs_elts[i].key, "TE") || !strcasecmp(reqhdrs_elts[i].key, "Trailer") || !strcasecmp(reqhdrs_elts[i].key, "Transfer-Encoding") || !strcasecmp(reqhdrs_elts[i].key, "Upgrade") /* * XXX: @@@ FIXME: "Proxy-Authorization" should *only* be suppressed * if THIS server requested the authentication, not when a frontend * proxy requested it! * * The solution to this problem is probably to strip out the * Proxy-Authorisation header in the authorisation code itself, not * here. This saves us having to signal somehow whether this request * was authenticated or not. */ || !strcasecmp(reqhdrs_elts[i].key, "Proxy-Authorization")) continue; ap_bvputs(f, reqhdrs_elts[i].key, ": ", reqhdrs_elts[i].val, CRLF, NULL); } /* the obligatory empty line to mark the end of the headers */ ap_bputs(CRLF, f); /* and flush the above away */ ap_bflush(f); /* and kill the send timeout */ ap_kill_timeout(r); /* read the request data, and pass it to the backend. * we might encounter a stray 100-continue reponse from a PUT or POST, * if this happens we ignore the 100 continue status line and read the * response again. */ { /* send the request data, if any. */ ap_hard_timeout("proxy receive request data", r); if (ap_should_client_block(r)) { while ((i = ap_get_client_block(r, buffer, sizeof buffer)) > 0) { ap_reset_timeout(r); ap_bwrite(f, buffer, i); } } ap_bflush(f); ap_kill_timeout(r); /* then, read a response line */ ap_hard_timeout("proxy receive response status line", r); result = ap_proxy_read_response_line(f, r, buffer, sizeof(buffer)-1, &backasswards, &major, &minor); ap_kill_timeout(r); /* trap any errors */ if (result != OK) { ap_bclose(f); return result; } /* if this response was 100-continue, a stray response has been caught. * read the line again for the real response */ if (r->status == 100) { ap_hard_timeout("proxy receive response status line", r); result = ap_proxy_read_response_line(f, r, buffer, sizeof(buffer)-1, &backasswards, &major, &minor); ap_kill_timeout(r); /* trap any errors */ if (result != OK) { ap_bclose(f); return result; } } } /* * We have our response status line from the convoluted code above, * now we read the headers to continue. */ ap_hard_timeout("proxy receive response headers", r); /* * Is it an HTTP/1 response? Do some sanity checks on the response. (This * is buggy if we ever see an HTTP/1.10) */ if (backasswards == 0) { /* read the response headers. */ /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers */ /* Also, take care with headers with multiple occurences. */ resp_hdrs = ap_proxy_read_headers(r, buffer, sizeof(buffer), f); if (resp_hdrs == NULL) { ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_NOERRNO, r->server, "proxy: Bad HTTP/%d.%d header returned by %s (%s)", major, minor, r->uri, r->method); resp_hdrs = ap_make_table(p, 20); nocache = 1; /* do not cache this broken file */ } /* handle Via header in the response */ if (conf->viaopt != via_off && conf->viaopt != via_block) { /* Create a "Via:" response header entry and merge it */ i = ap_get_server_port(r); if (ap_is_default_port(i, r)) { strlcpy(portstr, "", sizeof(portstr)); } else { ap_snprintf(portstr, sizeof portstr, ":%d", i); } ap_table_mergen((table *)resp_hdrs, "Via", (conf->viaopt == via_full) ? ap_psprintf(p, "%d.%d %s%s (%s)", major, minor, ap_get_server_name(r), portstr, SERVER_BASEVERSION) : ap_psprintf(p, "%d.%d %s%s", major, minor, ap_get_server_name(r), portstr) ); } /* is this content chunked? */ chunked = ap_find_last_token(r->pool, ap_table_get(resp_hdrs, "Transfer-Encoding"), "chunked"); /* strip hop-by-hop headers defined by Connection and RFC2616 */ ap_proxy_clear_connection(p, resp_hdrs); content_length = ap_table_get(resp_hdrs, "Content-Length"); if (content_length != NULL) { c->len = ap_strtol(content_length, NULL, 10); if (c->len < 0) { ap_kill_timeout(r); return ap_proxyerror(r, HTTP_BAD_GATEWAY, ap_pstrcat(r->pool, "Invalid Content-Length from remote server", NULL)); } } } else { /* an http/0.9 response */ /* no headers */ resp_hdrs = ap_make_table(p, 20); } ap_kill_timeout(r); /* * HTTP/1.1 requires us to accept 3 types of dates, but only generate one * type */ /* * we SET the dates here, obliterating possible multiple dates, as only * one of each date makes sense in each response. */ if ((datestr = ap_table_get(resp_hdrs, "Date")) != NULL) ap_table_set(resp_hdrs, "Date", ap_proxy_date_canon(p, datestr)); if ((datestr = ap_table_get(resp_hdrs, "Last-Modified")) != NULL) ap_table_set(resp_hdrs, "Last-Modified", ap_proxy_date_canon(p, datestr)); if ((datestr = ap_table_get(resp_hdrs, "Expires")) != NULL) ap_table_set(resp_hdrs, "Expires", ap_proxy_date_canon(p, datestr)); /* handle the ProxyPassReverse mappings */ if ((urlstr = ap_table_get(resp_hdrs, "Location")) != NULL) ap_table_set(resp_hdrs, "Location", proxy_location_reverse_map(r, urlstr)); if ((urlstr = ap_table_get(resp_hdrs, "URI")) != NULL) ap_table_set(resp_hdrs, "URI", proxy_location_reverse_map(r, urlstr)); if ((urlstr = ap_table_get(resp_hdrs, "Content-Location")) != NULL) ap_table_set(resp_hdrs, "Content-Location", proxy_location_reverse_map(r, urlstr)); /* check if NoCache directive on this host */ { struct sockaddr_in *sin; struct sockaddr_in6 *sin6; if (nocache == 0) { for (i = 0; i < conf->nocaches->nelts; i++) { if (ncent[i].name != NULL && (ncent[i].name[0] == '*' || strstr(desthost, ncent[i].name) != NULL)) { nocache = 1; break; } switch (res->ai_addr->sa_family) { case AF_INET: sin = (struct sockaddr_in *)res->ai_addr; if (sin->sin_addr.s_addr == ncent[i].addr.s_addr) { nocache = 1; break; } } } /* update the cache file, possibly even fulfilling the request if * it turns out a conditional allowed us to serve the object from the * cache... */ i = ap_proxy_cache_update(c, resp_hdrs, !backasswards, nocache); if (i != DECLINED) { ap_bclose(f); return i; } /* write status line and headers to the cache file */ ap_proxy_write_headers(c, ap_pstrcat(p, "HTTP/1.1 ", r->status_line, NULL), resp_hdrs); } } /* Setup the headers for our client from upstreams response-headers */ ap_proxy_table_replace(r->headers_out, resp_hdrs); /* Add X-Cache header - be careful not to obliterate any upstream headers */ ap_table_mergen(r->headers_out, "X-Cache", ap_pstrcat(r->pool, "MISS from ", ap_get_server_name(r), NULL)); /* The Content-Type of this response is the upstream one. */ r->content_type = ap_table_get(r->headers_out, "Content-Type"); ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server, "Content-Type: %s", r->content_type); /* finally output the headers to the client */ ap_send_http_header(r); /* * Is it an HTTP/0.9 respose? If so, send the extra data we read from * upstream as the start of the reponse to client */ /* FIXME: This code is broken: we try and write a buffer and length that * were never intelligently initialised. Rather have a bit of broken protocol * handling for now than broken code. */ /* if (backasswards) { ap_hard_timeout("proxy send assbackward", r); ap_bwrite(r->connection->client, buffer, len); if (c != NULL && c->fp != NULL && ap_bwrite(c->fp, buffer, len) != len) { ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req, "proxy: error writing extra data to %s", c->tempfile); c = ap_proxy_cache_error(c); } ap_kill_timeout(r); } */ /* send body */ /* if header only, then cache will be NULL */ /* HTTP/1.0 tells us to read to EOF, rather than content-length bytes */ /* XXX CHANGEME: We want to eventually support keepalives, which means * we must read content-length bytes... */ if (!r->header_only) { /* we need to set this for ap_proxy_send_fb()... */ c->cache_completion = conf->cache.cache_completion; /* XXX CHECKME: c->len should be the expected content length, or -1 if the * content length is not known. We need to make 100% sure c->len is always * set correctly before we get here to correctly do keepalive. */ ap_proxy_send_fb(f, r, c, c->len, 0, chunked, conf->io_buffer_size); } /* ap_proxy_send_fb() closes the socket f for us */ ap_proxy_cache_tidy(c); ap_proxy_garbage_coll(r); return OK; }
/* ** dav_load_lock_record: Reads lock information about key from lock db; ** creates linked lists of the direct and indirect locks. ** ** If add_method = DAV_APPEND_LIST, the result will be appended to the ** head of the direct and indirect lists supplied. ** ** Passive lock removal: If lock has timed out, it will not be returned. ** ### How much "logging" does RFC 2518 require? */ static dav_error * dav_fs_load_lock_record(dav_lockdb *lockdb, dav_datum key, int add_method, dav_lock_discovery **direct, dav_lock_indirect **indirect) { dav_error *err; size_t offset = 0; int need_save = DAV_FALSE; dav_datum val = { 0 }; dav_lock_discovery *dp; dav_lock_indirect *ip; dav_buffer buf = { 0 }; if (add_method != DAV_APPEND_LIST) { *direct = NULL; *indirect = NULL; } if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) { /* ### add a higher-level error? */ return err; } /* ** If we opened readonly and the db wasn't there, then there are no ** locks for this resource. Just exit. */ if (lockdb->info->db == NULL) return NULL; if ((err = (*dav_hooks_db_dbm.fetch)(lockdb->info->db, key, &val)) != NULL) return err; if (!val.dsize) return NULL; while (offset < val.dsize) { switch (*(val.dptr + offset++)) { case DAV_LOCK_DIRECT: /* Create and fill a dav_lock_discovery structure */ dp = ap_pcalloc(lockdb->info->pool, sizeof(*dp)); memcpy(dp, val.dptr + offset, sizeof(dp->f)); offset += sizeof(dp->f); dp->locktoken = ap_palloc(lockdb->info->pool, sizeof(*dp->locktoken)); memcpy(dp->locktoken, val.dptr + offset, sizeof(*dp->locktoken)); offset += sizeof(*dp->locktoken); if (*(val.dptr + offset) == '\0') { ++offset; } else { dp->owner = ap_pstrdup(lockdb->info->pool, val.dptr + offset); offset += strlen(dp->owner) + 1; } if (*(val.dptr + offset) == '\0') { ++offset; } else { dp->auth_user = ap_pstrdup(lockdb->info->pool, val.dptr + offset); offset += strlen(dp->auth_user) + 1; } if (!dav_fs_lock_expired(dp->f.timeout)) { dp->next = *direct; *direct = dp; } else { need_save = DAV_TRUE; /* Remove timed-out locknull fm .locknull list */ if (*key.dptr == DAV_TYPE_FNAME) { const char *fname = key.dptr + 1; struct stat finfo; /* if we don't see the file, then it's a locknull */ if (lstat(fname, &finfo) != 0) { if ((err = dav_fs_remove_locknull_member(lockdb->info->pool, fname, &buf)) != NULL) { /* ### push a higher-level description? */ return err; } } } } break; case DAV_LOCK_INDIRECT: /* Create and fill a dav_lock_indirect structure */ ip = ap_pcalloc(lockdb->info->pool, sizeof(*ip)); ip->locktoken = ap_palloc(lockdb->info->pool, sizeof(*ip->locktoken)); memcpy(ip->locktoken, val.dptr + offset, sizeof(*ip->locktoken)); offset += sizeof(*ip->locktoken); memcpy(&ip->timeout, val.dptr + offset, sizeof(ip->timeout)); offset += sizeof(ip->timeout); memcpy(&ip->key.dsize, val.dptr + offset, sizeof(int)); /* length of datum */ offset += sizeof(ip->key.dsize); ip->key.dptr = ap_palloc(lockdb->info->pool, ip->key.dsize); memcpy(ip->key.dptr, val.dptr + offset, ip->key.dsize); offset += ip->key.dsize; if (!dav_fs_lock_expired(ip->timeout)) { ip->next = *indirect; *indirect = ip; } else { need_save = DAV_TRUE; /* A locknull resource will never be locked indirectly */ } break; default: (*dav_hooks_db_dbm.freedatum)(lockdb->info->db, val); /* ### should use a computed_desc and insert corrupt token data */ --offset; return dav_new_error(lockdb->info->pool, HTTP_INTERNAL_SERVER_ERROR, DAV_ERR_LOCK_CORRUPT_DB, ap_psprintf(lockdb->info->pool, "The lock database was found to " "be corrupt. offset %i, c=%02x", offset, val.dptr[offset])); } } (*dav_hooks_db_dbm.freedatum)(lockdb->info->db, val); /* Clean up this record if we found expired locks */ /* ** ### shouldn't do this if we've been opened READONLY. elide the ** ### timed-out locks from the response, but don't save that info back */ if (need_save == DAV_TRUE) { return dav_fs_save_lock_record(lockdb, key, *direct, *indirect); } return NULL; }