Squid Web Cache master
Loading...
Searching...
No Matches
ext_file_userip_acl.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 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 * Copyright (C) 2002 Rodrigo Campos
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 * Author: Rodrigo Campos (rodrigo@geekbunker.org)
27 *
28 */
29#include "squid.h"
31#include "rfc1738.h"
32#include "util.h"
33
34#include <cstdlib>
35#include <cstring>
36#if HAVE_SYS_SOCKET_H
37#include <sys/socket.h>
38#endif
39#if HAVE_NETINET_IN_H
40#include <netinet/in.h>
41#endif
42#if HAVE_ARPA_INET_H
43#include <arpa/inet.h>
44#endif
45#if HAVE_GRP_H
46#include <grp.h>
47#endif
48
50 unsigned long address; // IP address (assumes IPv4)
51 unsigned long netmask; // IP netmask
52 char *username;
54};
55
56int match_user(char *, char *);
57int match_group(char *, char *);
58struct ip_user_dict *load_dict(FILE *);
59int dict_lookup(struct ip_user_dict *, char *, char *);
60
62#define DICT_BUFFER_SIZE 8196
63
64static void
66 while (head) {
67 struct ip_user_dict *next = head->next_entry;
68 safe_free(head->username);
69 xfree(head);
70 head = next;
71 }
72}
73
81struct ip_user_dict *
82load_dict(FILE * FH) {
83 struct ip_user_dict *current_entry; /* the structure used to
84 store data */
85 struct ip_user_dict *first_entry = nullptr; /* the head of the
86 linked list */
87 char line[DICT_BUFFER_SIZE]; /* the buffer for the lines read
88 from the dict file */
89 char *tmpbuf; /* for the address before the
90 bitwise AND */
91
92 /* the pointer to the first entry in the linked list */
93 first_entry = static_cast<struct ip_user_dict*>(xcalloc(1, sizeof(struct ip_user_dict)));
94 current_entry = first_entry;
95
96 unsigned int lineCount = 0;
97 while (fgets(line, sizeof(line), FH) != nullptr) {
98 ++lineCount;
99 if (line[0] == '#') {
100 continue;
101 }
102
103 char *cp; // a char pointer used to parse each line.
104 if ((cp = strchr (line, '\n')) != nullptr) {
105 /* chop \n characters */
106 *cp = '\0';
107 }
108 if (strtok(line, "\t ") != nullptr) {
109 // NP: line begins with IP/mask. Skipped to the end of it with this strtok()
110
111 /* get the username */
112 char *username;
113 if ((username = strtok(nullptr, "\t ")) == nullptr) {
114 debug("Missing username on line %u of dictionary file\n", lineCount);
115 continue;
116 }
117
118 /* look for a netmask */
119 if ((cp = strtok (line, "/")) != nullptr) {
120 /* store the ip address in a temporary buffer */
121 tmpbuf = cp;
122 cp = strtok (nullptr, "/");
123 if (cp != nullptr) {
124 /* if we have a slash in the lhs, we have a netmask */
125 current_entry->netmask = (inet_addr(cp));
126 current_entry->address =
127 (((inet_addr (tmpbuf))) & current_entry->netmask);
128 } else {
129 /* when there's no slash, we figure the netmask is /32 */
130 current_entry->address = (inet_addr(tmpbuf));
131 current_entry->netmask = (inet_addr("255.255.255.255"));
132 }
133 }
134 /* get space for the username */
135 current_entry->username =
136 (char*)calloc(strlen(username) + 1, sizeof(char));
137 strcpy(current_entry->username, username);
138
139 /* get space and point current_entry to the new entry */
140 current_entry->next_entry =
141 static_cast<struct ip_user_dict*>(xcalloc(1, sizeof(struct ip_user_dict)));
142 current_entry = current_entry->next_entry;
143 }
144
145 }
146
147 /* Return a pointer to the first entry linked list */
148 return first_entry;
149}
150
155int
156dict_lookup(struct ip_user_dict *first_entry, char *username,
157 char *address)
158{
159 /* Move the pointer to the first entry of the linked list. */
160 struct ip_user_dict *current_entry = first_entry;
161
162 while (current_entry && current_entry->username) {
163 debug("user: %s\naddr: %lu\nmask: %lu\n\n",
164 current_entry->username, current_entry->address,
165 current_entry->netmask);
166
167 if ((inet_addr (address) & (unsigned long) current_entry->
168 netmask) == current_entry->address) {
169 /* If the username contains an @ we assume it?s a group and
170 call the corresponding function */
171 if ((strchr (current_entry->username, '@')) == nullptr) {
172 if ((match_user (current_entry->username, username)) == 1)
173 return 1;
174 } else {
175 if ((match_group (current_entry->username, username)) == 1)
176 return 1;
177 }
178 }
179 current_entry = current_entry->next_entry;
180 }
181
182 /* If no match was found we return 0 */
183 return 0;
184}
185
186int
187match_user(char *dict_username, char *username)
188{
189 if ((strcmp(dict_username, username)) == 0) {
190 return 1;
191 } else {
192 if ((strcmp(dict_username, "ALL")) == 0) {
193 return 1;
194 }
195 }
196 return 0;
197} /* match_user */
198
199int
200match_group(char *dict_group, char *username)
201{
202 struct group *g; /* a struct to hold group entries */
203 ++dict_group; /* the @ should be the first char
204 so we rip it off by incrementing
205 * the pointer by one */
206
207 g = getgrnam(dict_group);
208 if (!g || !g->gr_mem) {
209 debug("Group does not exist or has no members '%s'\n", dict_group);
210 return 0;
211 }
212
213 for (char * const *m = g->gr_mem; *m; ++m) {
214 if (strcmp(*m, username) == 0)
215 return 1;
216 }
217 return 0;
218}
219
220static void
221usage(const char *program_name)
222{
223 fprintf (stderr, "Usage:\n%s [-d] -f <configuration file>\n",
225}
226
227int
228main (int argc, char *argv[])
229{
230 char *filename = nullptr;
231 char *program_name = argv[0];
232 char *cp;
233 char *username, *address;
234 char line[HELPER_INPUT_BUFFER];
235 struct ip_user_dict *current_entry;
236 int ch;
237
238 setvbuf (stdout, nullptr, _IOLBF, 0);
239 while ((ch = getopt(argc, argv, "df:h")) != -1) {
240 switch (ch) {
241 case 'f':
242 filename = optarg;
243 break;
244 case 'd':
245 debug_enabled = 1;
246 break;
247 case 'h':
249 exit(EXIT_SUCCESS);
250 default:
251 fprintf(stderr, "%s: FATAL: Unknown parameter option '%c'", program_name, ch);
253 exit(EXIT_FAILURE);
254 }
255 }
256 if (filename == nullptr) {
257 fprintf(stderr, "%s: FATAL: No Filename configured.", program_name);
259 exit(EXIT_FAILURE);
260 }
261 FILE *FH = fopen(filename, "r");
262 if (!FH) {
263 int xerrno = errno;
264 fprintf(stderr, "%s: FATAL: Unable to open file '%s': %s", program_name, filename, xstrerr(xerrno));
265 exit(EXIT_FAILURE);
266 }
267 current_entry = load_dict(FH);
268
269 while (fgets(line, HELPER_INPUT_BUFFER, stdin)) {
270 if ((cp = strchr (line, '\n')) == nullptr) {
271 /* too large message received.. skip and deny */
272 fprintf(stderr, "%s: ERROR: Input Too Large: %s\n", program_name, line);
273 while (fgets(line, sizeof(line), stdin)) {
274 fprintf(stderr, "%s: ERROR: Input Too Large..: %s\n", program_name, line);
275 if (strchr(line, '\n') != nullptr)
276 break;
277 }
278 SEND_BH(HLP_MSG("Input Too Large."));
279 continue;
280 }
281 *cp = '\0';
282 address = strtok(line, " \t");
283 username = strtok(nullptr, " \t");
284 if (!address || !username) {
285 debug("%s: unable to read tokens\n", program_name);
286 SEND_BH(HLP_MSG("Invalid Input."));
287 continue;
288 }
291 int result = dict_lookup(current_entry, username, address);
292 debug("%s: result: %d\n", program_name, result);
293 if (result != 0) {
294 SEND_OK("");
295 } else {
296 SEND_ERR("");
297 }
298 }
299
300 fclose (FH);
301 free_dict(current_entry);
302 return EXIT_SUCCESS;
303}
304
squidaio_request_t * head
Definition aiops.cc:129
#define HELPER_INPUT_BUFFER
int debug_enabled
Definition debug.cc:13
void debug(const char *format,...)
Definition debug.cc:19
char * program_name
struct ip_user_dict * load_dict(FILE *)
int match_user(char *, char *)
int match_group(char *, char *)
int dict_lookup(struct ip_user_dict *, char *, char *)
static void free_dict(struct ip_user_dict *head)
#define DICT_BUFFER_SIZE
static void usage(void)
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition getopt.c:62
char * optarg
Definition getopt.c:51
int main()
#define xfree
#define SEND_ERR(x)
#define SEND_OK(x)
#define HLP_MSG(text)
#define SEND_BH(x)
void rfc1738_unescape(char *url)
Definition rfc1738.c:146
unsigned long address
struct ip_user_dict * next_entry
unsigned long netmask
void * xcalloc(size_t n, size_t sz)
Definition xalloc.cc:71
#define safe_free(x)
Definition xalloc.h:73
const char * xstrerr(int error)
Definition xstrerror.cc:83