/* * Send back a simple error page */ void http_response_send_error(struct http_response *resp, int code, const char *fmt, ...) { struct http_request *const req = resp->msg->conn->req; const char *ua; FILE *fp; int i; /* Check headers already sent */ if (resp->msg->hdrs_sent) return; /* Set response line info */ http_response_set_header(resp, 0, HDR_REPLY_STATUS, "%d", code); http_response_set_header(resp, 0, HDR_REPLY_REASON, "%s", http_response_status_msg(code)); /* Set additional headers */ http_response_set_header(resp, 0, HTTP_HEADER_CONTENT_TYPE, "text/html; charset=iso-8859-1"); /* Close connection for real errors */ if (code >= 400) { http_response_set_header(resp, 0, _http_message_connection_header(resp->msg), "close"); } /* Send error page body */ if ((fp = http_response_get_output(resp, 1)) == NULL) return; fprintf(fp, "<HTML>\n<HEAD>\n<TITLE>%d %s</TITLE></HEAD>\n", code, http_response_status_msg(code)); fprintf(fp, "<BODY BGCOLOR=\"#FFFFFF\">\n<H3>%d %s</H3>\n", code, http_response_status_msg(code)); if (fmt != NULL) { va_list args; fprintf(fp, "<B>"); va_start(args, fmt); vfprintf(fp, fmt, args); va_end(args); fprintf(fp, "</B>\n"); } #if 0 fprintf(fp, "<P></P>\n<HR>\n"); fprintf(fp, "<FONT SIZE=\"-1\"><EM>%s</EM></FONT>\n", serv->server_name); #endif /* Add fillter for IE */ if ((ua = http_request_get_header(req, HTTP_HEADER_USER_AGENT)) != NULL && strstr(ua, "IE") != NULL) { for (i = 0; i < 20; i++) { fprintf(fp, "<!-- FILLER TO MAKE INTERNET EXPLORER SHOW" " THIS PAGE INSTEAD OF ITS OWN PAGE -->\n"); } } fprintf(fp, "</BODY>\n</HTML>\n"); }
static int WebServletRun(struct http_servlet *servlet, struct http_request *req, struct http_response *resp) { FILE *f; const char *path; const char *query; int priv = 0; if (Enabled(&gWeb.options, WEB_AUTH)) { const char *username; const char *password; ConsoleUser u; struct console_user iu; /* Get username and password */ if ((username = http_request_get_username(req)) == NULL) username = ""; if ((password = http_request_get_password(req)) == NULL) password = ""; strlcpy(iu.username, username, sizeof(iu.username)); RWLOCK_RDLOCK(gUsersLock); u = ghash_get(gUsers, &iu); RWLOCK_UNLOCK(gUsersLock); if ((u == NULL) || strcmp(u->password, password)) { http_response_send_basic_auth(resp, "Access Restricted"); return (1); } priv = u->priv; } if (!(f = http_response_get_output(resp, 1))) { return 0; } if (!(path = http_request_get_path(req))) return 0; if (!(query = http_request_get_query_string(req))) return 0; if (!strcmp(path,"/mpd.css")) { http_response_set_header(resp, 0, "Content-Type", "text/css"); WebShowCSS(f); } else if (!strcmp(path,"/bincmd")) { http_response_set_header(resp, 0, "Content-Type", "text/plain"); http_response_set_header(resp, 1, "Pragma", "no-cache"); http_response_set_header(resp, 1, "Cache-Control", "no-cache, must-revalidate"); pthread_cleanup_push(WebServletRunCleanup, NULL); GIANT_MUTEX_LOCK(); WebRunBinCmd(f, query, priv); GIANT_MUTEX_UNLOCK(); pthread_cleanup_pop(0); } else if (!strcmp(path,"/") || !strcmp(path,"/cmd")) { http_response_set_header(resp, 0, "Content-Type", "text/html"); http_response_set_header(resp, 1, "Pragma", "no-cache"); http_response_set_header(resp, 1, "Cache-Control", "no-cache, must-revalidate"); pthread_cleanup_push(WebServletRunCleanup, NULL); GIANT_MUTEX_LOCK(); fprintf(f, "<!DOCTYPE HTML " "PUBLIC \"-//W3C//DTD HTML 4.01//EN\" " "\"http://www.w3.org/TR/html4/strict.dtd\">\n"); fprintf(f, "<HTML>\n"); fprintf(f, "<HEAD><TITLE>Multi-link PPP Daemon for FreeBSD (mpd)</TITLE>\n"); fprintf(f, "<LINK rel='stylesheet' href='/mpd.css' type='text/css'>\n"); fprintf(f, "</HEAD>\n<BODY>\n"); fprintf(f, "<H1>Multi-link PPP Daemon for FreeBSD</H1>\n"); if (!strcmp(path,"/")) WebShowSummary(f, priv); else if (!strcmp(path,"/cmd")) WebRunCmd(f, query, priv); GIANT_MUTEX_UNLOCK(); pthread_cleanup_pop(0); fprintf(f, "</BODY>\n</HTML>\n"); } else { http_response_send_error(resp, 404, NULL); } return 1; }
/* * Run template servlet */ static int http_servlet_tmpl_run(struct http_servlet *servlet, struct http_request *req, struct http_response *resp) { struct tmpl_private *const priv = servlet->arg; struct http_servlet_tmpl_info *const info = &priv->info; struct http_servlet_tmpl_tinfo *const tinfo = &priv->info.tinfo; struct tmpl_instance *this = NULL; FILE *output = NULL; const char *hval; struct stat sb; int num_errors; int r; /* Construct per-instance state */ if ((this = MALLOC(MEM_TYPE, sizeof(*this))) == NULL) { (*info->logger)(LOG_ERR, "%s: %s: %s", __FUNCTION__, "malloc", strerror(errno)); return (-1); } memset(this, 0, sizeof(*this)); this->priv = priv; /* Grab lock to avoid race with http_servlet_tmpl_destroy() */ r = pthread_rwlock_rdlock(&priv->lock); assert(r == 0); /* Push cleanup hook in case thread gets canceled */ pthread_cleanup_push(http_servlet_tmpl_run_cleanup, this); /* Get servlet output stream (buffered) */ if ((output = http_response_get_output(resp, 1)) == NULL) { (*info->logger)(LOG_ERR, "can't get template output: %s", strerror(errno)); goto fail_errno; } /* Set MIME type */ if (info->mime_type == NULL) { http_response_set_header(resp, 0, HTTP_HEADER_CONTENT_TYPE, "text/html; charset=iso-8859-1"); } else { http_response_set_header(resp, 0, HTTP_HEADER_CONTENT_TYPE, "%s", info->mime_type); if (info->mime_encoding != NULL) { http_response_set_header(resp, 0, HTTP_HEADER_CONTENT_ENCODING, "%s", info->mime_encoding); } } /* Assume servlet output is not cachable */ http_response_set_header(resp, 1, HTTP_HEADER_PRAGMA, "no-cache"); http_response_set_header(resp, 0, HTTP_HEADER_CACHE_CONTROL, "no-cache"); /* Get modification timestamp of the template file */ if (stat(info->path, &sb) == -1) { (*info->logger)(LOG_ERR, "%s: %s: %s", __FUNCTION__, info->path, strerror(errno)); memset(&sb.st_mtime, 0, sizeof(sb.st_mtime)); } /* Invalidate cached template if template file has changed */ if (priv->tmpl != NULL && memcmp(&sb.st_mtime, &priv->mtime, sizeof(priv->mtime)) != 0) { (*info->logger)(LOG_INFO, "template \"%s\" was updated", info->path); tmpl_destroy(&priv->tmpl); } /* Do we need to (re)parse the template? */ if (priv->tmpl == NULL) { /* Parse template file */ if ((priv->tmpl = tmpl_create_mmap(info->path, &num_errors, tinfo->mtype)) == NULL) { (*info->logger)(LOG_ERR, "can't create template from \"%s\": %s", info->path, strerror(errno)); goto fail_errno; } /* Check for an error from tmpl_create() */ if (priv->tmpl == NULL) { (*info->logger)(LOG_ERR, "can't create \"%s\" template: %s", info->path, strerror(errno)); goto fail_errno; } /* Warn if there were any parse errors */ if (num_errors != 0) { (*info->logger)(LOG_WARNING, "%d parse error%s in template \"%s\"", num_errors, num_errors == 1 ? "" : "s", info->path); } /* Update last modified time */ memcpy(&priv->mtime, &sb.st_mtime, sizeof(priv->mtime)); } /* Read URL-encoded form data if this is a normal POST */ if (strcmp(http_request_get_method(req), HTTP_METHOD_POST) == 0 && (hval = http_request_get_header(req, HTTP_HEADER_CONTENT_TYPE)) != NULL && strcasecmp(hval, HTTP_CTYPE_FORM_URLENCODED) == 0) { if (http_request_read_url_encoded_values(req) == -1) { (*info->logger)(LOG_ERR, "error reading %s data for \"%s\" template: %s", HTTP_METHOD_POST, info->path, strerror(errno)); goto fail_errno; } } /* Fill in handler function cookie */ this->targ.arg = info->tinfo.arg; this->targ.req = req; this->targ.resp = resp; /* Create tmpl execution context */ if ((this->ctx = tmpl_ctx_create(&this->targ, tinfo->mtype, tinfo->handler, tinfo->errfmtr)) == NULL) { (*info->logger)(LOG_ERR, "%s: %s: %s", __FUNCTION__, "tmpl_ctx_create", strerror(errno)); goto fail_errno; } /* Execute template */ if (tmpl_execute(priv->tmpl, this->ctx, output, tinfo->flags) == -1) { (*info->logger)(LOG_ERR, "can't execute \"%s\" template: %s", info->path, strerror(errno)); goto fail_errno; } /* OK */ goto done; fail_errno: /* Fail with appropriate error response */ http_response_send_errno_error(resp); done: /* Done */ if (output != NULL) fclose(output); pthread_cleanup_pop(1); return (1); }