]> git.ipfire.org Git - thirdparty/squid.git/blame - helpers/basic_auth/NCSA/basic_ncsa_auth.cc
Boilerplate: update copyright blurbs for Basic authentication helpers
[thirdparty/squid.git] / helpers / basic_auth / NCSA / basic_ncsa_auth.cc
CommitLineData
5b95b903
AJ
1/*
2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
94439e4e 9/*
94439e4e 10 * AUTHOR: Arjan de Vet <Arjan.deVet@adv.iae.nl>
11 *
12 * Example authentication program for Squid, based on the original
13 * proxy_auth code from client_side.c, written by
14 * Jon Thackray <jrmt@uk.gdscorp.com>.
15 *
16 * Uses a NCSA httpd style password file for authentication with the
17 * following improvements suggested by various people:
18 *
19 * - comment lines are possible and should start with a '#';
20 * - empty or blank lines are possible;
21 * - extra fields in the password file are ignored; this makes it
22 * possible to use a Unix password file but I do not recommend that.
23 *
304fb0a1 24 * MD5 without salt and magic strings - Added by Ramon de Carvalho and Rodrigo Rubira Branco
94439e4e 25 */
26
f7f3304a 27#include "squid.h"
43fed740
AJ
28#include "crypt_md5.h"
29#include "hash.h"
30#include "helpers/defines.h"
1fa9b1a7 31#include "rfc1738.h"
43fed740 32#include "util.h"
81951d76 33
074d6a40
AJ
34#include <cerrno>
35#include <cstring>
94439e4e 36#if HAVE_UNISTD_H
37#include <unistd.h>
38#endif
94439e4e 39#if HAVE_SYS_STAT_H
40#include <sys/stat.h>
41#endif
42#if HAVE_CRYPT_H
43#include <crypt.h>
44#endif
45
94439e4e 46static hash_table *hash = NULL;
47static HASHFREE my_free;
48
49typedef struct _user_data {
50 /* first two items must be same as hash_link */
51 char *user;
52 struct _user_data *next;
53 char *passwd;
54} user_data;
55
56static void
57my_free(void *p)
58{
3138a4e4 59 user_data *u = static_cast<user_data*>(p);
94439e4e 60 xfree(u->user);
61 xfree(u->passwd);
62 xfree(u);
63}
64
65static void
66read_passwd_file(const char *passwdfile)
67{
68 FILE *f;
3c18a677 69 char buf[HELPER_INPUT_BUFFER];
94439e4e 70 user_data *u;
71 char *user;
72 char *passwd;
73 if (hash != NULL) {
26ac0430
AJ
74 hashFreeItems(hash, my_free);
75 hashFreeMemory(hash);
94439e4e 76 }
77 /* initial setup */
78 hash = hash_create((HASHCMP *) strcmp, 7921, hash_string);
79 if (NULL == hash) {
43fed740 80 fprintf(stderr, "FATAL: Cannot create hash table\n");
26ac0430 81 exit(1);
94439e4e 82 }
83 f = fopen(passwdfile, "r");
a2897c13 84 if (NULL == f) {
43fed740 85 fprintf(stderr, "FATAL: %s: %s\n", passwdfile, xstrerror());
26ac0430 86 exit(1);
a2897c13 87 }
3c18a677 88 unsigned int lineCount = 0;
2ea57237 89 buf[HELPER_INPUT_BUFFER-1] = '\0';
3c18a677
AJ
90 while (fgets(buf, sizeof(buf)-1, f) != NULL) {
91 ++lineCount;
26ac0430
AJ
92 if ((buf[0] == '#') || (buf[0] == ' ') || (buf[0] == '\t') ||
93 (buf[0] == '\n'))
94 continue;
95 user = strtok(buf, ":\n\r");
3c18a677
AJ
96 if (user == NULL) {
97 fprintf(stderr, "ERROR: Missing user name at %s line %d\n", passwdfile, lineCount);
98 continue;
99 }
26ac0430
AJ
100 passwd = strtok(NULL, ":\n\r");
101 if ((strlen(user) > 0) && passwd) {
3138a4e4 102 u = static_cast<user_data*>(xmalloc(sizeof(*u)));
26ac0430
AJ
103 u->user = xstrdup(user);
104 u->passwd = xstrdup(passwd);
105 hash_join(hash, (hash_link *) u);
106 }
94439e4e 107 }
108 fclose(f);
109}
110
111int
112main(int argc, char **argv)
113{
114 struct stat sb;
407e1c93 115 time_t change_time = -1;
43fed740 116 char buf[HELPER_INPUT_BUFFER];
94439e4e 117 char *user, *passwd, *p;
118 user_data *u;
119 setbuf(stdout, NULL);
120 if (argc != 2) {
26ac0430
AJ
121 fprintf(stderr, "Usage: ncsa_auth <passwordfile>\n");
122 exit(1);
94439e4e 123 }
124 if (stat(argv[1], &sb) != 0) {
43fed740 125 fprintf(stderr, "FATAL: cannot stat %s\n", argv[1]);
26ac0430 126 exit(1);
94439e4e 127 }
43fed740 128 while (fgets(buf, HELPER_INPUT_BUFFER, stdin) != NULL) {
26ac0430
AJ
129 if ((p = strchr(buf, '\n')) != NULL)
130 *p = '\0'; /* strip \n */
131 if (stat(argv[1], &sb) == 0) {
132 if (sb.st_mtime != change_time) {
133 read_passwd_file(argv[1]);
134 change_time = sb.st_mtime;
135 }
136 }
137 if ((user = strtok(buf, " ")) == NULL) {
43fed740 138 SEND_ERR("");
26ac0430
AJ
139 continue;
140 }
141 if ((passwd = strtok(NULL, "")) == NULL) {
43fed740 142 SEND_ERR("");
26ac0430
AJ
143 continue;
144 }
145 rfc1738_unescape(user);
146 rfc1738_unescape(passwd);
147 u = (user_data *) hash_lookup(hash, user);
148 if (u == NULL) {
43fed740 149 SEND_ERR("No such user");
2df24144
AJ
150 continue;
151 }
152 char *crypted = NULL;
8655ee19 153#if HAVE_CRYPT
f04d5d43 154 size_t passwordLength = strlen(passwd);
2df24144
AJ
155 // Bug 3831: given algorithms more secure than DES crypt() does not truncate, so we can ignore the bug 3107 length checks below
156 // '$1$' = MD5, '$2a$' = Blowfish, '$5$' = SHA256 (Linux), '$6$' = SHA256 (BSD) and SHA512
157 if (passwordLength > 1 && u->passwd[0] == '$' &&
b402a8ce 158 (crypted = crypt(passwd, u->passwd)) && strcmp(u->passwd, crypted) == 0) {
2df24144
AJ
159 SEND_OK("");
160 continue;
161 }
162 // 'other' prefixes indicate DES algorithm.
163 if (passwordLength <= 8 && (crypted = crypt(passwd, u->passwd)) && (strcmp(u->passwd, crypted) == 0)) {
43fed740 164 SEND_OK("");
2df24144
AJ
165 continue;
166 }
167 if (passwordLength > 8 && (crypted = crypt(passwd, u->passwd)) && (strcmp(u->passwd, crypted) == 0)) {
2d2772b0
AJ
168 // Bug 3107: crypt() DES functionality silently truncates long passwords.
169 SEND_ERR("Password too long. Only 8 characters accepted.");
2df24144
AJ
170 continue;
171 }
172
8655ee19 173#endif
2df24144 174 if ( (crypted = crypt_md5(passwd, u->passwd)) && strcmp(u->passwd, crypted) == 0) {
43fed740 175 SEND_OK("");
2df24144
AJ
176 continue;
177 }
178 if ( (crypted = md5sum(passwd)) && strcmp(u->passwd, crypted) == 0) {
43fed740 179 SEND_OK("");
2df24144 180 continue;
26ac0430 181 }
2df24144 182 SEND_ERR("Wrong password");
94439e4e 183 }
5fb27788 184 if (hash != NULL) {
26ac0430
AJ
185 hashFreeItems(hash, my_free);
186 hashFreeMemory(hash);
5fb27788 187 }
94439e4e 188 exit(0);
189}