]>
Commit | Line | Data |
---|---|---|
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 | ||
fb381327 | 9 | /* |
10 | * usersfile.c | |
11 | * (C) 2000 Antonino Iannella, Stellar-X Pty Ltd | |
12 | * Released under GPL, see COPYING-2.0 for details. | |
26ac0430 | 13 | * |
fb381327 | 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 | ||
f7f3304a | 19 | #include "squid.h" |
bb85e424 AJ |
20 | #include "util.h" |
21 | ||
074d6a40 AJ |
22 | #include <cctype> |
23 | #include <cerrno> | |
24 | #include <cstring> | |
25 | #include <ctime> | |
fb381327 | 26 | #include <syslog.h> |
27 | #include <unistd.h> | |
28 | #include <sys/stat.h> | |
fb381327 | 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 | { | |
7c16470c AJ |
39 | const char * const *A = static_cast<const char * const *>(a); |
40 | const char * const *B = static_cast<const char * const *>(b); | |
4630fd19 | 41 | return strcasecmp(*A, *B); |
fb381327 | 42 | } |
43 | ||
44 | static void | |
45 | free_names(usersfile * uf) | |
46 | { | |
47 | int i; | |
755494da | 48 | for (i = 0; i < uf->Inuse; ++i) { |
26ac0430 AJ |
49 | if (uf->names[i]) |
50 | free(uf->names[i]); | |
51 | uf->names[i] = NULL; | |
fb381327 | 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) { | |
26ac0430 | 73 | path = uf->path; |
fb381327 | 74 | } else { |
26ac0430 AJ |
75 | if (uf->path) |
76 | free(uf->path); | |
bb85e424 | 77 | uf->path = xstrdup(path); |
fb381327 | 78 | } |
79 | ||
80 | /* Open the users file. Report any errors. */ | |
81 | fp = fopen(path, "r"); | |
82 | if (NULL == fp) { | |
26ac0430 AJ |
83 | uf->LMT = 0; |
84 | if (errno == ENOENT) | |
85 | return 0; | |
86 | syslog(LOG_ERR, "%s: %s", path, strerror(errno)); | |
87 | return 1; | |
fb381327 | 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) { | |
26ac0430 | 92 | syslog(LOG_ERR, "%s: %s", path, strerror(errno)); |
470144f5 | 93 | fclose(fp); |
26ac0430 | 94 | return 1; |
fb381327 | 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 */ | |
470144f5 AJ |
100 | if (FileBuf.st_size == 0) { |
101 | fclose(fp); | |
26ac0430 | 102 | return 0; |
470144f5 | 103 | } |
fb381327 | 104 | |
105 | /* | |
106 | * Read the file into memory | |
107 | * XXX assumes one username per input line | |
108 | */ | |
109 | while (fgets(buf, 1024, fp) != NULL) { | |
26ac0430 AJ |
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; | |
7c16470c | 118 | uf->names = static_cast<char**>(calloc(uf->Alloc, sizeof(*uf->names))); |
26ac0430 AJ |
119 | } else if (uf->Inuse == uf->Alloc) { |
120 | uf->Alloc = uf->Alloc << 1; | |
7c16470c | 121 | uf->names = static_cast<char**>(realloc(uf->names, uf->Alloc * sizeof(*uf->names))); |
26ac0430 AJ |
122 | /* zero out the newly allocated memory */ |
123 | memset(&uf->names[uf->Alloc >> 1], | |
124 | '\0', | |
125 | (uf->Alloc >> 1) * sizeof(*uf->names)); | |
126 | } | |
bb85e424 | 127 | uf->names[uf->Inuse] = xstrdup(buf); |
755494da | 128 | ++uf->Inuse; |
fb381327 | 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') | |
26ac0430 | 151 | return 1; |
fb381327 | 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) | |
26ac0430 | 156 | return 1; |
fb381327 | 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 | ||
4630fd19 | 162 | p = bsearch(&User, |
26ac0430 AJ |
163 | uf->names, |
164 | uf->Inuse, | |
165 | sizeof(*uf->names), | |
166 | name_cmp); | |
fb381327 | 167 | if (NULL == p) { |
26ac0430 | 168 | return 0; |
fb381327 | 169 | } |
fb381327 | 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 | ||
a7d5f733 | 184 | if (uf->path == NULL) |
26ac0430 | 185 | return; |
a7d5f733 | 186 | |
fb381327 | 187 | if (stat(uf->path, &ChkBuf) < 0) { |
26ac0430 AJ |
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; | |
fb381327 | 195 | } |
196 | /* return if no change */ | |
197 | if (ChkBuf.st_mtime == uf->LMT) | |
26ac0430 | 198 | return; |
fb381327 | 199 | |
200 | /* | |
201 | * The file changed, so re-read it. | |
202 | */ | |
a7d5f733 | 203 | syslog(LOG_INFO, "Check_forfilechange: Reloading user list '%s'.", uf->path); |
fb381327 | 204 | Read_usersfile(NULL, uf); |
205 | } |