]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/external_acl/file_userip/ext_file_userip_acl.cc
Additional tools may use malloc/calloc/free
[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 "config.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
49 struct ip_user_dict {
50 unsigned long address; // IP address (assumes IPv4)
51 unsigned long netmask; // IP netmask
52 char *username;
53 struct ip_user_dict *next_entry;
54 };
55
56 int match_user(char *, char *);
57 int match_group(char *, char *);
58 struct ip_user_dict *load_dict(FILE *);
59 int dict_lookup(struct ip_user_dict *, char *, char *);
60
61 /** Size of lines read from the dictionary file */
62 #define DICT_BUFFER_SIZE 8196
63
64 /** This function parses the dictionary file and loads it
65 * in memory. All IP addresses are processed with a bitwise AND
66 * with their netmasks before they are stored.
67 * If there?s no netmask (no /) in the in the lhs , a mask
68 * 255.255.255.255 is assumed.
69 * It returns a pointer to the first entry of the linked list
70 */
71 struct ip_user_dict *
72 load_dict(FILE * FH) {
73 struct ip_user_dict *current_entry; /* the structure used to
74 store data */
75 struct ip_user_dict *first_entry = NULL; /* the head of the
76 linked list */
77 char line[DICT_BUFFER_SIZE]; /* the buffer for the lines read
78 from the dict file */
79 char *cp; /* a char pointer used to parse
80 each line */
81 char *username; /* for the username */
82 char *tmpbuf; /* for the address before the
83 bitwise AND */
84
85 /* the pointer to the first entry in the linked list */
86 first_entry = (struct ip_user_dict*)malloc(sizeof(struct ip_user_dict));
87 current_entry = first_entry;
88
89 while ((cp = fgets (line, DICT_BUFFER_SIZE, FH)) != NULL) {
90 if (line[0] == '#') {
91 continue;
92 }
93 if ((cp = strchr (line, '\n')) != NULL) {
94 /* chop \n characters */
95 *cp = '\0';
96 }
97 if ((cp = strtok (line, "\t ")) != NULL) {
98 /* get the username */
99 username = strtok (NULL, "\t ");
100 /* look for a netmask */
101 if ((cp = strtok (line, "/")) != NULL) {
102 /* store the ip address in a temporary buffer */
103 tmpbuf = cp;
104 cp = strtok (NULL, "/");
105 if (cp != NULL) {
106 /* if we have a slash in the lhs, we have a netmask */
107 current_entry->netmask = (inet_addr(cp));
108 current_entry->address =
109 (((inet_addr (tmpbuf))) & current_entry->netmask);
110 } else {
111 /* when theres no slash, we figure the netmask is /32 */
112 current_entry->address = (inet_addr(tmpbuf));
113 current_entry->netmask = (inet_addr("255.255.255.255"));
114 }
115 }
116 /* get space for the username */
117 current_entry->username =
118 (char*)calloc(strlen(username) + 1, sizeof(char));
119 strcpy(current_entry->username, username);
120
121 /* get space and point current_entry to the new entry */
122 current_entry->next_entry =
123 (struct ip_user_dict*)malloc(sizeof(struct ip_user_dict));
124 current_entry = current_entry->next_entry;
125 }
126
127 }
128
129 /* Return a pointer to the first entry linked list */
130 return first_entry;
131 }
132
133 /** This function looks for a matching ip/mask in
134 * the dict file loaded in memory.
135 * It returns 1 if it finds a match or 0 if no match is found
136 */
137 int
138 dict_lookup(struct ip_user_dict *first_entry, char *username,
139 char *address)
140 {
141 /* Move the pointer to the first entry of the linked list. */
142 struct ip_user_dict *current_entry = first_entry;
143
144 while (current_entry->username != NULL) {
145 debug("user: %s\naddr: %lu\nmask: %lu\n\n",
146 current_entry->username, current_entry->address,
147 current_entry->netmask);
148
149 if ((inet_addr (address) & (unsigned long) current_entry->
150 netmask) == current_entry->address) {
151 /* If the username contains an @ we assume it?s a group and
152 call the corresponding function */
153 if ((strchr (current_entry->username, '@')) == NULL) {
154 if ((match_user (current_entry->username, username)) == 1)
155 return 1;
156 } else {
157 if ((match_group (current_entry->username, username)) == 1)
158 return 1;
159 }
160 }
161 current_entry = current_entry->next_entry;
162 }
163
164 /* If no match was found we return 0 */
165 return 0;
166 }
167
168 int
169 match_user(char *dict_username, char *username)
170 {
171 if ((strcmp(dict_username, username)) == 0) {
172 return 1;
173 } else {
174 if ((strcmp(dict_username, "ALL")) == 0) {
175 return 1;
176 }
177 }
178 return 0;
179 } /* match_user */
180
181 int
182 match_group(char *dict_group, char *username)
183 {
184 struct group *g; /* a struct to hold group entries */
185 dict_group++; /* the @ should be the first char
186 so we rip it off by incrementing
187 * the pointer by one */
188
189 if ((g = getgrnam(dict_group)) == NULL) {
190 debug("Group does not exist '%s'\n", dict_group);
191 return 0;
192 } else {
193 while (*(g->gr_mem) != NULL) {
194 if (strcmp(*((g->gr_mem)++), username) == 0) {
195 return 1;
196 }
197 }
198 }
199 return 0;
200
201 }
202
203 static void
204 usage(const char *program_name)
205 {
206 fprintf (stderr, "Usage:\n%s [-d] -f <configuration file>\n",
207 program_name);
208 }
209
210 int
211 main (int argc, char *argv[])
212 {
213 FILE *FH;
214 char *filename = NULL;
215 char *program_name = argv[0];
216 char *cp;
217 char *username, *address;
218 char line[HELPER_INPUT_BUFFER];
219 struct ip_user_dict *current_entry;
220 int ch;
221
222 setvbuf (stdout, NULL, _IOLBF, 0);
223 while ((ch = getopt(argc, argv, "df:h")) != -1) {
224 switch (ch) {
225 case 'f':
226 filename = optarg;
227 break;
228 case 'd':
229 debug_enabled = 1;
230 break;
231 case 'h':
232 usage(program_name);
233 exit (0);
234 default:
235 fprintf(stderr, "%s: FATAL: Unknown parameter option '%c'", program_name, ch);
236 usage(program_name);
237 exit (1);
238 }
239 }
240 if (filename == NULL) {
241 fprintf(stderr, "%s: FATAL: No Filename configured.", program_name);
242 usage(program_name);
243 exit(1);
244 }
245 FH = fopen(filename, "r");
246 current_entry = load_dict(FH);
247
248 while (fgets(line, HELPER_INPUT_BUFFER, stdin)) {
249 if ((cp = strchr (line, '\n')) == NULL) {
250 /* too large message received.. skip and deny */
251 fprintf(stderr, "%s: ERROR: Input Too Large: %s\n", program_name, line);
252 while (fgets(line, sizeof(line), stdin)) {
253 fprintf(stderr, "%s: ERROR: Input Too Large..: %s\n", program_name, line);
254 if (strchr(line, '\n') != NULL)
255 break;
256 }
257 SEND_ERR("Input Too Large.");
258 continue;
259 }
260 *cp = '\0';
261 address = strtok(line, " \t");
262 username = strtok(NULL, " \t");
263 if (!address || !username) {
264 debug("%s: unable to read tokens\n", program_name);
265 SEND_ERR("Invalid Input.");
266 continue;
267 }
268 rfc1738_unescape(address);
269 rfc1738_unescape(username);
270 int result = dict_lookup(current_entry, username, address);
271 debug("%s: result: %d\n", program_name, result);
272 if (result != 0) {
273 SEND_OK("");
274 } else {
275 SEND_ERR("");
276 }
277 }
278
279 fclose (FH);
280 return 0;
281 }