-.\" $OpenBSD: httpd.conf.5,v 1.44 2015/01/13 09:21:15 reyk Exp $
+.\" $OpenBSD: httpd.conf.5,v 1.45 2015/01/18 14:01:17 florian Exp $
.\"
.\" Copyright (c) 2014, 2015 Reyk Floeter <reyk@openbsd.org>
.\"
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: January 13 2015 $
+.Dd $Mdocdate: January 18 2015 $
.Dt HTTPD.CONF 5
.Os
.Sh NAME
Specify an additional alias
.Ar name
for this server.
+.It 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
+.Pa htpasswd .
+This file needs to be readable by the user
+.Xr httpd 8
+drops to
+.Pq www by default Pc .
.It Ic connection Ar option
Set the specified options and limits for HTTP connections.
Valid options are:
include "/etc/nginx/mime.types"
.Ed
.Sh SEE ALSO
+.Xr htpasswd 1 ,
.Xr httpd 8
.Sh AUTHORS
.An -nosplit
-/* $OpenBSD: httpd.h,v 1.68 2015/01/16 06:40:17 deraadt Exp $ */
+/* $OpenBSD: httpd.h,v 1.69 2015/01/18 14:01:17 florian Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
int clt_fcgi_type;
int clt_fcgi_chunked;
int clt_fcgi_end;
+ char *clt_fcgi_remote_user;
struct evbuffer *clt_srvevb;
struct evbuffer *clt_log;
#define SRVFLAG_TLS 0x00002000
#define SRVFLAG_ACCESS_LOG 0x00004000
#define SRVFLAG_ERROR_LOG 0x00008000
+#define SRVFLAG_AUTH_BASIC 0x00010000
#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"
+ "\14SYSLOG\15NO_SYSLOG\16TLS\17ACCESS_LOG\20ERROR_LOG" \
+ "\21AUTH_BASIC"
#define TCPFLAG_NODELAY 0x01
#define TCPFLAG_NNODELAY 0x02
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;
-/* $OpenBSD: parse.y,v 1.54 2015/01/16 06:40:17 deraadt Exp $ */
+/* $OpenBSD: parse.y,v 1.55 2015/01/18 14:01:17 florian Exp $ */
/*
* Copyright (c) 2007 - 2015 Reyk Floeter <reyk@openbsd.org>
%token COMBINED CONNECTION DIRECTORY ERR FCGI INDEX IP KEY LISTEN LOCATION
%token LOG LOGDIR MAXIMUM NO NODELAY ON PORT PREFORK REQUEST REQUESTS ROOT
%token SACK SERVER SOCKET STRIP STYLE SYSLOG TCP TIMEOUT TLS TYPES
-%token ERROR INCLUDE
+%token ERROR INCLUDE AUTHENTICATE WITH
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.port> port
| directory
| logformat
| fastcgi
+ | authenticate
| LOCATION STRING {
struct server *s;
}
;
+authenticate : AUTHENTICATE STRING WITH STRING {
+ if (strlcpy(srv->srv_conf.auth_realm, $2,
+ sizeof(srv->srv_conf.auth_realm)) >=
+ sizeof(srv->srv_conf.auth_realm)) {
+ yyerror("basic auth realm name too long");
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ if (strlcpy(srv->srv_conf.auth_htpasswd, $4,
+ sizeof(srv->srv_conf.auth_htpasswd)) >=
+ sizeof(srv->srv_conf.auth_htpasswd)) {
+ yyerror("password file name too long");
+ free($4);
+ YYERROR;
+ }
+ free($4);
+ srv->srv_conf.flags |= SRVFLAG_AUTH_BASIC;
+ }
+ | AUTHENTICATE WITH STRING {
+ if (strlcpy(srv->srv_conf.auth_htpasswd, $3,
+ sizeof(srv->srv_conf.auth_htpasswd)) >=
+ sizeof(srv->srv_conf.auth_htpasswd)) {
+ yyerror("password file name too long");
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ srv->srv_conf.flags |= SRVFLAG_AUTH_BASIC;
+ };
+
directory : DIRECTORY dirflags
| DIRECTORY '{' optnl dirflags_l '}'
;
static const struct keywords keywords[] = {
{ "access", ACCESS },
{ "alias", ALIAS },
+ { "authenticate", AUTHENTICATE},
{ "auto", AUTO },
{ "backlog", BACKLOG },
{ "body", BODY },
{ "tcp", TCP },
{ "timeout", TIMEOUT },
{ "tls", TLS },
- { "types", TYPES }
+ { "types", TYPES },
+ { "with", WITH }
};
const struct keywords *p;
-/* $OpenBSD: server_fcgi.c,v 1.46 2015/01/16 06:40:17 deraadt Exp $ */
+/* $OpenBSD: server_fcgi.c,v 1.47 2015/01/18 14:01:17 florian Exp $ */
/*
* Copyright (c) 2014 Florian Obser <florian@openbsd.org>
goto fail;
}
+ if (srv_conf->flags & SRVFLAG_AUTH_BASIC) {
+ if (fcgi_add_param(¶m, "REMOTE_USER",
+ clt->clt_fcgi_remote_user, clt) == -1) {
+ errstr = "failed to encode param";
+ goto fail;
+ }
+ }
+
/* Add HTTP_* headers */
if (server_headers(clt, desc, server_fcgi_writeheader, ¶m) == -1) {
errstr = "failed to encode param";
-/* $OpenBSD: server_http.c,v 1.64 2015/01/16 06:40:17 deraadt Exp $ */
+/* $OpenBSD: server_http.c,v 1.65 2015/01/18 14:01:17 florian Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
#include <stdio.h>
#include <err.h>
#include <pwd.h>
+#include <resolv.h>
#include <syslog.h>
#include <event.h>
#include <fnmatch.h>
static int server_httpmethod_cmp(const void *, const void *);
static int server_httperror_cmp(const void *, const void *);
void server_httpdesc_free(struct http_descriptor *);
+int server_http_authenticate(struct server_config *,
+ struct client *);
static struct httpd *env = NULL;
desc->http_chunked = 0;
}
+int
+server_http_authenticate(struct server_config *srv_conf, struct client *clt)
+{
+ FILE *fp = NULL;
+ struct http_descriptor *desc = clt->clt_descreq;
+ struct kv *ba, key;
+ size_t linesize = 0;
+ ssize_t linelen;
+ int ret = -1;
+ char *line = NULL, decoded[1024];
+ char *clt_user = NULL, *clt_pass = NULL, *user = NULL, *pass = NULL;
+
+ memset(decoded, 0, sizeof(decoded));
+ key.kv_key = "Authorization";
+
+ if ((ba = kv_find(&desc->http_headers, &key)) == NULL ||
+ ba->kv_value == NULL)
+ goto done;
+
+ if (strncmp(ba->kv_value, "Basic ", strlen("Basic ")) != 0)
+ goto done;
+
+ if (b64_pton(strchr(ba->kv_value, ' ') + 1, decoded,
+ sizeof(decoded)) <= 0)
+ goto done;
+
+ if ((clt_pass = strchr(decoded, ':')) == NULL)
+ goto done;
+
+ clt_user = decoded;
+ *clt_pass++ = '\0';
+
+ if (clt_pass == NULL)
+ goto done;
+
+ if ((fp = fopen(srv_conf->auth_htpasswd, "r")) == NULL)
+ goto done;
+
+ while ((linelen = getline(&line, &linesize, fp)) != -1) {
+ if (line[linelen - 1] == '\n')
+ line[linelen - 1] = '\0';
+ user = line;
+ pass = strchr(line, ':');
+
+ if (pass == NULL) {
+ explicit_bzero(line, linelen);
+ continue;
+ }
+
+ *pass++ = '\0';
+
+ if (strcmp(clt_user, user) != 0) {
+ explicit_bzero(line, linelen);
+ continue;
+ }
+
+ if (crypt_checkpass(clt_pass, pass) == 0) {
+ explicit_bzero(line, linelen);
+ clt->clt_fcgi_remote_user = strdup(clt_user);
+ if (clt->clt_fcgi_remote_user != NULL)
+ ret = 0;
+ break;
+ }
+ }
+done:
+ if (fp != NULL)
+ fclose(fp);
+
+ if (ba != NULL && ba->kv_value != NULL) {
+ explicit_bzero(ba->kv_value, strlen(ba->kv_value));
+ explicit_bzero(decoded, sizeof(decoded));
+ }
+
+ return (ret);
+}
+
void
server_read_http(struct bufferevent *bev, void *arg)
{
clt->clt_line = 0;
clt->clt_done = 0;
clt->clt_chunk = 0;
+ free(clt->clt_fcgi_remote_user);
+ clt->clt_fcgi_remote_user = NULL;
clt->clt_bev->readcb = server_read_http;
clt->clt_srv_conf = &srv->srv_conf;
extraheader = NULL;
}
break;
+ case 401:
+ if (asprintf(&extraheader,
+ "WWW-Authenticate: Basic realm=\"%s\"\r\n", msg) == -1) {
+ code = 500;
+ extraheader = NULL;
+ }
+ break;
default:
/*
* Do not send details of the error. Traditionally,
server_httpdesc_free(desc);
free(desc);
clt->clt_descresp = NULL;
+ free(clt->clt_fcgi_remote_user);
+ clt->clt_fcgi_remote_user = NULL;
}
int
/* Now search for the location */
srv_conf = server_getlocation(clt, desc->http_path);
- return (server_file(httpd, clt));
+ if (srv_conf->flags & SRVFLAG_AUTH_BASIC &&
+ server_http_authenticate(srv_conf, clt) == -1) {
+ server_abort_http(clt, 401, srv_conf->auth_realm);
+ return (-1);
+ } else
+ return (server_file(httpd, clt));
fail:
server_abort_http(clt, 400, "bad request");
return (-1);