]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/basic_auth/NCSA/basic_ncsa_auth.cc
merge from parent SslServerCertValidator r12337
[thirdparty/squid.git] / helpers / basic_auth / NCSA / basic_ncsa_auth.cc
1 /*
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 *
16 * MD5 without salt and magic strings - Added by Ramon de Carvalho and Rodrigo Rubira Branco
17 */
18
19 #include "squid.h"
20 #include "crypt_md5.h"
21 #include "hash.h"
22 #include "helpers/defines.h"
23 #include "rfc1738.h"
24 #include "util.h"
25
26 #if HAVE_STDIO_H
27 #include <stdio.h>
28 #endif
29 #if HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #if HAVE_STRING_H
33 #include <string.h>
34 #endif
35 #if HAVE_SYS_STAT_H
36 #include <sys/stat.h>
37 #endif
38 #if HAVE_CRYPT_H
39 #include <crypt.h>
40 #endif
41 #if HAVE_ERRNO_H
42 #include <errno.h>
43 #endif
44
45 static hash_table *hash = NULL;
46 static HASHFREE my_free;
47
48 typedef struct _user_data {
49 /* first two items must be same as hash_link */
50 char *user;
51 struct _user_data *next;
52 char *passwd;
53 } user_data;
54
55 static void
56 my_free(void *p)
57 {
58 user_data *u = static_cast<user_data*>(p);
59 xfree(u->user);
60 xfree(u->passwd);
61 xfree(u);
62 }
63
64 static void
65 read_passwd_file(const char *passwdfile)
66 {
67 FILE *f;
68 char buf[HELPER_INPUT_BUFFER];
69 user_data *u;
70 char *user;
71 char *passwd;
72 if (hash != NULL) {
73 hashFreeItems(hash, my_free);
74 hashFreeMemory(hash);
75 }
76 /* initial setup */
77 hash = hash_create((HASHCMP *) strcmp, 7921, hash_string);
78 if (NULL == hash) {
79 fprintf(stderr, "FATAL: Cannot create hash table\n");
80 exit(1);
81 }
82 f = fopen(passwdfile, "r");
83 if (NULL == f) {
84 fprintf(stderr, "FATAL: %s: %s\n", passwdfile, xstrerror());
85 exit(1);
86 }
87 unsigned int lineCount = 0;
88 buf[HELPER_INPUT_BUFFER-1] = '\0';
89 while (fgets(buf, sizeof(buf)-1, f) != NULL) {
90 ++lineCount;
91 if ((buf[0] == '#') || (buf[0] == ' ') || (buf[0] == '\t') ||
92 (buf[0] == '\n'))
93 continue;
94 user = strtok(buf, ":\n\r");
95 if (user == NULL) {
96 fprintf(stderr, "ERROR: Missing user name at %s line %d\n", passwdfile, lineCount);
97 continue;
98 }
99 passwd = strtok(NULL, ":\n\r");
100 if ((strlen(user) > 0) && passwd) {
101 u = static_cast<user_data*>(xmalloc(sizeof(*u)));
102 u->user = xstrdup(user);
103 u->passwd = xstrdup(passwd);
104 hash_join(hash, (hash_link *) u);
105 }
106 }
107 fclose(f);
108 }
109
110 int
111 main(int argc, char **argv)
112 {
113 struct stat sb;
114 time_t change_time = -1;
115 char buf[HELPER_INPUT_BUFFER];
116 char *user, *passwd, *p;
117 user_data *u;
118 setbuf(stdout, NULL);
119 if (argc != 2) {
120 fprintf(stderr, "Usage: ncsa_auth <passwordfile>\n");
121 exit(1);
122 }
123 if (stat(argv[1], &sb) != 0) {
124 fprintf(stderr, "FATAL: cannot stat %s\n", argv[1]);
125 exit(1);
126 }
127 while (fgets(buf, HELPER_INPUT_BUFFER, stdin) != NULL) {
128 if ((p = strchr(buf, '\n')) != NULL)
129 *p = '\0'; /* strip \n */
130 if (stat(argv[1], &sb) == 0) {
131 if (sb.st_mtime != change_time) {
132 read_passwd_file(argv[1]);
133 change_time = sb.st_mtime;
134 }
135 }
136 if ((user = strtok(buf, " ")) == NULL) {
137 SEND_ERR("");
138 continue;
139 }
140 if ((passwd = strtok(NULL, "")) == NULL) {
141 SEND_ERR("");
142 continue;
143 }
144 rfc1738_unescape(user);
145 rfc1738_unescape(passwd);
146 u = (user_data *) hash_lookup(hash, user);
147 if (u == NULL) {
148 SEND_ERR("No such user");
149 #if HAVE_CRYPT
150 } else if (strlen(passwd) <= 8 && strcmp(u->passwd, (char *) crypt(passwd, u->passwd)) == 0) {
151 // Bug 3107: crypt() DES functionality silently truncates long passwords.
152 SEND_OK("");
153 } else if (strlen(passwd) > 8 && strcmp(u->passwd, (char *) crypt(passwd, u->passwd)) == 0) {
154 // Bug 3107: crypt() DES functionality silently truncates long passwords.
155 SEND_ERR("Password too long. Only 8 characters accepted.");
156 #endif
157 } else if (strcmp(u->passwd, (char *) crypt_md5(passwd, u->passwd)) == 0) {
158 SEND_OK("");
159 } else if (strcmp(u->passwd, (char *) md5sum(passwd)) == 0) {
160 SEND_OK("");
161 } else {
162 SEND_ERR("Wrong password");
163 }
164 }
165 if (hash != NULL) {
166 hashFreeItems(hash, my_free);
167 hashFreeMemory(hash);
168 }
169 exit(0);
170 }