/* * Name: env_gen_extra * (and via a not-so-tricky #define, env_gen) * This routine calls malloc: please free the memory when you are done */ static char *env_gen_extra(const char *key, const char *value, int extra) { char *result; int key_len, value_len; if (value == NULL) /* ServerAdmin may not be defined, eg */ value = ""; key_len = strlen(key); value_len = strlen(value); /* leave room for '=' sign and null terminator */ result = malloc(extra + key_len + value_len + 2); if (result) { memcpy(result + extra, key, key_len); *(result + extra + key_len) = '='; memcpy(result + extra + key_len + 1, value, value_len); *(result + extra + key_len + value_len + 1) = '\0'; } else { log_error_time(); log_error_mesg(__FILE__, __LINE__, "not enough memory for env_gen_extra! Not fatal.\n"); log_error_time(); fprintf(stderr, "tried to allocate (key=value) extra=%d: %s=%s\n", extra, key, value); } return result; }
/* * Name: env_gen_extra * (and via a not-so-tricky #define, env_gen) * This routine calls malloc: please free the memory when you are done */ static char *env_gen_extra(const char *key, const char *value, int extra) { char *result; int key_len, value_len; if (value == NULL) value = ""; key_len = strlen(key); value_len = strlen(value); result = malloc(extra + key_len + value_len + 2); if (result) { memcpy(result + extra, key, key_len); *(result + extra + key_len) = '='; memcpy(result + extra + key_len + 1, value, value_len); *(result + extra + key_len + value_len + 1) = '\0'; } else { log_error_time(); perror("malloc"); log_error_time(); fprintf(stderr, "tried to allocate (key=value) extra=%d: %s=%s\n", extra, key, value); } return result; }
static void c_set_group(char *v1, char *v2, void *t) { struct group *groupbuf; char *endptr; int i; DEBUG(DEBUG_CONFIG) { log_error_time(); printf("Group %s = ", v1); } i = strtol(v1, &endptr, 0); if (*v1 != '\0' && *endptr == '\0') { server_gid = i; } else { groupbuf = getgrnam(v1); if (!groupbuf) { log_error_time(); fprintf(stderr, "No such group: %s\n", v1); if (current_uid) return; exit(EXIT_FAILURE); } server_gid = groupbuf->gr_gid; } DEBUG(DEBUG_CONFIG) { printf("%d\n", server_gid); } }
int add_cgi_env(request * req, char *key, char *value, int http_prefix) { char *p; int prefix_len; if (http_prefix) { prefix_len = 5; } else { prefix_len = 0; } if (req->cgi_env_index < CGI_ENV_MAX) { p = env_gen_extra(key, value, prefix_len); if (!p) { log_error_time(); fprintf(stderr, "Unable to generate additional CGI Environment" "variable -- ran out of memory!\n"); } if (prefix_len) memcpy(p, "HTTP_", 5); req->cgi_env[req->cgi_env_index++] = p; return 1; } else { log_error_time(); fprintf(stderr, "Unable to generate additional CGI Environment" "variable -- not enough space!\n"); } return 0; }
static void c_set_user(char *v1, char *v2, void *t) { struct passwd *passwdbuf; char *endptr; int i; DEBUG(DEBUG_CONFIG) { log_error_time(); printf("User %s = ", v1); } i = strtol(v1, &endptr, 0); if (*v1 != '\0' && *endptr == '\0') { server_uid = i; } else { passwdbuf = getpwnam(v1); if (!passwdbuf) { log_error_time(); fprintf(stderr, "No such user: %s\n", v1); if (current_uid) return; exit(EXIT_FAILURE); } server_uid = passwdbuf->pw_uid; } DEBUG(DEBUG_CONFIG) { printf("%d\n", server_uid); } }
static hash_struct *hash_find(hash_struct * table[], const char *key, const unsigned int hash) { hash_struct *current; current = table[hash]; if (!key) { log_error_time(); fprintf(stderr, "Yipes! Null value sent as key! [hash_find]!\n"); return NULL; } else if (key[0] == '\0') { log_error_time(); fprintf(stderr, "Attempt to locate empty string in hash! [hash_find]!\n"); return NULL; } while (current) { if (!strcmp(current->key, key)) /* hit */ return current; current = current->next; } return NULL; }
void sighup_run(void) { sighup_flag = 0; time(¤t_time); log_error_time(); fputs("caught SIGHUP, restarting\n", stderr); /* Philosophy change for 0.92: don't close and attempt reopen of logfiles, * since usual permission structure prevents such reopening. */ FD_ZERO(&block_read_fdset); FD_ZERO(&block_write_fdset); /* clear_common_env(); NEVER DO THIS */ dump_mime(); dump_passwd(); dump_alias(); free_requests(); log_error_time(); fputs("re-reading configuration files\n", stderr); read_config_files(); log_error_time(); fputs("successful restart\n", stderr); }
/* * Name: env_gen_extra * (and via a not-so-tricky #define, env_gen) * This routine calls malloc: please free the memory when you are done */ static char *env_gen_extra(const char *key, const char *value, unsigned int extra) { char *result; unsigned int key_len, value_len; if (value == NULL) /* ServerAdmin may not be defined, eg */ value = ""; key_len = strlen(key); value_len = strlen(value); /* leave room for '=' sign and null terminator */ result = malloc(extra + key_len + value_len + 2); if (result) { memcpy(result + extra, key, key_len); *(result + extra + key_len) = '='; memcpy(result + extra + key_len + 1, value, value_len); *(result + extra + key_len + value_len + 1) = '\0'; } else { log_error_time(); perror("malloc"); log_error_time(); fprintf(stderr, "tried to allocate (key=value) extra=%u: %s=%s\n", extra, key, value); } return result; }
void create_common_env() { int index = 0, i; /* NOTE NOTE NOTE: If you (the reader) someday modify this chunk of code to handle more "common" CGI environment variables, then bump the value COMMON_CGI_COUNT in defines.h UP Also, in the case of document_root and server_admin, two variables that may or may not be defined depending on the way the server is configured, we check for null values and use an empty string to denote a NULL value to the environment, as per the specification. The quote for which follows: "In all cases, a missing environment variable is equivalent to a zero-length (NULL) value, and vice versa." */ common_cgi_env[index++] = env_gen_extra("PATH", ((cgi_path != NULL) ? cgi_path : DEFAULT_PATH), 0); common_cgi_env[index++] = env_gen_extra("SERVER_SOFTWARE", SERVER_VERSION, 0); common_cgi_env[index++] = env_gen_extra("SERVER_NAME", server_name, 0); common_cgi_env[index++] = env_gen_extra("GATEWAY_INTERFACE", CGI_VERSION, 0); common_cgi_env[index++] = env_gen_extra("SERVER_PORT", simple_itoa(server_port), 0); /* NCSA and APACHE added -- not in CGI spec */ /* common_cgi_env[index++] = env_gen_extra("DOCUMENT_ROOT", document_root); */ /* NCSA added */ /* common_cgi_env[index++] = env_gen_extra("SERVER_ROOT", server_root); */ /* APACHE added */ common_cgi_env[index++] = env_gen_extra("SERVER_ADMIN", server_admin, 0); common_cgi_env[index] = NULL; /* Sanity checking -- make *sure* the memory got allocated */ if (index > COMMON_CGI_COUNT) { log_error_time(); fprintf(stderr, "COMMON_CGI_COUNT not high enough.\n"); exit(1); } for(i = 0;i < index;++i) { if (common_cgi_env[i] == NULL) { log_error_time(); fprintf(stderr, "Unable to allocate a component of common_cgi_env - out of memory.\n"); exit(1); } } }
static void set_root() { if (chroot_dir != NULL) { if (chdir(chroot_dir) == -1) { log_error_time(); perror("chdir (to chroot)"); exit(EXIT_FAILURE); } if (chroot(chroot_dir) == -1) { log_error_time(); perror("chroot"); exit(EXIT_FAILURE); } if (chdir("/") == -1) { log_error_time(); perror("chdir (after chroot)"); exit(EXIT_FAILURE); } free(chroot_dir); } /* server_root is a very useful variable, we get it from * document_root (e.g. given /var/www, server_root is set to /var/) * or from getcwd */ if (document_root != NULL) { if (document_root[0] == '/') { /* absolute path */ unsigned int c = 0, i = 1, len = strlen(document_root); if (document_root[len - 1] == '/') len--; for (;i < len; i++) { if (document_root[i] == '/') c = i; } server_root = strdup(document_root); server_root[c + 1] = '\0'; } else { /* relative path */ char cpt[1025]; if (getcwd(cpt, sizeof(cpt)) == cpt) { unsigned int len = strlen(cpt); cpt[len++] = '/'; cpt[len] = '\0'; server_root = strdup(cpt); /* server_root[len] = '\0'; */ } else { perror("getcwd"); DIE("could not set server_root\n"); } } server_root_len = strlen (server_root); } }
void show_hash_stats(void) { int i; hash_struct *temp; int total = 0; int count; for (i = 0; i < MIME_HASHTABLE_SIZE; ++i) { if (mime_hashtable[i]) { count = 0; temp = mime_hashtable[i]; while (temp) { temp = temp->next; ++count; } #ifdef NOISY_SIGALRM log_error_time(); fprintf(stderr, "mime_hashtable[%d] has %d entries\n", i, count); #endif total += count; } } log_error_time(); fprintf(stderr, "mime_hashtable has %d total entries\n", total); total = 0; for (i = 0; i < PASSWD_HASHTABLE_SIZE; ++i) { if (passwd_hashtable[i]) { temp = passwd_hashtable[i]; count = 0; while (temp) { temp = temp->next; ++count; } #ifdef NOISY_SIGALRM log_error_time(); fprintf(stderr, "passwd_hashtable[%d] has %d entries\n", i, count); #endif total += count; } } log_error_time(); fprintf(stderr, "passwd_hashtable has %d total entries\n", total); }
void sigchld_run(void) { int status; pid_t pid; #ifdef BOA_DEBUG struct timeval tv; #endif sigchld_flag = 0; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { #ifdef BOA_DEBUG if (verbose_cgi_logs) { time(¤t_time); log_error_time(); gettimeofday(&tv,NULL); fprintf(stderr, "reaping child %d: status %d;%u,%u\n", (int) pid, status,tv.tv_usec,tv.tv_sec); } #endif } return; }
static void sanitize_request(request * req, int new_req) { static unsigned int bytes_to_zero = offsetof(request, fd); if (new_req) { req->kacount = ka_max; req->time_last = current_time; req->client_stream_pos = 0; } else { unsigned int bytes_to_move = req->client_stream_pos - req->parse_pos; if (bytes_to_move) { memmove(req->client_stream, req->client_stream + req->parse_pos, bytes_to_move); } req->client_stream_pos = bytes_to_move; } /* bzero */ /* we want to clear a middle part of the request: */ DEBUG(DEBUG_REQUEST) { log_error_time(); fprintf(stderr, "req: %p, offset: %d\n", (void *) req, bytes_to_zero); } memset(req, 0, bytes_to_zero); req->status = READ_HEADER; req->header_line = req->client_stream; }
void sigterm_stage1_run(void) { /* lame duck mode */ time(¤t_time); log_error_time(); fputs("caught SIGTERM, starting shutdown\n", stderr); sigterm_flag = 2; }
static void drop_privs(void) { if (getuid() == 0) { struct passwd *passwdbuf; passwdbuf = getpwuid(server_uid); if (passwdbuf == NULL) { DIE("getpwuid"); } if (initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1) { DIE("initgroups"); } if (setgid(server_gid) == -1) { DIE("setgid"); } if (setuid(server_uid) == -1) { DIE("setuid"); } /* test for failed-but-return-was-successful setuid * http://www.securityportal.com/list-archive/bugtraq/2000/Jun/0101.html */ if (setuid(0) != -1) { DIE("icky Linux kernel bug!"); } } else { if (server_gid || server_uid) { log_error_time(); fprintf(stderr, "Warning: " "Not running as root: no attempt to change" " to uid %d gid %d\n", server_uid, server_gid); } server_gid = getgid(); server_uid = getuid(); } }
void sigint(int dummy) { time(¤t_time); log_error_time(); fputs("caught SIGINT: shutting down\n", stderr); fclose(stderr); chdir(tempdir); exit(1); }
void sigsegv(int dummy) { time(¤t_time); log_error_time(); fprintf(stderr, "caught SIGSEGV, dumping core in %s\n", tempdir); fclose(stderr); chdir(tempdir); abort(); }
void sigterm_stage1_run(int server_s) /* lame duck mode */ { time(¤t_time); log_error_time(); fputs("caught SIGTERM, starting shutdown\n", stderr); FD_CLR(server_s, &block_read_fdset); close(server_s); sigterm_flag = 2; }
void sigint(int dummy) { time(¤t_time); log_error_time(); fputs("caught SIGINT: shutting down\n", stderr); if (chdir(tempdir) == -1) perror ("chdir (tempdir) failed"); exit(EXIT_FAILURE); }
void sigsegv(int dummy) { time(¤t_time); log_error_time(); fprintf(stderr, "caught SIGSEGV, dumping core in %s\n", tempdir); if (chdir(tempdir) == -1) perror ("chdir (tempdir) failed"); abort(); }
void sigalrm_run(void) { time(¤t_time); log_error_time(); fprintf(stderr, "%ld requests, %ld errors\n", status.requests, status.errors); show_hash_stats(); sigalrm_flag = 0; }
int modified_since(time_t * mtime, char *if_modified_since) { struct tm *file_gmt; char *ims_info; char monthname[10 + 1]; int day, month, year, hour, minute, second; int comp; ims_info = if_modified_since; while (*ims_info != ' ' && *ims_info != '\0') ++ims_info; if (*ims_info != ' ') return -1; if (sscanf(ims_info, "%d %3s %d %d:%d:%d GMT", &day, monthname, &year, &hour, &minute, &second) == 6); else if (sscanf(ims_info, "%d-%3s-%d %d:%d:%d GMT", &day, monthname, &year, &hour, &minute, &second) == 6) year += 1900; else if (sscanf(ims_info, " %3s %d %d:%d:%d %d", monthname, &day, &hour, &minute, &second, &year) == 6); /* NOTE: Use if_modified_since here, because the date *starts* * with the day, versus a throwaway item */ else if (sscanf(if_modified_since, "%d %10s %d %d:%d:%d GMT", &day, monthname, &year, &hour, &minute, &second) == 6); else { log_error_time(); fprintf(stderr, "Error in %s, line %d: Unable to sscanf \"%s\"\n", __FILE__, __LINE__, ims_info); return -1; } file_gmt = gmtime(mtime); month = month2int(monthname); /* Go through from years to seconds -- if they are ever unequal, we know which one is newer and can return */ if ((comp = 1900 + file_gmt->tm_year - year)) return (comp > 0); if ((comp = file_gmt->tm_mon - month)) return (comp > 0); if ((comp = file_gmt->tm_mday - day)) return (comp > 0); if ((comp = file_gmt->tm_hour - hour)) return (comp > 0); if ((comp = file_gmt->tm_min - minute)) return (comp > 0); if ((comp = file_gmt->tm_sec - second)) return (comp > 0); return 0; }
int modified_since(time_t * mtime, char *if_modified_since) { struct tm *file_gmt; char *ims_info; char monthname[10 + 1]; int day, month, year, hour, minute, second; int comp; ims_info = if_modified_since; while (*ims_info != ' ' && *ims_info != '\0') ++ims_info; if (*ims_info != ' ') return -1; /* the pre-space in the third scanf skips whitespace for the string */ if (sscanf(ims_info, "%d %3s %d %d:%d:%d GMT", /* RFC 1123 */ &day, monthname, &year, &hour, &minute, &second) == 6); else if (sscanf(ims_info, "%d-%3s-%d %d:%d:%d GMT", /* RFC 1036 */ &day, monthname, &year, &hour, &minute, &second) == 6) year += 1900; else if (sscanf(ims_info, " %3s %d %d:%d:%d %d", /* asctime() format */ monthname, &day, &hour, &minute, &second, &year) == 6); /* allow this non-standard date format: 31 September 2000 23:59:59 GMT */ /* NOTE: Use if_modified_since here, because the date *starts* * with the day, versus a throwaway item */ else if (sscanf(if_modified_since, "%d %10s %d %d:%d:%d GMT", &day, monthname, &year, &hour, &minute, &second) == 6); else { log_error_time(); fprintf(stderr, "Error in %s, line %d: Unable to sscanf \"%s\"\n", __FILE__, __LINE__, ims_info); return -1; /* error */ } file_gmt = gmtime(mtime); month = month2int(monthname); /* Go through from years to seconds -- if they are ever unequal, we know which one is newer and can return */ if ((comp = 1900 + file_gmt->tm_year - year)) return (comp > 0); if ((comp = file_gmt->tm_mon - month)) return (comp > 0); if ((comp = file_gmt->tm_mday - day)) return (comp > 0); if ((comp = file_gmt->tm_hour - hour)) return (comp > 0); if ((comp = file_gmt->tm_min - minute)) return (comp > 0); if ((comp = file_gmt->tm_sec - second)) return (comp > 0); return 0; /* this person must really be into the latest/greatest */ }
static unsigned boa_hash(const char *str) { if (str == NULL || str[0] == '\0') { log_error_time(); fprintf(stderr, "Attempt to hash NULL or empty string! [boa_hash]!\n"); return 0; } return _boa_hash(str); }
int create_temporary_file(short want_unlink, char *storage, int size) { static char boa_tempfile[MAX_PATH_LENGTH + 1]; int fd; snprintf(boa_tempfile, MAX_PATH_LENGTH, "%s/boa-temp.XXXXXX", tempdir); /* open temp file */ fd = mkstemp(boa_tempfile); if (fd == -1) { log_error_time(); perror("mkstemp"); return 0; } if (storage != NULL) { int len = strlen(boa_tempfile); if (len < size) { memcpy(storage, boa_tempfile, len + 1); } else { close(fd); fd = 0; log_error_time(); fprintf(stderr, "not enough memory for memcpy in storage\n"); want_unlink = 1; } } if (want_unlink) { if (unlink(boa_tempfile) == -1) { close(fd); fd = 0; log_error_time(); fprintf(stderr, "unlink temp file\n"); } } return (fd); }
static unsigned four_char_hash(const char *buf) { unsigned int hash = (buf[0] + (buf[1] ? buf[1] : 241 + (buf[2] ? buf[2] : 251 + (buf[3] ? buf[3] : 257)))); DEBUG(DEBUG_HASH) { log_error_time(); fprintf(stderr, "four_char_hash(%s) = %u\n", buf, hash); } return hash; }
static unsigned four_char_hash(char *buf) { unsigned int hash = (buf[0] + (buf[1] ? buf[1] : 241 + (buf[2] ? buf[2] : 251 + (buf[3] ? buf[3] : 257)))); #ifdef DEBUG_HASH log_error_time(); fprintf(stderr, "four_char_hash(%s) = %u\n", buf, hash); #endif return hash; }
void sigbus(int dummy) { if (handle_sigbus) { longjmp(env, dummy); } time(¤t_time); log_error_time(); fprintf(stderr, "caught SIGBUS, dumping core in %s\n", tempdir); fclose(stderr); chdir(tempdir); abort(); }
int process_option_line(request * req) { char c, *value, *line = req->header_line; /* Start by aggressively hacking the in-place copy of the header line */ #ifdef FASCIST_LOGGING log_error_time(); fprintf(stderr, "%s:%d - Parsing \"%s\"\n", __FILE__, __LINE__, line); #endif value = strchr(line, ':'); if (value == NULL) return 0; *value++ = '\0'; /* overwrite the : */ to_upper(line); /* header types are case-insensitive */ while ((c = *value) && (c == ' ' || c == '\t')) value++; if (!memcmp(line, "IF_MODIFIED_SINCE", 18) && !req->if_modified_since) req->if_modified_since = value; else if (!memcmp(line, "CONTENT_TYPE", 13) && !req->content_type) req->content_type = value; else if (!memcmp(line, "CONTENT_LENGTH", 15) && !req->content_length) req->content_length = value; else if (!memcmp(line, "CONNECTION", 11) && ka_max && req->keepalive != KA_STOPPED) { req->keepalive = (!strncasecmp(value, "Keep-Alive", 10) ? KA_ACTIVE : KA_STOPPED); } /* #ifdef ACCEPT_ON */ else if (!memcmp(line, "ACCEPT", 7)) add_accept_header(req, value); /* #endif */ /* Need agent and referer for logs */ else if (!memcmp(line, "REFERER", 8)) { req->header_referer = value; if (!add_cgi_env(req, "REFERER", value, 1)) return 0; } else if (!memcmp(line, "USER_AGENT", 11)) { req->header_user_agent = value; if (!add_cgi_env(req, "USER_AGENT", value, 1)) return 0; } else { if (!add_cgi_env(req, line, value, 1)) return 0; } return 1; }
void sigterm_stage2_run() /* lame duck mode */ { log_error_time(); fprintf(stderr, "exiting Boa normally (uptime %d seconds)\n", (int) (current_time - start_time)); chdir(tempdir); clear_common_env(); dump_mime(); dump_passwd(); dump_alias(); free_requests(); exit(0); }