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