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 
49 struct ip_user_dict {
50  unsigned long address; // IP address (assumes IPv4)
51  unsigned long netmask; // IP netmask
52  char *username;
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 
62 #define DICT_BUFFER_SIZE 8196
63 
64 static 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 
81 struct ip_user_dict *
82 load_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 
155 int
156 dict_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 
186 int
187 match_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 
199 int
200 match_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 
220 static void
221 usage(const char *program_name)
222 {
223  fprintf (stderr, "Usage:\n%s [-d] -f <configuration file>\n",
224  program_name);
225 }
226 
227 int
228 main (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 
const char * xstrerr(int error)
Definition: xstrerror.cc:83
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
#define DICT_BUFFER_SIZE
void debug(const char *format,...)
Definition: debug.cc:19
int match_group(char *, char *)
unsigned long address
char * optarg
Definition: getopt.c:51
int match_user(char *, char *)
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: getopt.c:62
int main(int argc, char *argv[])
void rfc1738_unescape(char *url)
Definition: rfc1738.c:146
#define SEND_ERR(x)
struct ip_user_dict * load_dict(FILE *)
int debug_enabled
Definition: debug.cc:13
#define safe_free(x)
Definition: xalloc.h:73
#define SEND_BH(x)
int dict_lookup(struct ip_user_dict *, char *, char *)
#define xfree
struct ip_user_dict * next_entry
#define HELPER_INPUT_BUFFER
Definition: UserRequest.cc:24
unsigned long netmask
squidaio_request_t * head
Definition: aiops.cc:129
char * program_name
static void free_dict(struct ip_user_dict *head)
static void usage(const char *program_name)
#define HLP_MSG(text)
#define SEND_OK(x)

 

Introduction

Documentation

Support

Miscellaneous