]> git.ipfire.org Git - thirdparty/squid.git/blame - helpers/digest_auth/file/text_backend.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / helpers / digest_auth / file / text_backend.cc
CommitLineData
0ff1980a 1/*
2 * text_backend.c
3 *
4 * AUTHOR: Robert Collins. Based on ncsa_auth.c by Arjan de Vet
5 * <Arjan.deVet@adv.iae.nl>
6 *
7 * Example digest auth text backend for Squid, based on the original
8 * proxy_auth code from client_side.c, written by
9 * Jon Thackray <jrmt@uk.gdscorp.com>.
10 *
11 * - comment lines are possible and should start with a '#';
12 * - empty or blank lines are possible;
5fcad6f9 13 * - file format is username:plaintext or username:realm:HA1
26ac0430 14 *
0ff1980a 15 * To build a directory integrated backend, you need to be able to
16 * calculate the HA1 returned to squid. To avoid storing a plaintext
17 * password you can calculate MD5(username:realm:password) when the
18 * user changes their password, and store the tuple username:realm:HA1.
19 * then find the matching username:realm when squid asks for the
20 * HA1.
21 *
22 * This implementation could be improved by using such a triple for
23 * the file format. However storing such a triple does little to
24 * improve security: If compromised the username:realm:HA1 combination
25 * is "plaintext equivalent" - for the purposes of digest authentication
26 * they allow the user access. Password syncronisation is not tackled
27 * by digest - just preventing on the wire compromise.
28 *
29 * Copyright (c) 2003 Robert Collins <robertc@squid-cache.org>
30 */
f7f3304a 31#include "squid.h"
0ff1980a 32
33#include "text_backend.h"
34
35static hash_table *hash = NULL;
36static HASHFREE my_free;
37static char *passwdfile = NULL;
ca6965d0 38static int ha1mode = 0;
0ff1980a 39static time_t change_time = 0;
40
41typedef struct _user_data {
42 hash_link hash;
43 char *passwd;
5fcad6f9 44 char *ha1;
0ff1980a 45} user_data;
46
47static void
48my_free(void *p)
49{
54e8823b 50 user_data *u = static_cast<user_data*>(p);
0ff1980a 51 xfree(u->hash.key);
52 xfree(u->passwd);
53 xfree(u);
54}
55
56static void
d5f8d05f 57read_passwd_file(const char *passwordFile, int isHa1Mode)
0ff1980a 58{
59 FILE *f;
60 char buf[8192];
61 user_data *u;
62 char *user;
63 char *passwd;
5fcad6f9 64 char *ha1 = NULL;
65 char *realm;
0ff1980a 66
67 if (hash != NULL) {
26ac0430 68 hashFreeItems(hash, my_free);
0ff1980a 69 }
70 /* initial setup */
71 hash = hash_create((HASHCMP *) strcmp, 7921, hash_string);
72 if (NULL == hash) {
54e8823b 73 fprintf(stderr, "digest_file_auth: cannot create hash table\n");
26ac0430 74 exit(1);
0ff1980a 75 }
d5f8d05f 76 f = fopen(passwordFile, "r");
0ff1980a 77 while (fgets(buf, 8192, f) != NULL) {
26ac0430
AJ
78 if ((buf[0] == '#') || (buf[0] == ' ') || (buf[0] == '\t') ||
79 (buf[0] == '\n'))
80 continue;
81 user = strtok(buf, ":\n");
82 realm = strtok(NULL, ":\n");
83 passwd = strtok(NULL, ":\n");
84 if (!passwd) {
85 passwd = realm;
86 realm = NULL;
87 }
88 if ((strlen(user) > 0) && passwd) {
89 if (strncmp(passwd, "{HHA1}", 6) == 0) {
90 ha1 = passwd + 6;
91 passwd = NULL;
e053c141 92 } else if (isHa1Mode) {
26ac0430
AJ
93 ha1 = passwd;
94 passwd = NULL;
95 }
96 if (ha1 && strlen(ha1) != 32) {
97 /* We cannot accept plaintext passwords when using HA1 encoding,
98 * as the passwords may be output to cache.log if debugging is on.
99 */
54e8823b 100 fprintf(stderr, "digest_file_auth: ignoring invalid password for %s\n", user);
26ac0430
AJ
101 continue;
102 }
54e8823b 103 u = static_cast<user_data*>(xcalloc(1, sizeof(*u)));
26ac0430
AJ
104 if (realm) {
105 int len = strlen(user) + strlen(realm) + 2;
106 u->hash.key = malloc(len);
54e8823b 107 snprintf(static_cast<char*>(u->hash.key), len, "%s:%s", user, realm);
26ac0430
AJ
108 } else {
109 u->hash.key = xstrdup(user);
110 }
111 if (ha1)
112 u->ha1 = xstrdup(ha1);
113 else
114 u->passwd = xstrdup(passwd);
115 hash_join(hash, &u->hash);
116 }
0ff1980a 117 }
118 fclose(f);
119}
120
121/* replace when changing the backend */
122void
ca6965d0 123TextArguments(int argc, char **argv)
0ff1980a 124{
125 struct stat sb;
ca6965d0 126 if (argc == 2)
26ac0430 127 passwdfile = argv[1];
ca6965d0 128 if ((argc == 3) && !strcmp("-c", argv[1])) {
26ac0430
AJ
129 ha1mode = 1;
130 passwdfile = argv[2];
0ff1980a 131 }
132 if (!passwdfile) {
54e8823b 133 fprintf(stderr, "Usage: digest_file_auth [OPTIONS] <passwordfile>\n");
26ac0430
AJ
134 fprintf(stderr, " -c accept digest hashed passwords rather than plaintext in passwordfile\n");
135 exit(1);
0ff1980a 136 }
137 if (stat(passwdfile, &sb) != 0) {
26ac0430
AJ
138 fprintf(stderr, "cannot stat %s\n", passwdfile);
139 exit(1);
0ff1980a 140 }
141}
142
ca6965d0 143static const user_data *
144GetPassword(RequestData * requestData)
0ff1980a 145{
146 user_data *u;
147 struct stat sb;
5fcad6f9 148 char buf[256];
149 int len;
0ff1980a 150 if (stat(passwdfile, &sb) == 0) {
26ac0430
AJ
151 if (sb.st_mtime != change_time) {
152 read_passwd_file(passwdfile, ha1mode);
153 change_time = sb.st_mtime;
154 }
0ff1980a 155 }
0ff1980a 156 if (!hash)
26ac0430 157 return NULL;
5fcad6f9 158 len = snprintf(buf, sizeof(buf), "%s:%s", requestData->user, requestData->realm);
54e8823b 159 if (len >= static_cast<int>(sizeof(buf)))
26ac0430 160 return NULL;
54e8823b 161 u = (user_data*)hash_lookup(hash, buf);
5fcad6f9 162 if (u)
26ac0430 163 return u;
54e8823b 164 u = (user_data*)hash_lookup(hash, requestData->user);
5fcad6f9 165 return u;
0ff1980a 166}
167
168void
ca6965d0 169TextHHA1(RequestData * requestData)
0ff1980a 170{
ca6965d0 171 const user_data *u = GetPassword(requestData);
5fcad6f9 172 if (!u) {
26ac0430
AJ
173 requestData->error = -1;
174 return;
0ff1980a 175 }
5fcad6f9 176 if (u->ha1) {
26ac0430 177 xstrncpy(requestData->HHA1, u->ha1, sizeof(requestData->HHA1));
5fcad6f9 178 } else {
26ac0430
AJ
179 HASH HA1;
180 DigestCalcHA1("md5", requestData->user, requestData->realm, u->passwd, NULL, NULL, HA1, requestData->HHA1);
5fcad6f9 181 }
0ff1980a 182}