]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/external_acl/file_userip/ext_file_userip_acl.cc
SourceFormat Enforcement
[thirdparty/squid.git] / helpers / external_acl / file_userip / ext_file_userip_acl.cc
1 /* $Id$
2 * Copyright (C) 2002 Rodrigo Campos
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 * Author: Rodrigo Campos (rodrigo@geekbunker.org)
19 *
20 */
21 #include "squid.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_STDLIB_H
30 #include <stdlib.h>
31 #endif
32 #if HAVE_STRING_H
33 #include <string.h>
34 #endif
35 #if HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
37 #endif
38 #if HAVE_NETINET_IN_H
39 #include <netinet/in.h>
40 #endif
41 #if HAVE_ARPA_INET_H
42 #include <arpa/inet.h>
43 #endif
44 #if HAVE_GRP_H
45 #include <grp.h>
46 #endif
47
48 struct ip_user_dict {
49 unsigned long address; // IP address (assumes IPv4)
50 unsigned long netmask; // IP netmask
51 char *username;
52 struct ip_user_dict *next_entry;
53 };
54
55 int match_user(char *, char *);
56 int match_group(char *, char *);
57 struct ip_user_dict *load_dict(FILE *);
58 int dict_lookup(struct ip_user_dict *, char *, char *);
59
60 /** Size of lines read from the dictionary file */
61 #define DICT_BUFFER_SIZE 8196
62
63 /** This function parses the dictionary file and loads it
64 * in memory. All IP addresses are processed with a bitwise AND
65 * with their netmasks before they are stored.
66 * If there?s no netmask (no /) in the in the lhs , a mask
67 * 255.255.255.255 is assumed.
68 * It returns a pointer to the first entry of the linked list
69 */
70 struct ip_user_dict *
71 load_dict(FILE * FH) {
72 struct ip_user_dict *current_entry; /* the structure used to
73 store data */
74 struct ip_user_dict *first_entry = NULL; /* the head of the
75 linked list */
76 char line[DICT_BUFFER_SIZE]; /* the buffer for the lines read
77 from the dict file */
78 char *cp; /* a char pointer used to parse
79 each line */
80 char *username; /* for the username */
81 char *tmpbuf; /* for the address before the
82 bitwise AND */
83
84 /* the pointer to the first entry in the linked list */
85 first_entry = (struct ip_user_dict*)malloc(sizeof(struct ip_user_dict));
86 current_entry = first_entry;
87
88 while ((cp = fgets (line, DICT_BUFFER_SIZE, FH)) != NULL) {
89 if (line[0] == '#') {
90 continue;
91 }
92 if ((cp = strchr (line, '\n')) != NULL) {
93 /* chop \n characters */
94 *cp = '\0';
95 }
96 if ((cp = strtok (line, "\t ")) != NULL) {
97 /* get the username */
98 username = strtok (NULL, "\t ");
99 /* look for a netmask */
100 if ((cp = strtok (line, "/")) != NULL) {
101 /* store the ip address in a temporary buffer */
102 tmpbuf = cp;
103 cp = strtok (NULL, "/");
104 if (cp != NULL) {
105 /* if we have a slash in the lhs, we have a netmask */
106 current_entry->netmask = (inet_addr(cp));
107 current_entry->address =
108 (((inet_addr (tmpbuf))) & current_entry->netmask);
109 } else {
110 /* when theres no slash, we figure the netmask is /32 */
111 current_entry->address = (inet_addr(tmpbuf));
112 current_entry->netmask = (inet_addr("255.255.255.255"));
113 }
114 }
115 /* get space for the username */
116 current_entry->username =
117 (char*)calloc(strlen(username) + 1, sizeof(char));
118 strcpy(current_entry->username, username);
119
120 /* get space and point current_entry to the new entry */
121 current_entry->next_entry =
122 (struct ip_user_dict*)malloc(sizeof(struct ip_user_dict));
123 current_entry = current_entry->next_entry;
124 }
125
126 }
127
128 /* Return a pointer to the first entry linked list */
129 return first_entry;
130 }
131
132 /** This function looks for a matching ip/mask in
133 * the dict file loaded in memory.
134 * It returns 1 if it finds a match or 0 if no match is found
135 */
136 int
137 dict_lookup(struct ip_user_dict *first_entry, char *username,
138 char *address)
139 {
140 /* Move the pointer to the first entry of the linked list. */
141 struct ip_user_dict *current_entry = first_entry;
142
143 while (current_entry->username != NULL) {
144 debug("user: %s\naddr: %lu\nmask: %lu\n\n",
145 current_entry->username, current_entry->address,
146 current_entry->netmask);
147
148 if ((inet_addr (address) & (unsigned long) current_entry->
149 netmask) == current_entry->address) {
150 /* If the username contains an @ we assume it?s a group and
151 call the corresponding function */
152 if ((strchr (current_entry->username, '@')) == NULL) {
153 if ((match_user (current_entry->username, username)) == 1)
154 return 1;
155 } else {
156 if ((match_group (current_entry->username, username)) == 1)
157 return 1;
158 }
159 }
160 current_entry = current_entry->next_entry;
161 }
162
163 /* If no match was found we return 0 */
164 return 0;
165 }
166
167 int
168 match_user(char *dict_username, char *username)
169 {
170 if ((strcmp(dict_username, username)) == 0) {
171 return 1;
172 } else {
173 if ((strcmp(dict_username, "ALL")) == 0) {
174 return 1;
175 }
176 }
177 return 0;
178 } /* match_user */
179
180 int
181 match_group(char *dict_group, char *username)
182 {
183 struct group *g; /* a struct to hold group entries */
184 ++dict_group; /* the @ should be the first char
185 so we rip it off by incrementing
186 * the pointer by one */
187
188 if ((g = getgrnam(dict_group)) == NULL) {
189 debug("Group does not exist '%s'\n", dict_group);
190 return 0;
191 } else {
192 while (*(g->gr_mem) != NULL) {
193 if (strcmp(*((g->gr_mem)++), username) == 0) {
194 return 1;
195 }
196 }
197 }
198 return 0;
199
200 }
201
202 static void
203 usage(const char *program_name)
204 {
205 fprintf (stderr, "Usage:\n%s [-d] -f <configuration file>\n",
206 program_name);
207 }
208
209 int
210 main (int argc, char *argv[])
211 {
212 FILE *FH;
213 char *filename = NULL;
214 char *program_name = argv[0];
215 char *cp;
216 char *username, *address;
217 char line[HELPER_INPUT_BUFFER];
218 struct ip_user_dict *current_entry;
219 int ch;
220
221 setvbuf (stdout, NULL, _IOLBF, 0);
222 while ((ch = getopt(argc, argv, "df:h")) != -1) {
223 switch (ch) {
224 case 'f':
225 filename = optarg;
226 break;
227 case 'd':
228 debug_enabled = 1;
229 break;
230 case 'h':
231 usage(program_name);
232 exit (0);
233 default:
234 fprintf(stderr, "%s: FATAL: Unknown parameter option '%c'", program_name, ch);
235 usage(program_name);
236 exit (1);
237 }
238 }
239 if (filename == NULL) {
240 fprintf(stderr, "%s: FATAL: No Filename configured.", program_name);
241 usage(program_name);
242 exit(1);
243 }
244 FH = fopen(filename, "r");
245 current_entry = load_dict(FH);
246
247 while (fgets(line, HELPER_INPUT_BUFFER, stdin)) {
248 if ((cp = strchr (line, '\n')) == NULL) {
249 /* too large message received.. skip and deny */
250 fprintf(stderr, "%s: ERROR: Input Too Large: %s\n", program_name, line);
251 while (fgets(line, sizeof(line), stdin)) {
252 fprintf(stderr, "%s: ERROR: Input Too Large..: %s\n", program_name, line);
253 if (strchr(line, '\n') != NULL)
254 break;
255 }
256 SEND_ERR("Input Too Large.");
257 continue;
258 }
259 *cp = '\0';
260 address = strtok(line, " \t");
261 username = strtok(NULL, " \t");
262 if (!address || !username) {
263 debug("%s: unable to read tokens\n", program_name);
264 SEND_ERR("Invalid Input.");
265 continue;
266 }
267 rfc1738_unescape(address);
268 rfc1738_unescape(username);
269 int result = dict_lookup(current_entry, username, address);
270 debug("%s: result: %d\n", program_name, result);
271 if (result != 0) {
272 SEND_OK("");
273 } else {
274 SEND_ERR("");
275 }
276 }
277
278 fclose (FH);
279 return 0;
280 }