]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/basic_auth/MSNT/usersfile.cc
SourceFormat Enforcement
[thirdparty/squid.git] / helpers / basic_auth / MSNT / usersfile.cc
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
9 /*
10 * usersfile.c
11 * (C) 2000 Antonino Iannella, Stellar-X Pty Ltd
12 * Released under GPL, see COPYING-2.0 for details.
13 *
14 * These routines are to allow users attempting to use the proxy which
15 * have been explicitly allowed by the system administrator.
16 * The code originated from denyusers.c.
17 */
18
19 #include "squid.h"
20 #include "util.h"
21
22 #include <cctype>
23 #include <cerrno>
24 #include <cstring>
25 #include <ctime>
26 #include <syslog.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29 #include <sys/param.h>
30 #include <fcntl.h>
31
32 #include "usersfile.h"
33
34 #define NAMELEN 50 /* Maximum username length */
35
36 static int
37 name_cmp(const void *a, const void *b)
38 {
39 const char * const *A = static_cast<const char * const *>(a);
40 const char * const *B = static_cast<const char * const *>(b);
41 return strcasecmp(*A, *B);
42 }
43
44 static void
45 free_names(usersfile * uf)
46 {
47 int i;
48 for (i = 0; i < uf->Inuse; ++i) {
49 if (uf->names[i])
50 free(uf->names[i]);
51 uf->names[i] = NULL;
52 }
53 uf->Inuse = 0;
54 }
55
56 /*
57 * Reads a file of usernames and stuffs them into an array
58 * of strings.
59 * Returns 0 if the user list was successfully loaded,
60 * and 1 in case of error.
61 */
62
63 int
64 Read_usersfile(const char *path, usersfile * uf)
65 {
66 FILE *fp;
67 struct stat FileBuf;
68 char buf[1024];
69
70 free_names(uf);
71
72 if (NULL == path) {
73 path = uf->path;
74 } else {
75 if (uf->path)
76 free(uf->path);
77 uf->path = xstrdup(path);
78 }
79
80 /* Open the users file. Report any errors. */
81 fp = fopen(path, "r");
82 if (NULL == fp) {
83 uf->LMT = 0;
84 if (errno == ENOENT)
85 return 0;
86 syslog(LOG_ERR, "%s: %s", path, strerror(errno));
87 return 1;
88 }
89 /* Stat the file. If it does not exist, save the size as zero.
90 * Clear the allowed user string. Return. */
91 if (fstat(fileno(fp), &FileBuf) < 0) {
92 syslog(LOG_ERR, "%s: %s", path, strerror(errno));
93 fclose(fp);
94 return 1;
95 }
96 /* If it exists, save the modification time and size */
97 uf->LMT = FileBuf.st_mtime;
98
99 /* Handle the special case of a zero length file */
100 if (FileBuf.st_size == 0) {
101 fclose(fp);
102 return 0;
103 }
104
105 /*
106 * Read the file into memory
107 * XXX assumes one username per input line
108 */
109 while (fgets(buf, 1024, fp) != NULL) {
110 /* ensure no names longer than our limit */
111 buf[NAMELEN] = '\0';
112 /* skip bad input lines */
113 if (NULL == strtok(buf, "\r\n"))
114 continue;
115 /* grow the list if necessary */
116 if (0 == uf->Alloc) {
117 uf->Alloc = 256;
118 uf->names = static_cast<char**>(calloc(uf->Alloc, sizeof(*uf->names)));
119 } else if (uf->Inuse == uf->Alloc) {
120 uf->Alloc = uf->Alloc << 1;
121 uf->names = static_cast<char**>(realloc(uf->names, uf->Alloc * sizeof(*uf->names)));
122 /* zero out the newly allocated memory */
123 memset(&uf->names[uf->Alloc >> 1],
124 '\0',
125 (uf->Alloc >> 1) * sizeof(*uf->names));
126 }
127 uf->names[uf->Inuse] = xstrdup(buf);
128 ++uf->Inuse;
129 }
130 fclose(fp);
131 fp = NULL;
132
133 /* sort the names for searching */
134 qsort(uf->names, uf->Inuse, sizeof(*uf->names), name_cmp);
135
136 return 0;
137 }
138
139 /*
140 * Check to see if the username provided by Squid appears in the
141 * user list. Returns 0 if the user was not found, and 1 if they were.
142 */
143
144 int
145 Check_userlist(usersfile * uf, char *User)
146 {
147 void *p;
148
149 /* Empty users are always in the list */
150 if (User[0] == '\0')
151 return 1;
152
153 /* If allowed user list is empty, allow all users.
154 * If no users are supposed to be using the proxy, stop squid instead. */
155 if (0 == uf->Inuse)
156 return 1;
157
158 /* Check if username string is found in the allowed user list.
159 * If so, allow. If not, deny. Reconstruct the username
160 * to have whitespace, to avoid finding wrong string subsets. */
161
162 p = bsearch(&User,
163 uf->names,
164 uf->Inuse,
165 sizeof(*uf->names),
166 name_cmp);
167 if (NULL == p) {
168 return 0;
169 }
170 return 1;
171 }
172
173 /*
174 * Checks if there has been a change in a users file.
175 * If the modification time has changed, then reload the user list.
176 */
177 void
178 Check_forfilechange(usersfile * uf)
179 {
180 struct stat ChkBuf; /* Stat data buffer */
181
182 /* Stat the allowed users file. If it cannot be accessed, return. */
183
184 if (uf->path == NULL)
185 return;
186
187 if (stat(uf->path, &ChkBuf) < 0) {
188 if (errno == ENOENT) {
189 uf->LMT = 0;
190 free_names(uf);
191 } else { /* Report error when accessing file */
192 syslog(LOG_ERR, "%s: %s", uf->path, strerror(errno));
193 }
194 return;
195 }
196 /* return if no change */
197 if (ChkBuf.st_mtime == uf->LMT)
198 return;
199
200 /*
201 * The file changed, so re-read it.
202 */
203 syslog(LOG_INFO, "Check_forfilechange: Reloading user list '%s'.", uf->path);
204 Read_usersfile(NULL, uf);
205 }
206