From 1e8d78b987550c351f47b204d3c9649cc1872e45 Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 1 Nov 2008 15:21:40 +0000 Subject: [PATCH] More HTTP server configuration: allow user-chosen address+port and HTTP Basic authentication data. git-svn-id: svn://svn.tartarus.org/sgt/agedu@8240 cda61777-01e9-0310-a592-d414129be87e --- TODO | 8 +--- agedu.c | 86 +++++++++++++++++++++++++++++++++++--- httpd.c | 143 +++++++++++++++++++++++++++++++++++++++------------------------- httpd.h | 9 +++- 4 files changed, 177 insertions(+), 69 deletions(-) diff --git a/TODO b/TODO index 07a84f1..9b93ca2 100644 --- a/TODO +++ b/TODO @@ -3,12 +3,6 @@ TODO list for agedu Before it's non-embarrassingly releasable: - - add more configurable options - + server address in httpd mode - + HTTP authentication: specify username and/or password, the - latter by at least some means which doesn't involve it showing - up in "ps" - - more flexible running modes + combined scan+dump mode which doesn't even generate an index file (nearly indistinguishable from find(1)) @@ -71,6 +65,8 @@ Before it's non-embarrassingly releasable: Future directions: + - IPv6 support in the HTTP server + - run-time configuration in the HTTP server * I think this probably works by having a configuration form, or a link pointing to one, somewhere on the report page. If you diff --git a/agedu.c b/agedu.c index 607d425..c88fdf5 100644 --- a/agedu.c +++ b/agedu.c @@ -273,9 +273,16 @@ static void text_query(const void *mappedfile, const char *querydir, HELPARG("age") HELPOPT("[--text] include only files older than this") \ VAL(AGERANGE) SHORT(r) LONG(age_range) LONG(range) LONG(ages) \ HELPARG("age[-age]") HELPOPT("[--html,--web] set limits of colour coding") \ + VAL(SERVERADDR) LONG(address) LONG(addr) LONG(server_address) \ + LONG(server_addr) \ + HELPARG("addr[:port]") HELPOPT("[--web] specify HTTP server address") \ VAL(AUTH) LONG(auth) LONG(http_auth) LONG(httpd_auth) \ LONG(server_auth) LONG(web_auth) \ HELPARG("type") HELPOPT("[--web] specify HTTP authentication method") \ + VAL(AUTHFILE) LONG(auth_file) \ + HELPARG("filename") HELPOPT("[--web] read HTTP Basic user/pass from file") \ + VAL(AUTHFD) LONG(auth_fd) \ + HELPARG("fd") HELPOPT("[--web] read HTTP Basic user/pass from fd") \ HELPPFX("also") \ NOVAL(HELP) SHORT(h) LONG(help) HELPOPT("display this help text") \ NOVAL(VERSION) SHORT(V) LONG(version) HELPOPT("report version number") \ @@ -408,6 +415,9 @@ int main(int argc, char **argv) time_t now = time(NULL); time_t textcutoff = now, htmlnewest = now, htmloldest = now; int htmlautoagerange = 1; + const char *httpserveraddr = NULL; + int httpserverport = 0; + const char *httpauthdata = NULL; int auth = HTTPD_AUTH_MAGIC | HTTPD_AUTH_BASIC; int progress = 1; struct inclusion_exclusion *inex = NULL; @@ -608,6 +618,21 @@ int main(int argc, char **argv) htmlautoagerange = 0; } break; + case OPT_SERVERADDR: + { + char *port; + if (optval[0] == '[' && + (port = strchr(optval, ']')) != NULL) + port++; + else + port = optval; + port += strcspn(port, ":"); + if (port) + *port++ = '\0'; + httpserveraddr = optval; + httpserverport = atoi(port); + } + break; case OPT_AUTH: if (!strcmp(optval, "magic")) auth = HTTPD_AUTH_MAGIC; @@ -638,6 +663,51 @@ int main(int argc, char **argv) return 1; } break; + case OPT_AUTHFILE: + case OPT_AUTHFD: + { + int fd; + char namebuf[40]; + const char *name; + char *authbuf; + int authlen, authsize; + int ret; + + if (optid == OPT_AUTHFILE) { + fd = open(optval, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "%s: %s: open: %s\n", PNAME, + optval, strerror(errno)); + return 1; + } + name = optval; + } else { + fd = atoi(optval); + name = namebuf; + sprintf(namebuf, "fd %d", fd); + } + + authlen = 0; + authsize = 256; + authbuf = snewn(authsize, char); + while ((ret = read(fd, authbuf+authlen, + authsize-authlen)) > 0) { + authlen += ret; + if ((authsize - authlen) < (authsize / 16)) { + authsize = authlen * 3 / 2 + 4096; + authbuf = sresize(authbuf, authsize, char); + } + } + if (ret < 0) { + fprintf(stderr, "%s: %s: read: %s\n", PNAME, + name, strerror(errno)); + return 1; + } + if (optid == OPT_AUTHFILE) + close(fd); + httpauthdata = authbuf; + } + break; case OPT_INCLUDE: case OPT_INCLUDEPATH: case OPT_EXCLUDE: @@ -865,7 +935,8 @@ int main(int argc, char **argv) } triewalk_free(tw); } else if (mode == HTTPD) { - struct html_config cfg; + struct html_config pcfg; + struct httpd_config dcfg; fd = open(filename, O_RDONLY); if (fd < 0) { @@ -884,11 +955,14 @@ int main(int argc, char **argv) return 1; } - cfg.format = NULL; - cfg.autoage = htmlautoagerange; - cfg.oldest = htmloldest; - cfg.newest = htmlnewest; - run_httpd(mappedfile, auth, &cfg); + dcfg.address = httpserveraddr; + dcfg.port = httpserverport; + dcfg.basicauthdata = httpauthdata; + pcfg.format = NULL; + pcfg.autoage = htmlautoagerange; + pcfg.oldest = htmloldest; + pcfg.newest = htmlnewest; + run_httpd(mappedfile, auth, &dcfg, &pcfg); } return 0; diff --git a/httpd.c b/httpd.c index b08f6ef..d03e1c5 100644 --- a/httpd.c +++ b/httpd.c @@ -417,11 +417,12 @@ static void base64_encode_atom(unsigned char *data, int n, char *out) out[3] = '='; } -void run_httpd(const void *t, int authmask, const struct html_config *incfg) +void run_httpd(const void *t, int authmask, const struct httpd_config *dcfg, + const struct html_config *incfg) { int fd; int authtype; - char *authstring = NULL, authbuf[512]; + char *authstring = NULL; unsigned long ipaddr; struct fd *f; struct sockaddr_in addr; @@ -440,13 +441,18 @@ void run_httpd(const void *t, int authmask, const struct html_config *incfg) 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) { + 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); + } else { + addr.sin_addr.s_addr = inet_addr(dcfg->address); + addr.sin_port = dcfg->port ? htons(dcfg->port) : 80; + } addrlen = sizeof(addr); if (bind(fd, (struct sockaddr *)&addr, addrlen) < 0) { fprintf(stderr, "bind: %s\n", strerror(errno)); @@ -464,73 +470,98 @@ void run_httpd(const void *t, int authmask, const struct html_config *incfg) 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 { + sprintf(username, "agedu"); + 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, "agedu: authentication method not supported\n"); + exit(1); + } + if (!dcfg->address) { + 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. diff --git a/httpd.h b/httpd.h index 467803f..1683ebb 100644 --- a/httpd.h +++ b/httpd.h @@ -7,4 +7,11 @@ #define HTTPD_AUTH_BASIC 2 #define HTTPD_AUTH_NONE 4 -void run_httpd(const void *t, int authmask, const struct html_config *cfg); +struct httpd_config { + const char *address; + int port; + const char *basicauthdata; +}; + +void run_httpd(const void *t, int authmask, const struct httpd_config *dcfg, + const struct html_config *pcfg); -- 2.11.0