From 2c1dec428c6e1d1bb6675847a5046a4fabdfe4c4 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Thu, 29 Apr 2004 03:55:57 +0000 Subject: - Added documentation - Fixed bugs - Added support for dns to sock_any --- Makefile.am | 4 +- common/sock_any.c | 99 ++++++++++++++- common/sock_any.h | 2 +- configure.in | 4 +- daemon/defaults.h | 2 +- daemon/digest.c | 87 ++++++++----- daemon/digest.h | 4 +- daemon/httpauthd.c | 10 ++ daemon/httpauthd.h | 3 +- daemon/ldap.c | 20 ++- daemon/simple.c | 14 +- doc/Makefile.am | 4 + doc/httpauth.conf.5 | 82 ------------ doc/httpauthd.8 | 45 +++++++ doc/httpauthd.conf.5 | 316 ++++++++++++++++++++++++++++++++++++++++++++++ doc/httpauthd.conf.sample | 34 +++++ sample/httpauthd.conf | 24 ++-- 17 files changed, 592 insertions(+), 162 deletions(-) create mode 100644 doc/Makefile.am delete mode 100644 doc/httpauth.conf.5 create mode 100644 doc/httpauthd.8 create mode 100644 doc/httpauthd.conf.5 create mode 100644 doc/httpauthd.conf.sample diff --git a/Makefile.am b/Makefile.am index 96afc15..47af21f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ -EXTRA_DIST = doc apache1x common config.sub -SUBDIRS = daemon +EXTRA_DIST = apache1x common config.sub +SUBDIRS = daemon doc dist-hook: rm -rf `find $(distdir)/ -name CVS` diff --git a/common/sock_any.c b/common/sock_any.c index b2bde01..f01933b 100644 --- a/common/sock_any.c +++ b/common/sock_any.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "sock_any.h" @@ -11,20 +12,47 @@ int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport) { size_t l; - const char* t; + char buf[256]; /* TODO: Use a constant */ + char* t; + char* t2; memset(any, 0, sizeof(*any)); + /* Just a port? */ + do + { + #define PORT_CHARS "0123456789" + #define PORT_MIN 1 + #define PORT_MAX 5 + + int port = 0; + + l = strspn(addr, PORT_CHARS); + if(l < PORT_MIN || l > PORT_MAX || addr[l] != 0) + break; + + port = strtol(t, &t2, 10); + if(*t2 || port <= 0 || port >= 65536) + break; + + any->s.in.sin_family = AF_INET; + any->s.in.sin_port = htons((unsigned short)(port <= 0 ? defport : port)); + any->s.in.sin_addr.s_addr = 0; + + any->namelen = sizeof(any->s.in); + return AF_INET; + } + while(0); + /* Look and see if we can parse an ipv4 address */ do { + #define IPV4_PORT_CHARS #define IPV4_CHARS "0123456789." #define IPV4_MIN 3 #define IPV4_MAX 18 int port = 0; - char buf[IPV4_MAX + 1]; - t = NULL; l = strlen(addr); @@ -51,7 +79,6 @@ int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport) if(t) { - char* t2; port = strtol(t, &t2, 10); if(*t2 || port <= 0 || port >= 65536) break; @@ -76,8 +103,6 @@ int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport) #define IPV6_MAX 48 int port = -1; - char buf[IPV6_MAX + 1]; - t = NULL; l = strlen(addr); @@ -131,9 +156,11 @@ int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport) while(0); #endif + /* A unix socket path */ do { - if(strchr(addr, ':')) + /* No colon and must have a path component */ + if(strchr(addr, ':') || !strchr(addr, '/')) break; l = strlen(addr); @@ -148,6 +175,64 @@ int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport) } while(0); + /* A DNS name and a port? */ + do + { + struct addrinfo* res; + int port = 0; + t = NULL; + + l = strlen(addr); + if(l < 255 && isalpha(addr[0])) + break; + + /* Some basic illegal character checks */ + if(strspn(addr, " /\\") != l) + break; + + strcpy(buf, addr); + + /* Find the last set that contains just numbers */ + t = strchr(buf, ':'); + if(t) + { + *t = 0; + t++; + } + + if(t) + { + port = strtol(t, &t2, 10); + if(*t2 || port <= 0 || port >= 65536) + break; + } + + /* Try and resolve the domain name */ + if(getaddrinfo(buf, NULL, NULL, &res) != 0 || !res) + break; + + memcpy(&(any->s.a), res->ai_addr, sizeof(struct sockaddr)); + any->namelen = res->ai_addrlen; + freeaddrinfo(res); + + port = htons((unsigned short)(port <= 0 ? defport : port)); + + switch(any->s.a.sa_family) + { + case PF_INET: + any->s.in.sin_port = port; + break; +#ifdef HAVE_INET6 + case PF_INET6: + any->s.in6.sin6_port = port; + break; +#endif + }; + + return any->s.a.sa_family; + } + while(0); + return -1; } diff --git a/common/sock_any.h b/common/sock_any.h index f281020..5d733b1 100644 --- a/common/sock_any.h +++ b/common/sock_any.h @@ -8,7 +8,6 @@ struct sockaddr_any { - size_t namelen; union _sockaddr_any { /* The header */ @@ -21,6 +20,7 @@ struct sockaddr_any struct sockaddr_in6 in6; #endif } s; + size_t namelen; }; #define SANY_ADDR(any) (&((any).s.a)) diff --git a/configure.in b/configure.in index b3ecf3d..c70ae2b 100644 --- a/configure.in +++ b/configure.in @@ -92,9 +92,9 @@ AC_CHECK_DECL(PTHREAD_MUTEX_ERRORCHECK_NP, [AC_DEFINE(HAVE_ERR_MUTEX, 1, "Error [ #include ])], [ #include ]) # Required Functions -AC_CHECK_FUNCS([memset strerror malloc realloc getopt strchr tolower], , +AC_CHECK_FUNCS([memset strerror malloc realloc getopt strchr tolower getaddrinfo], , [echo "ERROR: Required function missing"; exit 1]) AC_CHECK_FUNCS([strlwr]) -AC_CONFIG_FILES([Makefile daemon/Makefile]) +AC_CONFIG_FILES([Makefile daemon/Makefile doc/Makefile]) AC_OUTPUT diff --git a/daemon/defaults.h b/daemon/defaults.h index 828bec1..b3c6fcf 100644 --- a/daemon/defaults.h +++ b/daemon/defaults.h @@ -3,7 +3,7 @@ #define __DEFAULTS_H__ #define DEFAULT_PENDING_MAX 16 -#define DEFAULT_PENDING_TIMEOUT 60 +#define DEFAULT_PENDING_TIMEOUT 20 #define DEFAULT_TIMEOUT 900 #define DEFAULT_CACHEMAX 1024 #define DEFAULT_PORT 8020 diff --git a/daemon/digest.c b/daemon/digest.c index 0bd6398..5c53191 100644 --- a/daemon/digest.c +++ b/daemon/digest.c @@ -242,7 +242,7 @@ int digest_parse(char* header, ha_buffer_t* buf, digest_header_t* rec, if(rec->nonce) { size_t len = DIGEST_NONCE_LEN; - void* d = ha_bufdec64(buf, rec->nonce, &len); + void* d = ha_bufdechex(buf, rec->nonce, &len); if(d && len == DIGEST_NONCE_LEN) memcpy(nonce, d, DIGEST_NONCE_LEN); @@ -252,15 +252,15 @@ int digest_parse(char* header, ha_buffer_t* buf, digest_header_t* rec, return HA_OK; } -int digest_check(const char* realm, const char* method, const char* uri, - ha_buffer_t* buf, digest_header_t* dg, digest_record_t* rec) +int digest_check(digest_header_t* dg, digest_record_t* rec, ha_options_t* opts, + ha_buffer_t* buf, const char* method, const char* uri) { unsigned char hash[MD5_LEN]; md5_ctx_t md5; const char* digest; const char* t; - ASSERT(realm && method && uri && buf && dg && rec); + ASSERT(opts && method && buf && dg && rec); /* TODO: Many of these should somehow communicate BAD REQ back to the client */ @@ -272,21 +272,31 @@ int digest_check(const char* realm, const char* method, const char* uri, } /* Username */ - if(!dg->username || !dg->username[0] || - md5_strcmp(rec->userhash, dg->username) != 0) + if(!dg->username || !dg->username[0]) { ha_messagex(LOG_WARNING, "digest response missing username"); return HA_BADREQ; } + if(md5_strcmp(rec->userhash, dg->username) != 0) + { + ha_messagex(LOG_ERR, "digest response contains invalid username"); + return HA_FALSE; + } + /* The realm */ - if(!dg->realm || strcmp(dg->realm, realm) != 0) + if(!dg->realm) { - ha_messagex(LOG_WARNING, "digest response contains invalid realm: '%s'", - dg->realm ? dg->realm : ""); + ha_messagex(LOG_WARNING, "digest response contains missing realm"); return HA_BADREQ; } + if(strcmp(dg->realm, opts->realm) != 0) + { + ha_messagex(LOG_ERR, "digest response contains invalid realm: %s", dg->realm); + return HA_FALSE; + } + /* Components in the new RFC */ if(dg->qop) { @@ -308,25 +318,38 @@ int digest_check(const char* realm, const char* method, const char* uri, return HA_BADREQ; } - /* The nonce count */ - if(!dg->nc || !dg->nc[0]) + if(!opts->digest_ignorenc) { - ha_messagex(LOG_WARNING, "digest response is missing nc value"); - return HA_BADREQ; - } - - /* Validate the nc */ - else - { - char* e; - long nc = strtol(dg->nc, &e, 10); - - if(*e || nc != rec->nc) + /* The nonce count */ + if(!dg->nc || !dg->nc[0]) { - ha_messagex(LOG_WARNING, "digest response has invalid nc value: %s", - dg->nc); + ha_messagex(LOG_WARNING, "digest response is missing nc value"); return HA_BADREQ; } + + /* Validate the nc */ + else + { + char* e; + long nc = strtol(dg->nc, &e, 16); + + if(*e) + { + ha_messagex(LOG_ERR, "digest response has invalid nc value: %s", dg->nc); + return HA_BADREQ; + } + + /* If we didn't a nc then save it away */ + if(!*e && rec->nc == 0) + rec->nc = nc; + + if(*e || nc != rec->nc) + { + ha_messagex(LOG_WARNING, "digest response has wrong nc value. " + "possible replay attack: %s", dg->nc); + return HA_FALSE; + } + } } } @@ -345,7 +368,7 @@ int digest_check(const char* realm, const char* method, const char* uri, return HA_BADREQ; } - if(strcmp(dg->uri, uri) != 0) + if(!opts->digest_ignoreuri && strcmp(dg->uri, uri) != 0) { ha_uri_t d_uri; ha_uri_t s_uri; @@ -370,9 +393,9 @@ int digest_check(const char* realm, const char* method, const char* uri, if(ha_uricmp(&d_uri, &s_uri) != 0) { - ha_messagex(LOG_WARNING, "digest response contains wrong uri: %s " - "(should be %s)", dg->uri, uri); - return HA_BADREQ; + ha_messagex(LOG_ERR, "digest response contains wrong uri: %s " + "(should be %s)", dg->uri, uri); + return HA_FALSE; } } @@ -523,14 +546,14 @@ const char* digest_respond(ha_buffer_t* buf, digest_header_t* dg, return NULL; ha_bufmcat(buf, "rspauth=\"", t, "\"", - " qop=", dg->qop, - " nc=", dg->nc, - " cnonce=\"", dg->cnonce, "\"", NULL); + ", qop=", dg->qop, + ", nc=", dg->nc, + ", cnonce=\"", dg->cnonce, "\"", NULL); if(nextnonce) { ha_bufjoin(buf); - ha_bufmcat(buf, " nextnonce=\"", nextnonce, "\"", NULL); + ha_bufmcat(buf, ", nextnonce=\"", nextnonce, "\"", NULL); } return ha_bufdata(buf); diff --git a/daemon/digest.h b/daemon/digest.h index 0f5e6b2..8eec901 100644 --- a/daemon/digest.h +++ b/daemon/digest.h @@ -42,8 +42,8 @@ int ha_digestparse(char* header, ha_buffer_t* buf, digest_header_t* rec, int ha_digestnonce(time_t* tm, unsigned char* nonce); -int ha_digestcheck(const char* realm, const char* method, const char* uri, - ha_buffer_t* buf, digest_header_t* header, digest_record_t* rec); +int digest_check(digest_header_t* dg, digest_record_t* rec, ha_options_t* opts, + ha_buffer_t* buf, const char* method, const char* uri); const char* digest_respond(ha_buffer_t* buf, digest_header_t* dg, digest_record_t* rec, unsigned char* next); diff --git a/daemon/httpauthd.c b/daemon/httpauthd.c index 7c74754..55092db 100644 --- a/daemon/httpauthd.c +++ b/daemon/httpauthd.c @@ -1314,6 +1314,16 @@ static int config_parse(const char* file, ha_buffer_t* buf) recog = 1; } + else if(strcmp(name, "digestignorenc") == 0) + { + int v; + if(ha_confbool(name, value, &v) < 0) + exit(1); /* Message already printed */ + + opts->digest_ignorenc = v; + recog = 1; + } + else if(strcmp(name, "digestdomains") == 0) { opts->digest_domains = value; diff --git a/daemon/httpauthd.h b/daemon/httpauthd.h index cd1d39e..d225e4b 100644 --- a/daemon/httpauthd.h +++ b/daemon/httpauthd.h @@ -188,7 +188,8 @@ typedef struct ha_options const char* realm; /* For digest auth: */ - int digest_ignoreuri; + unsigned int digest_ignoreuri : 1; + unsigned int digest_ignorenc : 1; const char* digest_domains; const char* digest_debugnonce; } diff --git a/daemon/ldap.c b/daemon/ldap.c index 78e048f..1e03c32 100644 --- a/daemon/ldap.c +++ b/daemon/ldap.c @@ -981,7 +981,7 @@ static int digest_ldap_challenge(ldap_context_t* ctx, ha_response_t* resp, if(ctx->opts->digest_debugnonce) { nonce_str = ctx->opts->digest_debugnonce; - ha_messagex(LOG_WARNING, "simple: using debug nonce. security non-existant."); + ha_messagex(LOG_WARNING, "ldap: using debug nonce. security non-existant."); } else #endif @@ -1036,7 +1036,6 @@ static int digest_ldap_response(ldap_context_t* ctx, const char* header, if(dg.nonce && strcmp(dg.nonce, ctx->opts->digest_debugnonce) != 0) { ret = HA_FALSE; - resp->code = HA_SERVER_BADREQ; ha_messagex(LOG_WARNING, "ldap: digest response contains invalid nonce"); goto finally; } @@ -1054,10 +1053,7 @@ static int digest_ldap_response(ldap_context_t* ctx, const char* header, if(r != HA_OK) { if(r == HA_FALSE) - { - resp->code = HA_SERVER_BADREQ; ha_messagex(LOG_WARNING, "ldap: digest response contains invalid nonce"); - } goto finally; } @@ -1099,11 +1095,13 @@ static int digest_ldap_response(ldap_context_t* ctx, const char* header, } } - /* Increment our nonce count */ - rec->nc++; + /* We had a record so ... */ + else + { + rec->nc++; + } - ret = digest_check(ctx->opts->realm, method, - ctx->opts->digest_ignoreuri ? NULL : uri, buf, &dg, rec); + ret = digest_check(&dg, rec, ctx->opts, buf, method, uri); if(ret == HA_BADREQ) { @@ -1391,7 +1389,7 @@ int ldap_process(ha_context_t* context, ha_request_t* req, header = ha_getheader(req, "Authorization", HA_PREFIX_DIGEST); if(header) { - ha_messagex(LOG_DEBUG, "ldap: processing basic auth header"); + ha_messagex(LOG_DEBUG, "ldap: processing digest auth header"); ret = digest_ldap_response(ctx, header, req->args[AUTH_ARG_METHOD], req->args[AUTH_ARG_URI], resp, buf); if(ret < 0) @@ -1405,7 +1403,7 @@ int ldap_process(ha_context_t* context, ha_request_t* req, header = ha_getheader(req, "Authorization", HA_PREFIX_BASIC); if(header) { - ha_messagex(LOG_DEBUG, "ldap: processing digest auth header"); + ha_messagex(LOG_DEBUG, "ldap: processing basic auth header"); ret = basic_ldap_response(ctx, header, resp, buf); if(ret < 0) return ret; diff --git a/daemon/simple.c b/daemon/simple.c index 5b4eb60..d45668f 100644 --- a/daemon/simple.c +++ b/daemon/simple.c @@ -458,7 +458,6 @@ static int simple_digest_response(simple_context_t* ctx, const char* header, { if(dg.nonce && strcmp(dg.nonce, ctx->opts->digest_debugnonce) != 0) { - resp->code = HA_SERVER_BADREQ; ret = HA_FALSE; ha_messagex(LOG_WARNING, "simple: digest response contains invalid nonce"); goto finally; @@ -477,10 +476,7 @@ static int simple_digest_response(simple_context_t* ctx, const char* header, if(r != HA_OK) { if(r == HA_FALSE) - { - resp->code = HA_SERVER_BADREQ; ha_messagex(LOG_WARNING, "simple: digest response contains invalid nonce"); - } ret = r; goto finally; @@ -523,11 +519,13 @@ static int simple_digest_response(simple_context_t* ctx, const char* header, } } - /* Increment our nonce count */ - rec->nc++; + /* We had a record so ... */ + else + { + rec->nc++; + } - ret = digest_check(ctx->opts->realm, method, - ctx->opts->digest_ignoreuri ? NULL : uri, buf, &dg, rec); + ret = digest_check(&dg, rec, ctx->opts, buf, method, uri); if(ret == HA_BADREQ) { diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..56ca28e --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,4 @@ + +man_MANS = httpauthd.8 httpauthd.conf.5 + +EXTRA_DIST = protocol.txt httpauthd.conf.sample ${man_MANS} diff --git a/doc/httpauth.conf.5 b/doc/httpauth.conf.5 deleted file mode 100644 index fd26c7b..0000000 --- a/doc/httpauth.conf.5 +++ /dev/null @@ -1,82 +0,0 @@ -.Dd April, 2004 -.Dt HTTPAUTH.CONF 5 -.Os httpauth -.Sh NAME -.Nm httpauth.conf -.Nd the configuration file for -.Em httpauthd -.Sh DESCRIPTION -The XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx -.Nm -scripting language is a regular expression language used for fine grained, -buffer based search and replace. It is not limited to lines. A full description -of what -.Nm -is capable of is outside the scope of this document. -.Pp -.Ar script -is a text or compiled -.Nm -script. For details see the language documentation that came along with the distribution. -.Pp -When used with the -.Fl f -argument -.Nm -replaces files in place. Otherwise it reads from -.Ar infile -and writes to -.Ar outfile -\&. If either infile or outfile are missing or are equal to a dash -.Sq Li - -, then rep processes -.Em stdin -or -.Em stdout -respectively. -.Sh OPTIONS -The options are as follows: -.Bl -tag -width Fl -.It Fl b -Backup files where replacements have occurred. The backup files have an -.Sq x_r -extension appended to their filename. -.It Fl i -Prompt for confirmation before each replacement. -.It Fl p -Only output replaced text. Can be used as a rudimentary parser. -.It Fl q -Supress status messages. Only errors will be sent to stderr. -.It Fl z -Set the replacement buffer size to -.Ar buffsize . -This speeds up execution as regular expressions only have to act on a small -portion of the whole file at once. However the largest match will be limited to -roughly -.Ar buffsize -, so use this option with care. The script loops over each buffer until no more -matches are found within it. Care is taken to overlap the buffers as much as -possible to ensure that any match smaller than -.Ar buffsize -can be matched. -.Sh NOTE -The -.Nm -command uses -.Xr getopt 3 -to parse it's arguments, which allows it to accept -the -.Sq Li -- -option which will stop processing of flag options at that point. This allows -the processing of files with names that begin with a dash -.Pq Sq - . -.Sh BUGS -When reading from -.Em stdin -you must specify a buffer size. -.Sh SEE ALSO -.Xr repc 1 , -.Xr rlib 3 , -.Xr pcre 3 -.Sh AUTHOR -.An Nate Nielsen Aq nielsen@memberwebs.com \ No newline at end of file diff --git a/doc/httpauthd.8 b/doc/httpauthd.8 new file mode 100644 index 0000000..afdf753 --- /dev/null +++ b/doc/httpauthd.8 @@ -0,0 +1,45 @@ +.Dd April, 2004 +.Dt httpauthd 8 +.Os httpauth +.Sh NAME +.Nm httpauthd +.Nd a daemon which performs HTTP authentication +.Sh DESCRIPTION +.Xr httpauthd 8 +is a daemon that performs HTTP authentication for a variety of HTTP servers. +Callers send it HTTP headers, which it then processes and returns responses +destined for the client. +.Pp +It listens on unix or IP sockets, allowing for centralization of HTTP +authentication and an extra layer security if necessary. +.Pp +.Nm httpauthd +can perform a variety of different types of authentication, and is built +in an extensible manner so more can be added in the future. +.Pp +.Bl -bullet -compact +.It +Basic and Digest authentication against a file. +.It +Basic and Digest authentication against an LDAP server. +.It +Basic and NTLM authentication against a SMB domain server. +.El +.Sh OPTIONS +The options are as follows: +.Bl -tag -width Fl +.It Fl d +Don't detach from the console and run as a daemon. In addition the +.Ar level +argument specifies what level of error messages to display. 0 being +the least, 4 the most. +.It Fl f +Specify an alternate location for the configuration file. +.It Fl X +Process stdin and stdout instead of listening for connections on a +socket. Useful for troubleshooting problems. +.El +.Sh SEE ALSO +.Xr httpauth.conf 8 +.Sh AUTHOR +.An Nate Nielsen Aq nielsen@memberwebs.com diff --git a/doc/httpauthd.conf.5 b/doc/httpauthd.conf.5 new file mode 100644 index 0000000..2e3c49e --- /dev/null +++ b/doc/httpauthd.conf.5 @@ -0,0 +1,316 @@ +.Dd April, 2004 +.Dt httpauthd.conf 5 +.Os httpauth +.Sh NAME +.Nm httpauthd.conf +.Nd the configuration file for +.Xr httpauthd 8 +.Sh DESCRIPTION +.Xr httpauthd 8 +reads it's configuration from this file when starting up. It contains global +settings followed by the various authentication methods and their settings. +.Sh SYNTAX +The settings are specified one per line. The setting name comes first +followed by a colon, and the value for that setting. Authentication method +sections are prefixed with a '[method]' on a line of it's own. +.Pp +Lines beginning with a # mark are comments. An example: +.Bd -literal -offset indent +# Sample Configuration File +Socket: 0.0.0.0:8020 +AuthTypes: Basic Digest + +[Simple] +Alias: MyAuth +PasswordFile: /srv/passwd.file +.Ed +.Sh AUTHENTICATION METHODS +Methods are the various ways +.Xr httpauthd +can authenticate a user. A method will use either LDAP, a file or some +other means to determine if a user is valid. The methods currently +implemented are: +.Ar Simple LDAP NTLM +.Pp +A method block in the configuration file needs to contain one of the +above method names as the header for it's section (ie: [LDAP]). It +can be given another name by specifying an +.Em Alias +for it. +.Pp +This allows for the creation of various configurations with purpose +specific names. These names are used by callers of +.Xr httpauthd 8 +to identify how to authenticate a given HTTP connection. +.Sh GLOBAL OPTIONS +These options affect httpauthd as a whole. They should be placed before the +beginning of the first authentication method section. In addition certain +options can be placed in this section which affect all the authentication +methods. These are outlined under the +.Em METHOD OPTIONS +heading further below. +.Bl -hang +.It Cd Socket +This is where httpauthd listens for connections. It can either be a unix +type socket by specifying a file path (eg: /var/run/ha.sock), a port number +(eg: 8030) or a IP address with optional port number (eg: 192.168.2.38:8200). +If you specify an IP address without a port, +.Em 8020 +will be used. +.Pp +[ Default: +.Em /var/run/httpauthd.sock +] +.It Cd MaxThreads +This equals the amount of authentication connections that +.Xr httpauthd 8 +will be able to have open at once. +.Pp +[ Default: +.Em 32 +] +.El + +.Sh METHOD OPTIONS +These options change settings in how the various methods handle authentication. +When they appear after a method section, they only affect that method. Most of +them can also appear in the inital section of the configuration file in which +case they're used as defaults. +.Bl -hang +.It Cd Alias +Change the name of the current authentication method. This is necessary when +you're using a certain method twice (eg: LDAP) with different settings. This +option can only be used in a method section. +.It Cd AuthTypes +The allowed HTTP authentication types, separated by spaces. Any combination of: +.Ar Basic Digest NTLM +.Pp +[ Default: +.Ar Basic Digest NTLM +] +.It Cd CacheMax +The maximum amount of successful authentication requests a method can cache. +.Pp +[ Default: +.Em 1024 +] +.It Cd CacheTimeout +The length of time in seconds that a successful authentication remains cached. +How this exactly works depends on the method it applies to. +.Pp +[ Default: +.Em 900 +] +.It Cd DigestDomains +The +.Em domains +setting used with +.Em Digest +authentication. This allows you to specify one or more URIs which are in the +same authentication space. The specified URIs are prefixes, i.e. the +client will assume that all URIs "below" these are also protected by the +same username/password. The URIs may be either absolute URIs (i.e. inluding +a scheme, host, port, etc) or relative URIs. Separated by spaces. +.Pp +[ Default: +.Em (none) +] +.It Cd DigestIgnoreNC +When set to +.Em True +allows the NC value in +.Em Digest +authentication to be incorrect. This opens up various replay attacks. +.Pp +[ Default: +.Em False +] +.It Cd DigestIgnoreURI +When set to +.Em True +allows the URI value in +.Em Digest +authentication to be mismatched with the URI requested. This opens up +a variety of replay attacks, but may be necessary in some cases. +.Pp +[ Default: +.Em False +] +.It Cd Realm +The realm used in +.Em Basic +and +.Em Digest +authentication. +.Pp +[ Default: +.Em (none) +] +.El +.Sh SIMPLE METHOD OPTIONS +These are settings for the +.Em Simple +authentication method. This method authenticates against password hashes in a file. +.Bl -hang +.It Cd PasswordFile +The path of the file that contains the password hashes. This file can be in either +the format created by +.Xr htpasswd 1 +or +.Xr htdigest 1 +(tools that come with apache). +.Pp +[ Required ] +.El +.Sh LDAP METHOD OPTIONS +Settings for the +.Em LDAP +authentication method. This method authenticates users against an LDAP server. +.Bl -hang +.It Cd LDAPBase +The base DN to use in the search for a user. This only applies when no +LDAPDNMap is specified. +.Pp +[ Required when +.Em LDAPDNMap +is missing ] +.It Cd LDAPDNMap +Specifies the DN for a user name. The +.Em %u +and +.Em %r +flags can be used in the DN, which will substitute the user and realm +respectively. +.Pp +[ Optional ] +.It Cd LDAPDoBind +When performing Basic authentication, +.Xr httpauthd +can try to bind to the LDAP server as the user in question. This +allows authentication even when no access to cleartext passwords +is available. Note that this does not apply to Digest authentication. +.Pp +[ Default: +.Em True +] +.It Cd LDAPFilter +The LDAP filter to use when querying the server. The +.Em %u +and +.Em %r +flags can be used in the filter, which will substitute the user and realm +respectively. When used without a +.Em LDAPDNMap +then this is used to identify the LDAP entry for the user. In this case care +should be taken that the filter only returns one record. +.Pp +[ Required when +.Em LDAPDNMap +is missing ] +.It Cd LDAPHA1Attr +A HA1 is a special kind of digest containing the user name, realm and +password. This can be used in place of cleartext passwords when doing +Digest authentication. This setting specifies the attribute on the +LDAP server that the hash can be found in. +.Pp +.Xr httpauthd 8 +can perform both Basic and Digest authentication against this attribute. +Note that the realm however is stored in the hash and must match the +realm being sent to the client in the +.Em Realm +setting. +.Pp +[ Optional ] +.It Cd LDAPMax +The maximum amount of connections to make to the LDAP server. +.Pp +[ Default: +.Em 10 +] +.It Cd LDAPPasswsord +The password to use with +.Em LDAPUser +.Pp +[ Optional ] +.It Cd LDAPPwAttr +The name of the attribute on the LDAP server that contains the user's +password. This can be for Basic authentication (when +.Em LDAPDoBind +is off) or Digest authentication. When used with Digest Auth (and no +.Em LDAPHA1Attr +is specified) it needs to contain a cleartext password. +.Pp +[ Default: +.Em userPassword +] +.It Cd LDAPScope +When searching the LDAP for a user (ie: +.Em LDAPDNMap +is not specified) this is the scope for the search. Specify one of the +following: +.Ar sub base one +.Pp +[ Default: +.Em sub +] +.It Cd LDAPServers +The host names or IP addresses of the LDAP servers to authenticate against. +Separated by spaces. More than one can be specified for failover capability. +.Pp +[ Required ] +.It Cd LDAPTimeout +The timeout for searches on the LDAP server (in seconds). +.Pp +[ Default: +.Em 30 +] +.It Cd LDAPUser +When specified +.Xr httpauthd +will bind as this user after connecting to the LDAP server. This is useful +in the case where anonymous users can't perform LDAP searches, for example. +.Pp +[ Optional ] +.El +.Sh NTLM METHOD OPTIONS +Settings for the +.Em NTLM +authentication method. This method authenticates users against NT domain +server. +.Bl -hang +.It Cd NTLMBackup +The backup domain server to authenticate against. Used when +.Em NTLMServer +is not available. +.Pp +[ Optional ] +.It Cd NTLMDomain +The domain which contains the users that will be authenticated. This is +the NT domain, not the DNS domain. +.Pp +[ Required ] +.It Cd NTLMServer +The domain server to authenticate against. You should specify a name here +not an IP address. +.Pp +[ Required ] +.It Cd PendingMax +The maximum amount of halfway authenticated NTLM connections allowed. +This corresponds directly to the amount of concurrent connections made to +.Em NTLMServer +.Pp +[ Default: +.Em 16 +] +.It Cd PendingTimeout +The maximum time a halfway authenticated NTLM connection is allowed to +remain that way (in seconds). +.Pp +[ Default: +.Em 20 +] +.El +.Sh SEE ALSO +.Xr httpauthd 8 +.Sh AUTHOR +.An Nate Nielsen Aq nielsen@memberwebs.com diff --git a/doc/httpauthd.conf.sample b/doc/httpauthd.conf.sample new file mode 100644 index 0000000..f5e1e87 --- /dev/null +++ b/doc/httpauthd.conf.sample @@ -0,0 +1,34 @@ + +# Sample HTTPAUTH configuration file + +# Listen on a TCP port +Socket: 0.0.0.0 + +# Only perform Digest authentication +AuthTypes: Digest + +# ---------------------------------------------------- +# This is the beginning of an Simple method section +[Simple] + +# Give the method a name +Alias: LocalUsers + +# The file +PasswordFile: /usr/data/localusers.pw + + + + +# ---------------------------------------------------- +# This is the beginning of an LDAP method section +[LDAP] + +# Give the method a name +Alias: AllUsers + +LDAPServers: ldap.test.com +LDAPDoBind: True +LDAPDNMap: cn=%u,dc=test,dc=com +LDAPFilter: (objectClass=person) + diff --git a/sample/httpauthd.conf b/sample/httpauthd.conf index ae59ce2..f11f48e 100644 --- a/sample/httpauthd.conf +++ b/sample/httpauthd.conf @@ -3,31 +3,29 @@ # and blank lines MaxThreads: 18 CacheTimeout: 300 -AuthTypes: Basic Digest +AuthTypes: Digest +# AuthTypes: Basic Digest Socket: 0.0.0.0:8020 +DigestIgnoreNC: True + [Simple] Realm: blah PasswordFile: /data/projects/httpauth/sample/passwd.file -DigestDebugNonce: AkCLQA==560f26e24db2d4cecbe5d6e24d958377ab73def9 [LDAP] Realm: blah LDAPServers: authdev.ws.local LDAPDoBind: False -LDAPDNMap: cn=%u,ou=test,dc=fam -DigestDomains: http://test.ws.local/ +# LDAPDNMap: cn=%u,ou=test,dc=fam +# DigestDomains: http://test.ws.local/ LDAPUser: cn=root,dc=fam LDAPPassword: ldaptest@@password -LDAPHA1Attr: login -# LDAPPWAttr: clearPassword - -LDAPFilter: (&(comment=%r)(&(cn=%u)(objectClass=contactInfo))) -LDAPBase: ou=test,dc=fam -LDAPScope: one +# LDAPHA1Attr: login +LDAPPWAttr: clearPassword -DigestDebugNonce: AkCLQA==560f26e24db2d4cecbe5d6e24d958377ab73def9 +LDAPFilter: (cn=%u) +LDAPBase: dc=fam +LDAPScope: sub -# LDAPMax: -# LDAPTimeout: -- cgit v1.2.3