aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReyk Floeter <reyk@esdenera.com>2015-01-19 17:48:18 +0100
committerReyk Floeter <reyk@esdenera.com>2015-01-19 17:48:18 +0100
commitdda5d0c767c20326169f23cc38b6b53e51875bc2 (patch)
tree0d99cf0b000fc966de05d655f8a426bcc2a7c634
parentcb77100c319cef1e1da2cbfc368e967a917ed3f4 (diff)
downloadhttpd-dda5d0c767c20326169f23cc38b6b53e51875bc2.tar.gz
httpd-dda5d0c767c20326169f23cc38b6b53e51875bc2.zip
Split auth from server_config into struct auth
-rw-r--r--config.c107
-rw-r--r--httpd.c45
-rw-r--r--httpd.conf.55
-rw-r--r--httpd.h26
-rw-r--r--parse.y63
-rw-r--r--server.c4
-rw-r--r--server_fcgi.c2
-rw-r--r--server_http.c5
8 files changed, 227 insertions, 30 deletions
diff --git a/config.c b/config.c
index ba99593..5884c7b 100644
--- a/config.c
+++ b/config.c
@@ -45,6 +45,7 @@
int config_getserver_config(struct httpd *, struct server *,
struct imsg *);
+int config_getserver_auth(struct httpd *, struct server_config *);
int
config_init(struct httpd *env)
@@ -57,7 +58,8 @@ config_init(struct httpd *env)
env->sc_prefork_server = SERVER_NUMPROC;
ps->ps_what[PROC_PARENT] = CONFIG_ALL;
- ps->ps_what[PROC_SERVER] = CONFIG_SERVERS|CONFIG_MEDIA;
+ ps->ps_what[PROC_SERVER] =
+ CONFIG_SERVERS|CONFIG_MEDIA|CONFIG_AUTH;
ps->ps_what[PROC_LOGGER] = CONFIG_SERVERS;
}
@@ -78,6 +80,13 @@ config_init(struct httpd *env)
RB_INIT(env->sc_mediatypes);
}
+ if (what & CONFIG_AUTH) {
+ if ((env->sc_auth =
+ calloc(1, sizeof(*env->sc_auth))) == NULL)
+ return (-1);
+ TAILQ_INIT(env->sc_auth);
+ }
+
return (0);
}
@@ -86,6 +95,7 @@ config_purge(struct httpd *env, u_int reset)
{
struct privsep *ps = env->sc_ps;
struct server *srv;
+ struct auth *auth;
u_int what;
what = ps->ps_what[privsep_process] & reset;
@@ -97,6 +107,13 @@ config_purge(struct httpd *env, u_int reset)
if (what & CONFIG_MEDIA && env->sc_mediatypes != NULL)
media_purge(env->sc_mediatypes);
+
+ if (what & CONFIG_AUTH && env->sc_auth != NULL) {
+ while ((auth = TAILQ_FIRST(env->sc_auth)) != NULL) {
+ auth_free(env->sc_auth, auth);
+ free(auth);
+ }
+ }
}
int
@@ -217,6 +234,22 @@ config_setserver(struct httpd *env, struct server *srv)
}
int
+config_getserver_auth(struct httpd *env, struct server_config *srv_conf)
+{
+ struct privsep *ps = env->sc_ps;
+
+ if ((ps->ps_what[privsep_process] & CONFIG_AUTH) == 0 ||
+ (srv_conf->flags & SRVFLAG_AUTH) == 0)
+ return (0);
+
+ if ((srv_conf->auth = auth_byid(env->sc_auth,
+ srv_conf->auth_id)) == NULL)
+ return (-1);
+
+ return (0);
+}
+
+int
config_getserver_config(struct httpd *env, struct server *srv,
struct imsg *imsg)
{
@@ -243,6 +276,9 @@ config_getserver_config(struct httpd *env, struct server *srv,
if (parent == NULL)
parent = &srv->srv_conf;
+ if (config_getserver_auth(env, srv_conf) != 0)
+ return (-1);
+
if (srv_conf->flags & SRVFLAG_LOCATION) {
/* Inherit configuration from the parent */
f = SRVFLAG_INDEX|SRVFLAG_NO_INDEX;
@@ -284,6 +320,16 @@ config_getserver_config(struct httpd *env, struct server *srv,
if ((srv_conf->flags & f) == 0)
srv_conf->flags |= parent->flags & f;
+ f = SRVFLAG_AUTH|SRVFLAG_NO_AUTH;
+ if ((srv_conf->flags & f) == 0) {
+ srv_conf->flags |= parent->flags & f;
+ srv_conf->auth = parent->auth;
+ srv_conf->auth_id = parent->auth_id;
+ (void)strlcpy(srv_conf->auth_realm,
+ parent->auth_realm,
+ sizeof(srv_conf->auth_realm));
+ }
+
f = SRVFLAG_TLS;
srv_conf->flags |= parent->flags & f;
@@ -368,14 +414,15 @@ config_getserver(struct httpd *env, struct imsg *imsg)
fatalx("invalid location");
/* Otherwise create a new server */
- if ((srv = calloc(1, sizeof(*srv))) == NULL) {
- close(imsg->fd);
- return (-1);
- }
+ if ((srv = calloc(1, sizeof(*srv))) == NULL)
+ goto fail;
memcpy(&srv->srv_conf, &srv_conf, sizeof(srv->srv_conf));
srv->srv_s = imsg->fd;
+ if (config_getserver_auth(env, &srv->srv_conf) != 0)
+ goto fail;
+
SPLAY_INIT(&srv->srv_clients);
TAILQ_INIT(&srv->srv_hosts);
@@ -403,6 +450,8 @@ config_getserver(struct httpd *env, struct imsg *imsg)
return (0);
fail:
+ if (imsg->fd != -1)
+ close(imsg->fd);
if (srv != NULL) {
free(srv->srv_conf.tls_cert);
free(srv->srv_conf.tls_key);
@@ -459,3 +508,51 @@ config_getmedia(struct httpd *env, struct imsg *imsg)
return (0);
}
+
+int
+config_setauth(struct httpd *env, struct auth *auth)
+{
+ struct privsep *ps = env->sc_ps;
+ int id;
+ u_int what;
+
+ for (id = 0; id < PROC_MAX; id++) {
+ what = ps->ps_what[id];
+
+ if ((what & CONFIG_AUTH) == 0 || id == privsep_process)
+ continue;
+
+ DPRINTF("%s: sending auth \"%s[%u]\" to %s", __func__,
+ auth->auth_htpasswd, auth->auth_id, ps->ps_title[id]);
+
+ proc_compose_imsg(ps, id, -1, IMSG_CFG_AUTH, -1,
+ auth, sizeof(*auth));
+ }
+
+ return (0);
+}
+
+int
+config_getauth(struct httpd *env, struct imsg *imsg)
+{
+#ifdef DEBUG
+ struct privsep *ps = env->sc_ps;
+#endif
+ struct auth auth;
+ u_int8_t *p = imsg->data;
+
+ IMSG_SIZE_CHECK(imsg, &auth);
+ memcpy(&auth, p, sizeof(auth));
+
+ if (auth_add(env->sc_auth, &auth) == NULL) {
+ log_debug("%s: failed to add auth \"%s[%u]\"",
+ __func__, auth.auth_htpasswd, auth.auth_id);
+ return (-1);
+ }
+
+ DPRINTF("%s: %s %d received auth \"%s[%u]\"", __func__,
+ ps->ps_title[privsep_process], ps->ps_instance,
+ auth.auth_htpasswd, auth.auth_id);
+
+ return (0);
+}
diff --git a/httpd.c b/httpd.c
index c7d8f9f..79acce9 100644
--- a/httpd.c
+++ b/httpd.c
@@ -290,12 +290,18 @@ parent_configure(struct httpd *env)
int ret = -1;
struct server *srv;
struct media_type *media;
+ struct auth *auth;
RB_FOREACH(media, mediatypes, env->sc_mediatypes) {
if (config_setmedia(env, media) == -1)
fatal("send media");
}
+ TAILQ_FOREACH(auth, env->sc_auth, auth_entry) {
+ if (config_setauth(env, auth) == -1)
+ fatal("send auth");
+ }
+
/* First send the servers... */
TAILQ_FOREACH(srv, env->sc_servers, srv_entry) {
if (srv->srv_conf.flags & SRVFLAG_LOCATION)
@@ -1146,3 +1152,42 @@ media_cmp(struct media_type *a, struct media_type *b)
}
RB_GENERATE(mediatypes, media_type, media_entry, media_cmp);
+
+struct auth *
+auth_add(struct serverauth *serverauth, struct auth *auth)
+{
+ struct auth *entry;
+
+ TAILQ_FOREACH(entry, serverauth, auth_entry) {
+ if (strcmp(entry->auth_htpasswd, auth->auth_htpasswd) == 0)
+ return (entry);
+ }
+
+ if ((entry = calloc(1, sizeof(*entry))) == NULL)
+ return (NULL);
+
+ memcpy(entry, auth, sizeof(*entry));
+
+ TAILQ_INSERT_TAIL(serverauth, entry, auth_entry);
+
+ return (entry);
+}
+
+struct auth *
+auth_byid(struct serverauth *serverauth, u_int32_t id)
+{
+ struct auth *auth;
+
+ TAILQ_FOREACH(auth, serverauth, auth_entry) {
+ if (auth->auth_id == id)
+ return (auth);
+ }
+
+ return (NULL);
+}
+
+void
+auth_free(struct serverauth *serverauth, struct auth *auth)
+{
+ TAILQ_REMOVE(serverauth, auth, auth_entry);
+}
diff --git a/httpd.conf.5 b/httpd.conf.5
index d4a6a00..1d66c46 100644
--- a/httpd.conf.5
+++ b/httpd.conf.5
@@ -139,7 +139,7 @@ and include one or more lines of the following syntax:
Specify an additional alias
.Ar name
for this server.
-.It Ic authenticate Oo Ar realm Oc Ic with Pa htpasswd
+.It Oo Ic no Oc Ic authenticate Oo Ar realm Oc Ic with Pa htpasswd
Authenticate a remote user for
.Ar realm
by checking the credentials against the user authentication file
@@ -147,6 +147,9 @@ by checking the credentials against the user authentication file
The file name is relative to the
.Ic chroot
and must be readable by the www user.
+Use the
+.Ic no authenticate
+directive to disable authentication in a location.
.It Ic connection Ar option
Set the specified options and limits for HTTP connections.
Valid options are:
diff --git a/httpd.h b/httpd.h
index 0822a5b..8438d51 100644
--- a/httpd.h
+++ b/httpd.h
@@ -59,6 +59,7 @@
#define CONFIG_RELOAD 0x00
#define CONFIG_MEDIA 0x01
#define CONFIG_SERVERS 0x02
+#define CONFIG_AUTH 0x04
#define CONFIG_ALL 0xff
#define FCGI_CONTENT_SIZE 65535
@@ -189,6 +190,7 @@ enum imsg_type {
IMSG_CTL_REOPEN,
IMSG_CFG_SERVER,
IMSG_CFG_MEDIA,
+ IMSG_CFG_AUTH,
IMSG_CFG_DONE,
IMSG_LOG_ACCESS,
IMSG_LOG_ERROR,
@@ -325,13 +327,14 @@ SPLAY_HEAD(client_tree, client);
#define SRVFLAG_TLS 0x00002000
#define SRVFLAG_ACCESS_LOG 0x00004000
#define SRVFLAG_ERROR_LOG 0x00008000
-#define SRVFLAG_AUTH_BASIC 0x00010000
+#define SRVFLAG_AUTH 0x00010000
+#define SRVFLAG_NO_AUTH 0x00020000
#define SRVFLAG_BITS \
"\10\01INDEX\02NO_INDEX\03AUTO_INDEX\04NO_AUTO_INDEX" \
"\05ROOT\06LOCATION\07FCGI\10NO_FCGI\11LOG\12NO_LOG\13SOCKET" \
"\14SYSLOG\15NO_SYSLOG\16TLS\17ACCESS_LOG\20ERROR_LOG" \
- "\21AUTH_BASIC"
+ "\21AUTH\22NO_AUTH"
#define TCPFLAG_NODELAY 0x01
#define TCPFLAG_NNODELAY 0x02
@@ -361,6 +364,13 @@ struct log_file {
};
TAILQ_HEAD(log_files, log_file) log_files;
+struct auth {
+ char auth_htpasswd[PATH_MAX];
+ u_int32_t auth_id;
+ TAILQ_ENTRY(auth) auth_entry;
+};
+TAILQ_HEAD(serverauth, auth);
+
struct server_config {
u_int32_t id;
char name[HOST_NAME_MAX+1];
@@ -370,8 +380,6 @@ struct server_config {
char socket[PATH_MAX];
char accesslog[NAME_MAX];
char errorlog[NAME_MAX];
- char auth_realm[NAME_MAX];
- char auth_htpasswd[PATH_MAX];
in_port_t port;
struct sockaddr_storage ss;
@@ -400,6 +408,10 @@ struct server_config {
struct log_file *logaccess;
struct log_file *logerror;
+ char auth_realm[NAME_MAX];
+ u_int32_t auth_id;
+ struct auth *auth;
+
TAILQ_ENTRY(server_config) entry;
};
TAILQ_HEAD(serverhosts, server_config);
@@ -442,6 +454,7 @@ struct httpd {
struct serverlist *sc_servers;
struct mediatypes *sc_mediatypes;
+ struct serverauth *sc_auth;
struct privsep *sc_ps;
int sc_reload;
@@ -587,6 +600,9 @@ struct media_type *
int media_cmp(struct media_type *, struct media_type *);
RB_PROTOTYPE(kvtree, kv, kv_node, kv_cmp);
RB_PROTOTYPE(mediatypes, media_type, media_entry, media_cmp);
+struct auth *auth_add(struct serverauth *, struct auth *);
+struct auth *auth_byid(struct serverauth *, u_int32_t);
+void auth_free(struct serverauth *, struct auth *);
/* log.c */
void log_init(int);
@@ -639,6 +655,8 @@ int config_setserver(struct httpd *, struct server *);
int config_getserver(struct httpd *, struct imsg *);
int config_setmedia(struct httpd *, struct media_type *);
int config_getmedia(struct httpd *, struct imsg *);
+int config_setauth(struct httpd *, struct auth *);
+int config_getauth(struct httpd *, struct imsg *);
/* logger.c */
pid_t logger(struct privsep *, struct privsep_proc *);
diff --git a/parse.y b/parse.y
index b47173a..9afea2c 100644
--- a/parse.y
+++ b/parse.y
@@ -91,6 +91,7 @@ struct httpd *conf = NULL;
static int errors = 0;
static int loadcfg = 0;
uint32_t last_server_id = 0;
+uint32_t last_auth_id = 0;
static struct server *srv = NULL, *parentsrv = NULL;
static struct server_config *srv_conf = NULL;
@@ -117,6 +118,7 @@ typedef struct {
char *string;
struct timeval tv;
struct portrange port;
+ struct auth auth;
struct {
struct sockaddr_storage ss;
char name[HOST_NAME_MAX+1];
@@ -138,6 +140,7 @@ typedef struct {
%type <v.number> opttls
%type <v.tv> timeout
%type <v.string> numberstring
+%type <v.auth> authopts
%%
@@ -645,35 +648,60 @@ rootflags : STRING {
}
;
-authenticate : AUTHENTICATE STRING WITH STRING {
- if (strlcpy(srv->srv_conf.auth_realm, $2,
+authenticate : NO AUTHENTICATE {
+ srv->srv_conf.flags |= SRVFLAG_NO_AUTH;
+ }
+ | AUTHENTICATE authopts {
+ struct auth *auth;
+
+ if ((auth = auth_add(conf->sc_auth, &$2)) == NULL) {
+ yyerror("failed to add auth");
+ YYERROR;
+ }
+
+ if (auth->auth_id == 0) {
+ /* New htpasswd, get new Id */
+ auth->auth_id = ++last_auth_id;
+ if (last_auth_id == INT_MAX) {
+ yyerror("too many auth ids defined");
+ auth_free(conf->sc_auth, auth);
+ YYERROR;
+ }
+ }
+
+ srv->srv_conf.auth_id = auth->auth_id;
+ srv->srv_conf.flags |= SRVFLAG_AUTH;
+ }
+ ;
+
+authopts : STRING WITH STRING {
+ if (strlcpy(srv->srv_conf.auth_realm, $1,
sizeof(srv->srv_conf.auth_realm)) >=
sizeof(srv->srv_conf.auth_realm)) {
yyerror("basic auth realm name too long");
- free($2);
+ free($1);
YYERROR;
}
- free($2);
- if (strlcpy(srv->srv_conf.auth_htpasswd, $4,
- sizeof(srv->srv_conf.auth_htpasswd)) >=
- sizeof(srv->srv_conf.auth_htpasswd)) {
+ free($1);
+ if (strlcpy($$.auth_htpasswd, $3,
+ sizeof($$.auth_htpasswd)) >=
+ sizeof($$.auth_htpasswd)) {
yyerror("password file name too long");
- free($4);
+ free($3);
YYERROR;
}
- free($4);
- srv->srv_conf.flags |= SRVFLAG_AUTH_BASIC;
+ free($3);
+
}
- | AUTHENTICATE WITH STRING {
- if (strlcpy(srv->srv_conf.auth_htpasswd, $3,
- sizeof(srv->srv_conf.auth_htpasswd)) >=
- sizeof(srv->srv_conf.auth_htpasswd)) {
+ | WITH STRING {
+ if (strlcpy($$.auth_htpasswd, $2,
+ sizeof($$.auth_htpasswd)) >=
+ sizeof($$.auth_htpasswd)) {
yyerror("password file name too long");
- free($3);
+ free($2);
YYERROR;
}
- free($3);
- srv->srv_conf.flags |= SRVFLAG_AUTH_BASIC;
+ free($2);
};
directory : DIRECTORY dirflags
@@ -1400,6 +1428,7 @@ load_config(const char *filename, struct httpd *x_conf)
loadcfg = 1;
errors = 0;
last_server_id = 0;
+ last_auth_id = 0;
srv = NULL;
diff --git a/server.c b/server.c
index 943e60a..522deb1 100644
--- a/server.c
+++ b/server.c
@@ -337,6 +337,7 @@ serverconfig_reset(struct server_config *srv_conf)
{
srv_conf->tls_cert_file = srv_conf->tls_cert =
srv_conf->tls_key_file = srv_conf->tls_key = NULL;
+ srv_conf->auth = NULL;
}
struct server *
@@ -1122,6 +1123,9 @@ server_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
case IMSG_CFG_MEDIA:
config_getmedia(env, imsg);
break;
+ case IMSG_CFG_AUTH:
+ config_getauth(env, imsg);
+ break;
case IMSG_CFG_SERVER:
config_getserver(env, imsg);
break;
diff --git a/server_fcgi.c b/server_fcgi.c
index 7305eb0..8a6f5e6 100644
--- a/server_fcgi.c
+++ b/server_fcgi.c
@@ -259,7 +259,7 @@ server_fcgi(struct httpd *env, struct client *clt)
goto fail;
}
- if (srv_conf->flags & SRVFLAG_AUTH_BASIC) {
+ if (srv_conf->flags & SRVFLAG_AUTH) {
if (fcgi_add_param(&param, "REMOTE_USER",
clt->clt_fcgi_remote_user, clt) == -1) {
errstr = "failed to encode param";
diff --git a/server_http.c b/server_http.c
index 5bf6bd5..b1338cf 100644
--- a/server_http.c
+++ b/server_http.c
@@ -136,6 +136,7 @@ server_http_authenticate(struct server_config *srv_conf, struct client *clt)
{
FILE *fp = NULL;
struct http_descriptor *desc = clt->clt_descreq;
+ struct auth *auth = srv_conf->auth;
struct kv *ba, key;
size_t linesize = 0;
ssize_t linelen;
@@ -166,7 +167,7 @@ server_http_authenticate(struct server_config *srv_conf, struct client *clt)
if (clt_pass == NULL)
goto done;
- if ((fp = fopen(srv_conf->auth_htpasswd, "r")) == NULL)
+ if ((fp = fopen(auth->auth_htpasswd, "r")) == NULL)
goto done;
while ((linelen = getline(&line, &linesize, fp)) != -1) {
@@ -964,7 +965,7 @@ server_response(struct httpd *httpd, struct client *clt)
/* Now search for the location */
srv_conf = server_getlocation(clt, desc->http_path);
- if (srv_conf->flags & SRVFLAG_AUTH_BASIC &&
+ if (srv_conf->flags & SRVFLAG_AUTH &&
server_http_authenticate(srv_conf, clt) == -1) {
server_abort_http(clt, 401, srv_conf->auth_realm);
return (-1);