* httpd.c: implementation of httpd.h.
*/
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <syslog.h>
-
-#include "malloc.h"
+#include "agedu.h"
+#include "alloc.h"
#include "html.h"
#include "httpd.h"
{
return dupfmt("HTTP/1.1 %s %s\r\n"
"Date: %D\r\n"
- "Server: agedu\r\n"
+ "Server: " PNAME "\r\n"
"Connection: close\r\n"
"%s"
"Content-Type: text/html; charset=US-ASCII\r\n"
return dupfmt("HTTP/1.1 200 OK\r\n"
"Date: %D\r\n"
"Expires: %D\r\n"
- "Server: agedu\r\n"
+ "Server: " PNAME "\r\n"
"Connection: close\r\n"
"Content-Type: %s\r\n"
"\r\n"
* socket before closing it.
*/
char *got_data(struct connctx *ctx, char *data, int length,
- int magic_access, const char *auth_string)
+ int magic_access, const char *auth_string,
+ const struct html_config *cfg)
{
char *line, *p, *q, *r, *z1, *z2, c1, c2;
int auth_provided = 0, auth_correct = 0;
/* Restore the request to the way we received it. */
*z2 = c2;
*z1 = c1;
- text = dupfmt("<code>agedu</code> received the HTTP request"
+ text = dupfmt("<code>" PNAME "</code> received the HTTP request"
" \"<code>%h</code>\", which contains no URL.",
line);
ret = http_error("400", "Bad request", NULL, text);
}
if (!magic_access && !auth_correct) {
- if (auth_string && !auth_provided) {
+ if (auth_string) {
ret = http_error("401", "Unauthorized",
- "WWW-Authenticate: Basic realm=\"agedu\"\r\n",
- "Please authenticate to view these pages.");
+ "WWW-Authenticate: Basic realm=\""PNAME"\"\r\n",
+ "\nYou must authenticate to view these pages.");
} else {
ret = http_error("403", "Forbidden", NULL,
"This is a restricted-access set of pages.");
}
} else {
+ char *q;
p = ctx->url;
p += strspn(p, "/?");
- index = strtoul(p, NULL, 10);
- document = html_query(ctx->t, index, "%lu");
- if (document) {
- ret = http_success("text/html", 1, document);
- sfree(document);
- } else {
+ index = strtoul(p, &q, 10);
+ if (*q) {
ret = http_error("404", "Not Found", NULL,
- "Pathname index out of range.");
+ "This is not a valid pathname index.");
+ } else {
+ document = html_query(ctx->t, index, cfg);
+ if (document) {
+ ret = http_success("text/html", 1, document);
+ sfree(document);
+ } else {
+ ret = http_error("404", "Not Found", NULL,
+ "Pathname index out of range.");
+ }
}
}
return ret;
while (fgets(linebuf, sizeof(linebuf), fp)) {
if (strlen(linebuf) >= 75 &&
!strncmp(linebuf+6, matchbuf, strlen(matchbuf))) {
+ fclose(fp);
return atoi(linebuf + 75);
}
}
+ fclose(fp);
}
return -1;
out[3] = '=';
}
-void run_httpd(const void *t, int authmask)
+void run_httpd(const void *t, int authmask, const struct httpd_config *dcfg,
+ const struct html_config *incfg)
{
- int fd;
+ int fd, ret;
int authtype;
- char *authstring = NULL, authbuf[512];
- unsigned long ipaddr;
+ char *authstring = NULL;
struct fd *f;
struct sockaddr_in addr;
socklen_t addrlen;
+ struct html_config cfg = *incfg;
+
+ cfg.format = "%.0lu";
/*
* Establish the listening socket and retrieve its port
exit(1);
}
addr.sin_family = AF_INET;
- srand(0L);
- ipaddr = 0x7f000000;
- ipaddr += (1 + rand() % 255) << 16;
- ipaddr += (1 + rand() % 255) << 8;
- ipaddr += (1 + rand() % 255);
- addr.sin_addr.s_addr = htonl(ipaddr);
- addr.sin_port = htons(0);
+ if (!dcfg->address) {
+#ifdef RANDOM_LOCALHOST
+ unsigned long ipaddr;
+ srand(0L);
+ ipaddr = 0x7f000000;
+ ipaddr += (1 + rand() % 255) << 16;
+ ipaddr += (1 + rand() % 255) << 8;
+ ipaddr += (1 + rand() % 255);
+ addr.sin_addr.s_addr = htonl(ipaddr);
+#else
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+#endif
+ addr.sin_port = htons(0);
+ } else {
+ addr.sin_addr.s_addr = inet_addr(dcfg->address);
+ addr.sin_port = dcfg->port ? htons(dcfg->port) : 0;
+ }
addrlen = sizeof(addr);
- if (bind(fd, (struct sockaddr *)&addr, addrlen) < 0) {
+ ret = bind(fd, (const struct sockaddr *)&addr, addrlen);
+#ifdef RANDOM_LOCALHOST
+ if (ret < 0 && errno == EADDRNOTAVAIL && !dcfg->address) {
+ /*
+ * Some systems don't like us binding to random weird
+ * localhost-space addresses. Try again with the official
+ * INADDR_LOOPBACK.
+ */
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ addr.sin_port = htons(0);
+ ret = bind(fd, (const struct sockaddr *)&addr, addrlen);
+ }
+#endif
+ if (ret < 0) {
fprintf(stderr, "bind: %s\n", strerror(errno));
exit(1);
}
if ((authmask & HTTPD_AUTH_MAGIC) &&
(check_owning_uid(fd, 1) == getuid())) {
authtype = HTTPD_AUTH_MAGIC;
- printf("Using Linux /proc/net magic authentication\n");
+ if (authmask != HTTPD_AUTH_MAGIC)
+ printf("Using Linux /proc/net magic authentication\n");
} else if ((authmask & HTTPD_AUTH_BASIC)) {
- char username[128], password[128], userpass[259];
+ char username[128], password[128], userpassbuf[259];
+ const char *userpass;
const char *rname;
unsigned char passbuf[10];
int i, j, k, fd;
authtype = HTTPD_AUTH_BASIC;
- sprintf(username, "agedu");
- rname = "/dev/urandom";
- fd = open(rname, O_RDONLY);
- if (fd < 0) {
- int err = errno;
- rname = "/dev/random";
+ if (authmask != HTTPD_AUTH_BASIC)
+ printf("Using HTTP Basic authentication\n");
+
+ if (dcfg->basicauthdata) {
+ userpass = dcfg->basicauthdata;
+ } else {
+ strcpy(username, PNAME);
+ rname = "/dev/urandom";
fd = open(rname, O_RDONLY);
if (fd < 0) {
- int err2 = errno;
- fprintf(stderr, "/dev/urandom: open: %s\n", strerror(err));
- fprintf(stderr, "/dev/random: open: %s\n", strerror(err2));
- exit(1);
+ int err = errno;
+ rname = "/dev/random";
+ fd = open(rname, O_RDONLY);
+ if (fd < 0) {
+ int err2 = errno;
+ fprintf(stderr, "/dev/urandom: open: %s\n", strerror(err));
+ fprintf(stderr, "/dev/random: open: %s\n", strerror(err2));
+ exit(1);
+ }
}
- }
- for (i = 0; i < 10 ;) {
- j = read(fd, passbuf + i, 10 - i);
- if (j <= 0) {
- fprintf(stderr, "%s: read: %s\n", rname,
- j < 0 ? strerror(errno) : "unexpected EOF");
- exit(1);
+ for (i = 0; i < 10 ;) {
+ j = read(fd, passbuf + i, 10 - i);
+ if (j <= 0) {
+ fprintf(stderr, "%s: read: %s\n", rname,
+ j < 0 ? strerror(errno) : "unexpected EOF");
+ exit(1);
+ }
+ i += j;
}
- i += j;
- }
- close(fd);
- for (i = 0; i < 16; i++) {
- /* 32 characters out of the 36 alphanumerics gives me the
- * latitude to discard i,l,o for being too numeric-looking,
- * and w because it has two too many syllables and one too
- * many presidential associations. */
- static const char chars[32] = "0123456789abcdefghjkmnpqrstuvxyz";
- int v = 0;
-
- k = i / 8 * 5;
- for (j = 0; j < 5; j++)
- v |= ((passbuf[k+j] >> (i%8)) & 1) << j;
-
- password[i] = chars[v];
- }
- password[i] = '\0';
+ close(fd);
+ for (i = 0; i < 16; i++) {
+ /*
+ * 32 characters out of the 36 alphanumerics gives
+ * me the latitude to discard i,l,o for being too
+ * numeric-looking, and w because it has two too
+ * many syllables and one too many presidential
+ * associations.
+ */
+ static const char chars[32] =
+ "0123456789abcdefghjkmnpqrstuvxyz";
+ int v = 0;
+
+ k = i / 8 * 5;
+ for (j = 0; j < 5; j++)
+ v |= ((passbuf[k+j] >> (i%8)) & 1) << j;
+
+ password[i] = chars[v];
+ }
+ password[i] = '\0';
+
+ sprintf(userpassbuf, "%s:%s", username, password);
+ userpass = userpassbuf;
- printf("Using HTTP Basic authentication\nUsername: %s\nPassword: %s\n",
- username, password);
+ printf("Username: %s\nPassword: %s\n", username, password);
+ }
- k = sprintf(userpass, "%s:%s", username, password);
+ k = strlen(userpass);
+ authstring = snewn(k * 4 / 3 + 16, char);
for (i = j = 0; i < k ;) {
int s = k-i < 3 ? k-i : 3;
- base64_encode_atom((unsigned char *)(userpass+i), s, authbuf+j);
+ base64_encode_atom((unsigned char *)(userpass+i), s, authstring+j);
i += s;
j += 4;
}
- authbuf[j] = '\0';
- authstring = authbuf;
- } else {
+ authstring[j] = '\0';
+ } else if ((authmask & HTTPD_AUTH_NONE)) {
authtype = HTTPD_AUTH_NONE;
- printf("Web server is unauthenticated\n");
+ if (authmask != HTTPD_AUTH_NONE)
+ printf("Web server is unauthenticated\n");
+ } else {
+ fprintf(stderr, PNAME ": authentication method not supported\n");
+ exit(1);
+ }
+ if (ntohs(addr.sin_addr.s_addr) == INADDR_ANY) {
+ printf("Server port: %d\n", ntohs(addr.sin_port));
+ } else if (ntohs(addr.sin_port) == 80) {
+ printf("URL: http://%s/\n", inet_ntoa(addr.sin_addr));
+ } else {
+ printf("URL: http://%s:%d/\n",
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
}
- printf("URL: http://%s:%d/\n",
- inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
/*
* Now construct an fd structure to hold it.
*/
while (1) {
fd_set rfds, wfds;
- int i, j, maxfd, ret;
+ int i, j;
+ SELECT_TYPE_ARG1 maxfd;
+ int ret;
#define FD_SET_MAX(fd, set, max) \
do { FD_SET((fd),(set)); (max) = ((max)<=(fd)?(fd)+1:(max)); } while(0)
switch (fds[i].type) {
case FD_CLIENT:
+ FD_SET_MAX(fds[i].fd, &rfds, maxfd);
+ break;
case FD_LISTENER:
FD_SET_MAX(fds[i].fd, &rfds, maxfd);
break;
}
nfds = i;
- ret = select(maxfd, &rfds, &wfds, NULL, NULL);
+ ret = select(maxfd, SELECT_TYPE_ARG234 &rfds,
+ SELECT_TYPE_ARG234 &wfds, SELECT_TYPE_ARG234 NULL,
+ SELECT_TYPE_ARG5 NULL);
if (ret <= 0) {
if (ret < 0 && (errno != EINTR)) {
fprintf(stderr, "select: %s", strerror(errno));
fds[i].wdata = got_data
(fds[i].cctx, readbuf, ret,
(authtype == HTTPD_AUTH_NONE ||
- fds[i].magic_access), authstring);
+ fds[i].magic_access), authstring, &cfg);
if (fds[i].wdata) {
fds[i].wdatalen = strlen(fds[i].wdata);
fds[i].wdatapos = 0;