From 6435edf3cfa36bd5f722c695de7eaed2a4a356d2 Mon Sep 17 00:00:00 2001 From: hno <> Date: Sun, 23 Jun 2002 20:25:16 +0000 Subject: [PATCH] ip_user external_acl helper by Rodrigo Campos --- helpers/external_acl/ip_user/README | 42 ++++++ helpers/external_acl/ip_user/dict.c | 142 ++++++++++++++++++ .../ip_user/example-deny_all_but.conf | 2 + helpers/external_acl/ip_user/example.conf | 39 +++++ helpers/external_acl/ip_user/ip_user.h | 39 +++++ helpers/external_acl/ip_user/license | 19 +++ helpers/external_acl/ip_user/main.c | 93 ++++++++++++ helpers/external_acl/ip_user/match.c | 61 ++++++++ 8 files changed, 437 insertions(+) create mode 100644 helpers/external_acl/ip_user/README create mode 100644 helpers/external_acl/ip_user/dict.c create mode 100644 helpers/external_acl/ip_user/example-deny_all_but.conf create mode 100644 helpers/external_acl/ip_user/example.conf create mode 100644 helpers/external_acl/ip_user/ip_user.h create mode 100644 helpers/external_acl/ip_user/license create mode 100644 helpers/external_acl/ip_user/main.c create mode 100644 helpers/external_acl/ip_user/match.c diff --git a/helpers/external_acl/ip_user/README b/helpers/external_acl/ip_user/README new file mode 100644 index 0000000000..eaa697a55b --- /dev/null +++ b/helpers/external_acl/ip_user/README @@ -0,0 +1,42 @@ +$Id: README,v 1.1 2002/06/23 14:25:16 hno Exp $ + +README file for ip_user_check, an external helper for the +Squid external acl scheme. + +It works by reading a pair composed by an ip address and an username +on STDIN and matching it against a configuration file. + +The configuration for the external ACL should be: + +external_acl_type type-name %SRC %LOGIN /path/to/ip_user_check -f /path/to/config.file + +If the program finds a matching username/ip in the configuration file, +it returns `OK', or `ERR' otherwise. + +The usage for the program is: + +ip_user_check -f + + +The configuration file format is as follows: + +ip_addr[/mask] user|@group|ALL|NONE + +Where ip_addr is a dotted quad format IP address, the mask +must be in dotted quad format too. + +When the second parameter is prefixed with an @, the program will lookup in the +/etc/group entry for the specified username. + +There are other two directives, `ALL' and `NONE', which mean "any user on this ip +address may authenticate" or "no user on this ip address may authenticate". + +TODO +- Deny operator, to create `allow all but' rules +- Check for a valid user in the OS +- Accept decimal format netmasks + + +-- +Rodrigo Campos +rodrigo@geekbunker.org diff --git a/helpers/external_acl/ip_user/dict.c b/helpers/external_acl/ip_user/dict.c new file mode 100644 index 0000000000..cc3fbdd5a2 --- /dev/null +++ b/helpers/external_acl/ip_user/dict.c @@ -0,0 +1,142 @@ +/* $Id: dict.c,v 1.1 2002/06/23 14:25:17 hno Exp $ +* Copyright (C) 2002 Rodrigo Campos +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Author: Rodrigo Campos (rodrigo@geekbunker.org) +* +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "ip_user.h" + +#ifndef DEBUG +#undef DEBUG +#endif + + +/* This function parses the dictionary file and loads it + * in memory. All IP addresses are processed with a bitwise AND + * with their netmasks before they are stored. + * If there´s no netmask (no /) in the in the lhs , a mask + * 255.255.255.255 is assumed. + * It returns a pointer to the first entry of the linked list + */ +struct ip_user_dict * +load_dict (FILE * FH) +{ + struct ip_user_dict *current_entry; /* the structure used to + store data */ + struct ip_user_dict *first_entry = NULL; /* the head of the + linked list */ + char line[BUFSIZE]; /* the buffer for the lines read + from the dict file */ + char *cp; /* a char pointer used to parse + each line */ + char *username; /* for the username */ + char *tmpbuf; /* for the address before the + bitwise AND */ + + /* the pointer to the first entry in the linked list */ + first_entry = malloc (sizeof (struct ip_user_dict)); + current_entry = first_entry; + + while ((cp = fgets (line, sizeof (line), FH)) != NULL) { + if (line[0] == '#') { + continue; + } + if ((cp = strchr (line, '\n')) != NULL) { + /* chop \n characters */ + *cp = '\0'; + } + if ((cp = strtok (line, "\t ")) != NULL) { + /* get the username */ + username = strtok (NULL, "\t "); + /* look for a netmask */ + if ((cp = strtok (line, "/")) != NULL) { + /* store the ip address in a temporary buffer */ + tmpbuf = cp; + cp = strtok (NULL, "/"); + if (cp != NULL) { + /* if we have a slash in the lhs, we have a netmask */ + current_entry->netmask = (inet_addr (cp)); + current_entry->address = + (((inet_addr (tmpbuf))) & current_entry->netmask); + } else { + /* when theres no slash, we figure the netmask is /32 */ + current_entry->address = (inet_addr (tmpbuf)); + current_entry->netmask = (inet_addr ("255.255.255.255")); + } + } + /* get space for the username */ + current_entry->username = + calloc (strlen (username) + 1, sizeof (char)); + strcpy (current_entry->username, username); + + /* get space and point current_entry to the new entry */ + current_entry->next_entry = + malloc (sizeof (struct ip_user_dict)); + current_entry = current_entry->next_entry; + } + + } + + /* Return a pointer to the first entry linked list */ + return first_entry; +} /* load_dict */ + +/* This function looks for a matching ip/mask in + * the dict file loaded in memory. + * It returns 1 if it finds a match or 0 if no match is found + */ +int +dict_lookup (struct ip_user_dict *first_entry, char *username, + char *address) +{ + /* Move the pointer to the first entry of the linked list. */ + struct ip_user_dict *current_entry = first_entry; + + while (current_entry->username != NULL) { +#ifdef DEBUG + printf ("user: %s\naddr: %lu\nmask: %lu\n\n", + current_entry->username, current_entry->address, + current_entry->netmask); +#endif + + if ((inet_addr (address) & (unsigned long) current_entry-> + netmask) == current_entry->address) { + /* If the username contains an @ we assume it´s a group and + call the corresponding function */ + if ((strchr (current_entry->username, '@')) == NULL) { + if ((match_user (current_entry->username, username)) == 1) + return 1; + } else { + if ((match_group (current_entry->username, username)) == 1) + return 1; + } + } + current_entry = current_entry->next_entry; + } + + /* If no match was found we return 0 */ + return 0; +} /* dict_lookup */ diff --git a/helpers/external_acl/ip_user/example-deny_all_but.conf b/helpers/external_acl/ip_user/example-deny_all_but.conf new file mode 100644 index 0000000000..a5280b0e43 --- /dev/null +++ b/helpers/external_acl/ip_user/example-deny_all_but.conf @@ -0,0 +1,2 @@ +192.168.1.0/255.255.255.0 diniz +0.0.0.0/0.0.0.0 NONE diff --git a/helpers/external_acl/ip_user/example.conf b/helpers/external_acl/ip_user/example.conf new file mode 100644 index 0000000000..f994e9025b --- /dev/null +++ b/helpers/external_acl/ip_user/example.conf @@ -0,0 +1,39 @@ +# $Id: example.conf,v 1.1 2002/06/23 14:25:17 hno Exp $ +# Lines that begin with a # are ignored +# The main format is: +# +# Single user +# ip[/mask] user +# +# Users that belong to `group´ (/etc/group) +# ip[/mask] @group +# +# No User from this IP +# ip[/mask] NONE +# +# All Users from this IP +# ip[/mask] ALL +# +# IP and MASK must be in dotted quad format. +# +# Ths first match wins, so you may create rules that +# `allow everyone but foo bar´ or +# `deny everyone but foo bar´ +# +# Examples: +# All users from the 192.168.1.0/24 network are allowed +# 192.168.1.0/255.255.255.0 ALL +# +# Users from the 192.168.2.0/24 network are not allowed +# except for user `boss´ that can authenticate from +# anywhere +# 0.0.0.0/0.0.0.0 boss +# 192.168.2.0/255.255.255.0 NONE +# +# User `jayk´ may athenticate only from his station +# ip address +# 192.168.3.45 jayk +# +# Users of the `tol´ group may authenticate from +# their VLAN +# 10.0.0.0/255.255.0.0 @tol diff --git a/helpers/external_acl/ip_user/ip_user.h b/helpers/external_acl/ip_user/ip_user.h new file mode 100644 index 0000000000..f8617f461e --- /dev/null +++ b/helpers/external_acl/ip_user/ip_user.h @@ -0,0 +1,39 @@ +/* $Id: ip_user.h,v 1.1 2002/06/23 14:25:17 hno Exp $ +* Copyright (C) 2002 Rodrigo Campos +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Author: Rodrigo Campos (rodrigo@geekbunker.org) +* +*/ + + + + +struct ip_user_dict +{ + unsigned long address; + unsigned long netmask; + char *username; + struct ip_user_dict *next_entry; +}; + +extern int match_user(char *, char *); +extern int match_group(char *, char *); +extern struct ip_user_dict *load_dict(FILE *); +extern int dict_lookup(struct ip_user_dict *, char *, char *); + + +#define BUFSIZE 1024 diff --git a/helpers/external_acl/ip_user/license b/helpers/external_acl/ip_user/license new file mode 100644 index 0000000000..1be649a5e5 --- /dev/null +++ b/helpers/external_acl/ip_user/license @@ -0,0 +1,19 @@ +* Copyright (C) 2002 Rodrigo Campos +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Author: Rodrigo Campos (rodrigo@geekbunker.org) +* +*/ diff --git a/helpers/external_acl/ip_user/main.c b/helpers/external_acl/ip_user/main.c new file mode 100644 index 0000000000..ba3c8b4cbe --- /dev/null +++ b/helpers/external_acl/ip_user/main.c @@ -0,0 +1,93 @@ +/* $Id: main.c,v 1.1 2002/06/23 14:25:17 hno Exp $ +* Copyright (C) 2002 Rodrigo Campos +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Author: Rodrigo Campos (rodrigo@geekbunker.org) +* +*/ +#include +#include +#include +#include + + +#include "ip_user.h" + + +void +usage (char *program_name) +{ + fprintf (stderr, "Usage:\n%s -f \n", + program_name); +} + +int +main (int argc, char *argv[]) +{ + FILE *FH; + char *filename = NULL; + char *program_name = argv[0]; + char *cp; + char *username, *address; + char line[BUFSIZE]; + struct ip_user_dict *current_entry; + int ch; + + setvbuf (stdout, NULL, _IOLBF, 0); + while ((ch = getopt (argc, argv, "f:")) != -1) { + switch (ch) { + case 'f': + filename = optarg; + break; + default: + usage (program_name); + exit (1); + } + } + if (filename == NULL) { + usage (program_name); + exit(1); + } + FH = fopen (filename, "r"); + current_entry = load_dict (FH); + + while (fgets (line, sizeof (line), stdin)) { + if ((cp = strchr (line, '\n')) != NULL) { + *cp = '\0'; + } + if ((cp = strtok (line, " \t")) != NULL) { + address = cp; + username = strtok (NULL, " \t"); + } else { + fprintf (stderr, "helper: unable to read tokens\n"); + } +#ifdef DEBUG + printf ("result: %d\n", + dict_lookup (current_entry, username, address)); +#endif + if ((dict_lookup (current_entry, username, address)) != 0) { + printf ("OK\n"); + } else { + printf ("ERR\n"); + } + + + } + + + fclose (FH); + return 0; +} diff --git a/helpers/external_acl/ip_user/match.c b/helpers/external_acl/ip_user/match.c new file mode 100644 index 0000000000..071d529b0b --- /dev/null +++ b/helpers/external_acl/ip_user/match.c @@ -0,0 +1,61 @@ +/* $Id: match.c,v 1.1 2002/06/23 14:25:17 hno Exp $ +* Copyright (C) 2002 Rodrigo Campos +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* Author: Rodrigo Campos (rodrigo@geekbunker.org) +* +*/ +#include +#include +#include +#include + + +int +match_user (char *dict_username, char *username) +{ + if ((strcmp (dict_username, username)) == 0) { + return 1; + } else { + if ((strcmp (dict_username, "ALL")) == 0) { + return 1; + } + } + return 0; +} /* match_user */ + +int +match_group (char *dict_group, char *username) +{ + struct group *g; /* a struct to hold group entries */ + dict_group++; /* the @ should be the first char + so we rip it off by incrementing + * the pointer by one */ + + if ((g = getgrnam (dict_group)) == NULL) { + fprintf (stderr, "helper: Group does not exist '%s'\n", + dict_group); + return 0; + } else { + while (*(g->gr_mem) != NULL) { + if (strcmp (*((g->gr_mem)++), username) == 0) { + return 1; + } + } + } + return 0; + +} /* match_group */ -- 2.47.3