From: robertc <> Date: Tue, 1 Apr 2003 17:39:38 +0000 (+0000) Subject: Summary: Merge in digest helper refactoring. X-Git-Tag: SQUID_3_0_PRE1~256 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0ff1980a4e05750076c5c5d31d6daa5c2b13a1e5;p=thirdparty%2Fsquid.git Summary: Merge in digest helper refactoring. Keywords: Patches applied: * robertc@squid-cache.org--squid/squid--digest-auth--3.0--patch-6 Merge from HEAD. * robertc@squid-cache.org--squid/squid--digest-auth--3.0--patch-5 Tweak digest helper. * robertc@squid-cache.org--squid/squid--digest-auth--3.0--patch-4 Factor digest password helper for easy extension. * robertc@squid-cache.org--squid/squid--digest-auth--3.0--patch-3 merge from HEAD. --- diff --git a/helpers/digest_auth/password/Makefile.am b/helpers/digest_auth/password/Makefile.am index 72ab19aab4..652410c8a4 100644 --- a/helpers/digest_auth/password/Makefile.am +++ b/helpers/digest_auth/password/Makefile.am @@ -1,12 +1,16 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.am,v 1.2 2003/01/23 00:35:54 robertc Exp $ +# $Id: Makefile.am,v 1.3 2003/04/01 10:39:38 robertc Exp $ # # Uncomment and customize the following to suit your needs: # libexec_PROGRAMS = digest_pw_auth +digest_pw_auth_SOURCES = digest_pw_auth.c \ + digest_common.h \ + text_backend.c \ + text_backend.h INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ -I$(top_srcdir)/src/ diff --git a/helpers/digest_auth/password/digest_common.h b/helpers/digest_auth/password/digest_common.h new file mode 100644 index 0000000000..e69f9fa1ce --- /dev/null +++ b/helpers/digest_auth/password/digest_common.h @@ -0,0 +1,57 @@ +/* + * digest_common.h + * + * AUTHOR: Robert Collins. + * + * Digest helper API details. + * + * Copyright (c) 2003 Robert Collins + */ + +#ifndef _SQUID_DIGEST_COMMON_H_ +#define _SQUID_DIGEST_COMMON_H_ + +#include "config.h" +#if HAVE_STDIO_H +#include +#endif +#if HAVE_STDLIB_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_STRING_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_CRYPT_H +#include +#endif + +#include "util.h" +#include "hash.h" +#include "rfc2617.h" + +typedef struct _request_data { + char *user; + char *realm; + char *password; + HASHHEX HHA1; + int parsed; + int error; +} RequestData; + +/* to use a backend, include your backend.h file + * and define thusly: + * #define ProcessArguments(A, B) MyHandleArguments(A,B) + * #define GetHHA1(A) MyGetHHA1(A) + */ +typedef void HandleArguments (int, char **); +typedef void HHA1Creator(RequestData *); +#endif /* _SQUID_DIGEST_COMMON_H_ */ diff --git a/helpers/digest_auth/password/digest_pw_auth.c b/helpers/digest_auth/password/digest_pw_auth.c index f5854b929c..1e42d7da73 100644 --- a/helpers/digest_auth/password/digest_pw_auth.c +++ b/helpers/digest_auth/password/digest_pw_auth.c @@ -26,168 +26,59 @@ * they allow the user access. Password syncronisation is not tackled * by digest - just preventing on the wire compromise. * + * Copyright (c) 2003 Robert Collins */ -#include "config.h" -#if HAVE_STDIO_H -#include -#endif -#if HAVE_STDLIB_H -#include -#endif -#if HAVE_UNISTD_H -#include -#endif -#if HAVE_STRING_H -#include -#endif -#if HAVE_SYS_TYPES_H -#include -#endif -#if HAVE_SYS_STAT_H -#include -#endif -#if HAVE_CRYPT_H -#include -#endif - -#include "util.h" -#include "hash.h" -#include "rfc2617.h" - -static hash_table *hash = NULL; -static HASHFREE my_free; - -typedef struct _user_data { - hash_link hash; - char *passwd; - char *realm; -} user_data; +#include "digest_common.h" +#include "text_backend.h" static void -my_free(void *p) +ParseBuffer(char *buf, RequestData *requestData) { - user_data *u = p; - xfree(u->hash.key); - xfree(u->passwd); - xfree(u); + char *p; + requestData->parsed = 0; + if ((p = strchr(buf, '\n')) != NULL) + *p = '\0'; /* strip \n */ + if ((requestData->user = strtok(buf, "\"")) == NULL) + return; + if ((requestData->realm = strtok(NULL, "\"")) == NULL) + return; + if ((requestData->realm = strtok(NULL, "\"")) == NULL) + return; + requestData->parsed = -1; } static void -read_passwd_file(const char *passwdfile, int ha1mode) +OutputHHA1(RequestData *requestData) { - FILE *f; - char buf[8192]; - user_data *u; - char *user; - char *passwd; - int passwdha1; - - if (hash != NULL) { - hashFreeItems(hash, my_free); + requestData->error = 0; + GetHHA1(requestData); + if (requestData->error) { + printf("ERR\n"); + return; } - /* initial setup */ - hash = hash_create((HASHCMP *) strcmp, 7921, hash_string); - if (NULL == hash) { - fprintf(stderr, "digest_pw_auth: cannot create hash table\n"); - exit(1); - } - f = fopen(passwdfile, "r"); - while (fgets(buf, 8192, f) != NULL) { - if ((buf[0] == '#') || (buf[0] == ' ') || (buf[0] == '\t') || - (buf[0] == '\n')) - continue; - user = strtok(buf, ":\n"); - passwd = strtok(NULL, ":\n"); - if ((strlen(user) > 0) && passwd) { - passwdha1 = (strncmp("{HHA1}", passwd, 6))?0:1; - if (!ha1mode || passwdha1) { - u = xmalloc(sizeof(*u)); - u->hash.key = xstrdup(user); - u->passwd = xstrdup(passwd); - hash_join(hash, &u->hash); - } else { - /* We cannot accept plaintext passwords when using HA1 encoding, - * as the passwords may be output to cache.log if debugging is on. - */ - fprintf(stderr, "digest_pw_auth: ignoring %s password for %s\n", - "plaintext", user); - } - } + printf("%s\n", requestData->HHA1); +} + +static void +DoOneRequest(char *buf) +{ + RequestData requestData; + ParseBuffer (buf, &requestData); + if (!requestData.parsed) { + printf ("ERR\n"); + return; } - fclose(f); + OutputHHA1(&requestData); } int main(int argc, char **argv) { - struct stat sb; - time_t change_time = 0; char buf[256]; - char *user, *realm, *p, *passwdfile=NULL; - user_data *u; - HASH HA1; - HASHHEX HHA1; - int ha1mode=0; - setbuf(stdout, NULL); - if(argc == 2){ - passwdfile = argv[1]; - } - if((argc == 3) && !strcmp("-c", argv[1])){ - ha1mode=1; - passwdfile = argv[2]; - } - if (!passwdfile) { - fprintf(stderr, "Usage: digest_pw_auth [OPTIONS] \n"); - fprintf(stderr, " -c accept HHA1 passwords rather than plaintext in passwordfile\n"); - exit(1); - } - if (stat(passwdfile, &sb) != 0) { - fprintf(stderr, "cannot stat %s\n", passwdfile); - exit(1); - } - while (fgets(buf, 256, stdin) != NULL) { - if ((p = strchr(buf, '\n')) != NULL) - *p = '\0'; /* strip \n */ - if (stat(passwdfile, &sb) == 0) { - if (sb.st_mtime != change_time) { - read_passwd_file(passwdfile, ha1mode); - change_time = sb.st_mtime; - } - } - if (!hash) { - printf("ERR\n"); - continue; - } - if ((user = strtok(buf, "\"")) == NULL) { - printf("ERR\n"); - continue; - } - if ((realm = strtok(NULL, "\"")) == NULL) { - printf("ERR\n"); - continue; - } - if ((realm = strtok(NULL, "\"")) == NULL) { - printf("ERR\n"); - continue; - } - u = (user_data *)hash_lookup(hash, user); - if (u == NULL) { - printf("ERR\n"); - } else { - - if(! ha1mode ) - { - DigestCalcHA1("md5", user, realm, u->passwd, NULL, NULL, HA1, HHA1); - printf("%s\n", HHA1); - /* fprintf(stderr, "digest_pw_auth: %s:{HHA1}%s\n", user, HHA1); */ - } - else - { - printf("%s\n", &u->passwd[6]); - } - } - } + ProcessArguments (argc, argv); + while (fgets(buf, 256, stdin) != NULL) + DoOneRequest (buf); exit(0); } diff --git a/helpers/digest_auth/password/text_backend.c b/helpers/digest_auth/password/text_backend.c new file mode 100644 index 0000000000..ee6fa34311 --- /dev/null +++ b/helpers/digest_auth/password/text_backend.c @@ -0,0 +1,155 @@ +/* + * text_backend.c + * + * AUTHOR: Robert Collins. Based on ncsa_auth.c by Arjan de Vet + * + * + * Example digest auth text backend for Squid, based on the original + * proxy_auth code from client_side.c, written by + * Jon Thackray . + * + * - comment lines are possible and should start with a '#'; + * - empty or blank lines are possible; + * - file format is username:password + * + * To build a directory integrated backend, you need to be able to + * calculate the HA1 returned to squid. To avoid storing a plaintext + * password you can calculate MD5(username:realm:password) when the + * user changes their password, and store the tuple username:realm:HA1. + * then find the matching username:realm when squid asks for the + * HA1. + * + * This implementation could be improved by using such a triple for + * the file format. However storing such a triple does little to + * improve security: If compromised the username:realm:HA1 combination + * is "plaintext equivalent" - for the purposes of digest authentication + * they allow the user access. Password syncronisation is not tackled + * by digest - just preventing on the wire compromise. + * + * Copyright (c) 2003 Robert Collins + */ + +#include "text_backend.h" + +static hash_table *hash = NULL; +static HASHFREE my_free; +static char *passwdfile = NULL; +static int ha1mode=0; +static time_t change_time = 0; + +typedef struct _user_data { + hash_link hash; + char *passwd; +} user_data; + +static void +my_free(void *p) +{ + user_data *u = p; + xfree(u->hash.key); + xfree(u->passwd); + xfree(u); +} + +static void +read_passwd_file(const char *passwdfile, int ha1mode) +{ + FILE *f; + char buf[8192]; + user_data *u; + char *user; + char *passwd; + int passwdha1; + + if (hash != NULL) { + hashFreeItems(hash, my_free); + } + /* initial setup */ + hash = hash_create((HASHCMP *) strcmp, 7921, hash_string); + if (NULL == hash) { + fprintf(stderr, "digest_pw_auth: cannot create hash table\n"); + exit(1); + } + f = fopen(passwdfile, "r"); + while (fgets(buf, 8192, f) != NULL) { + if ((buf[0] == '#') || (buf[0] == ' ') || (buf[0] == '\t') || + (buf[0] == '\n')) + continue; + user = strtok(buf, ":\n"); + passwd = strtok(NULL, ":\n"); + if ((strlen(user) > 0) && passwd) { + passwdha1 = (strncmp("{HHA1}", passwd, 6))?0:1; + if (!ha1mode || passwdha1) { + u = xmalloc(sizeof(*u)); + u->hash.key = xstrdup(user); + u->passwd = xstrdup(passwd); + hash_join(hash, &u->hash); + } else { + /* We cannot accept plaintext passwords when using HA1 encoding, + * as the passwords may be output to cache.log if debugging is on. + */ + fprintf(stderr, "digest_pw_auth: ignoring %s password for %s\n", + "plaintext", user); + } + } + } + fclose(f); +} + +/* replace when changing the backend */ +void +TextArguments (int argc, char **argv) +{ + struct stat sb; + if(argc == 2) + passwdfile = argv[1]; + if((argc == 3) && !strcmp("-c", argv[1])){ + ha1mode=1; + passwdfile = argv[2]; + } + if (!passwdfile) { + fprintf(stderr, "Usage: digest_pw_auth [OPTIONS] \n"); + fprintf(stderr, " -c accept HHA1 passwords rather than plaintext in passwordfile\n"); + exit(1); + } + if (stat(passwdfile, &sb) != 0) { + fprintf(stderr, "cannot stat %s\n", passwdfile); + exit(1); + } +} + +static void +GetPassword (RequestData *requestData) +{ + user_data *u; + struct stat sb; + if (stat(passwdfile, &sb) == 0) { + if (sb.st_mtime != change_time) { + read_passwd_file(passwdfile, ha1mode); + change_time = sb.st_mtime; + } + } + requestData->password = NULL; + if (!hash) + return; + u = (user_data *)hash_lookup(hash, requestData->user); + if (u != NULL) + requestData->password = u->passwd; +} + +void +TextHHA1(RequestData *requestData) +{ + GetPassword (requestData); + if (requestData->password == NULL) { + requestData->error = -1; + return; + } + if(!ha1mode) { + HASH HA1; + DigestCalcHA1("md5", requestData->user, requestData->realm, requestData->password, NULL, NULL, HA1, requestData->HHA1); + + /* fprintf(stderr, "digest_pw_auth: %s:{HHA1}%s\n", requestData.user, HHA1); */ + } else + xstrncpy (requestData->HHA1, &requestData->password[6], sizeof (requestData->HHA1)); +} diff --git a/helpers/digest_auth/password/text_backend.h b/helpers/digest_auth/password/text_backend.h new file mode 100644 index 0000000000..ec52f1c6a7 --- /dev/null +++ b/helpers/digest_auth/password/text_backend.h @@ -0,0 +1,27 @@ +/* + * text_backend.h + * + * AUTHOR: Robert Collins. + * + * Example digest authentication backend for Squid, + * + * - comment lines are possible and should start with a '#'; + * - empty or blank lines are possible; + * - file format is username:password + * + * This implementation could be improved by using such a triple for + * the file format. However storing such a triple does little to + * improve security: If compromised the username:realm:HA1 combination + * is "plaintext equivalent" - for the purposes of digest authentication + * they allow the user access. Password syncronisation is not tackled + * by digest - just preventing on the wire compromise. + * + * Copyright (c) 2003 Robert Collins + */ + +#include "digest_common.h" + +extern void TextArguments (int argc, char **argv); +#define ProcessArguments(A, B) TextArguments(A,B) +extern void TextHHA1(RequestData *requestData); +#define GetHHA1(A) TextHHA1(A)