]> git.ipfire.org Git - thirdparty/squid.git/blame - helpers/digest_auth/password/text_backend.c
Summary: Merge in digest helper refactoring.
[thirdparty/squid.git] / helpers / digest_auth / password / text_backend.c
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;
13 * - file format is username:password
14 *
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 */
31
32#include "text_backend.h"
33
34static hash_table *hash = NULL;
35static HASHFREE my_free;
36static char *passwdfile = NULL;
37static int ha1mode=0;
38static time_t change_time = 0;
39
40typedef struct _user_data {
41 hash_link hash;
42 char *passwd;
43} user_data;
44
45static void
46my_free(void *p)
47{
48 user_data *u = p;
49 xfree(u->hash.key);
50 xfree(u->passwd);
51 xfree(u);
52}
53
54static void
55read_passwd_file(const char *passwdfile, int ha1mode)
56{
57 FILE *f;
58 char buf[8192];
59 user_data *u;
60 char *user;
61 char *passwd;
62 int passwdha1;
63
64 if (hash != NULL) {
65 hashFreeItems(hash, my_free);
66 }
67 /* initial setup */
68 hash = hash_create((HASHCMP *) strcmp, 7921, hash_string);
69 if (NULL == hash) {
70 fprintf(stderr, "digest_pw_auth: cannot create hash table\n");
71 exit(1);
72 }
73 f = fopen(passwdfile, "r");
74 while (fgets(buf, 8192, f) != NULL) {
75 if ((buf[0] == '#') || (buf[0] == ' ') || (buf[0] == '\t') ||
76 (buf[0] == '\n'))
77 continue;
78 user = strtok(buf, ":\n");
79 passwd = strtok(NULL, ":\n");
80 if ((strlen(user) > 0) && passwd) {
81 passwdha1 = (strncmp("{HHA1}", passwd, 6))?0:1;
82 if (!ha1mode || passwdha1) {
83 u = xmalloc(sizeof(*u));
84 u->hash.key = xstrdup(user);
85 u->passwd = xstrdup(passwd);
86 hash_join(hash, &u->hash);
87 } else {
88 /* We cannot accept plaintext passwords when using HA1 encoding,
89 * as the passwords may be output to cache.log if debugging is on.
90 */
91 fprintf(stderr, "digest_pw_auth: ignoring %s password for %s\n",
92 "plaintext", user);
93 }
94 }
95 }
96 fclose(f);
97}
98
99/* replace when changing the backend */
100void
101TextArguments (int argc, char **argv)
102{
103 struct stat sb;
104 if(argc == 2)
105 passwdfile = argv[1];
106 if((argc == 3) && !strcmp("-c", argv[1])){
107 ha1mode=1;
108 passwdfile = argv[2];
109 }
110 if (!passwdfile) {
111 fprintf(stderr, "Usage: digest_pw_auth [OPTIONS] <passwordfile>\n");
112 fprintf(stderr, " -c accept HHA1 passwords rather than plaintext in passwordfile\n");
113 exit(1);
114 }
115 if (stat(passwdfile, &sb) != 0) {
116 fprintf(stderr, "cannot stat %s\n", passwdfile);
117 exit(1);
118 }
119}
120
121static void
122GetPassword (RequestData *requestData)
123{
124 user_data *u;
125 struct stat sb;
126 if (stat(passwdfile, &sb) == 0) {
127 if (sb.st_mtime != change_time) {
128 read_passwd_file(passwdfile, ha1mode);
129 change_time = sb.st_mtime;
130 }
131 }
132 requestData->password = NULL;
133 if (!hash)
134 return;
135 u = (user_data *)hash_lookup(hash, requestData->user);
136 if (u != NULL)
137 requestData->password = u->passwd;
138}
139
140void
141TextHHA1(RequestData *requestData)
142{
143 GetPassword (requestData);
144 if (requestData->password == NULL) {
145 requestData->error = -1;
146 return;
147 }
148 if(!ha1mode) {
149 HASH HA1;
150 DigestCalcHA1("md5", requestData->user, requestData->realm, requestData->password, NULL, NULL, HA1, requestData->HHA1);
151
152 /* fprintf(stderr, "digest_pw_auth: %s:{HHA1}%s\n", requestData.user, HHA1); */
153 } else
154 xstrncpy (requestData->HHA1, &requestData->password[6], sizeof (requestData->HHA1));
155}