diff options
Diffstat (limited to 'src/pluto/foodgroups.c')
-rw-r--r-- | src/pluto/foodgroups.c | 450 |
1 files changed, 0 insertions, 450 deletions
diff --git a/src/pluto/foodgroups.c b/src/pluto/foodgroups.c deleted file mode 100644 index e4f9a1d01..000000000 --- a/src/pluto/foodgroups.c +++ /dev/null @@ -1,450 +0,0 @@ -/* Implement policy groups-style control files (aka "foodgroups") - * Copyright (C) 2002 D. Hugh Redelmeier. - * - * 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. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * 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. - */ - -#include <string.h> -#include <stdio.h> -#include <stddef.h> -#include <stdlib.h> -#include <sys/queue.h> - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "connections.h" -#include "foodgroups.h" -#include "kernel.h" -#include "lex.h" -#include "log.h" -#include "whack.h" - - -/* Food group config files are found in directory fg_path */ - -#ifndef POLICYGROUPSDIR -#define POLICYGROUPSDIR IPSEC_CONFDIR "/ipsec.d/policies" -#endif - -const char *policygroups_dir = POLICYGROUPSDIR; - -static char *fg_path = NULL; -static size_t fg_path_space = 0; - - -/* Groups is a list of connections that are policy groups. - * The list is updated as group connections are added and deleted. - */ - -struct fg_groups { - struct fg_groups *next; - connection_t *connection; -}; - -static struct fg_groups *groups = NULL; - - -/* Targets is a list of pairs: subnet and its policy group. - * This list is bulk-updated on whack --listen and - * incrementally updated when group connections are deleted. - * - * It is ordered by source subnet, and if those are equal, then target subnet. - * A subnet is compared by comparing the network, and if those are equal, - * comparing the mask. - */ - -struct fg_targets { - struct fg_targets *next; - struct fg_groups *group; - ip_subnet subnet; - char *name; /* name of instance of group conn */ -}; - -static struct fg_targets *targets = NULL; - -struct fg_targets *new_targets; - -/* ipcmp compares the two ip_address values a and b. - * It returns -1, 0, or +1 if a is, respectively, - * less than, equal to, or greater than b. - */ -static int ipcmp(ip_address *a, ip_address *b) -{ - if (addrtypeof(a) != addrtypeof(b)) - { - return addrtypeof(a) < addrtypeof(b)? -1 : 1; - } - else if (sameaddr(a, b)) - { - return 0; - } - else - { - const struct sockaddr *sa = sockaddrof(a) - , *sb = sockaddrof(b); - - passert(addrtypeof(a) == AF_INET); /* not yet implemented IPv6 version :-( */ - return (ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr) - < ntohl(((const struct sockaddr_in *)sb)->sin_addr.s_addr)) - ? -1 : 1; - } -} - -/* subnetcmp compares the two ip_subnet values a and b. - * It returns -1, 0, or +1 if a is, respectively, - * less than, equal to, or greater than b. - */ -static int subnetcmp(const ip_subnet *a, const ip_subnet *b) -{ - ip_address neta, maska, netb, maskb; - int r; - - networkof(a, &neta); - maskof(a, &maska); - networkof(b, &netb); - maskof(b, &maskb); - r = ipcmp(&neta, &netb); - if (r == 0) - r = ipcmp(&maska, &maskb); - return r; -} - -static void read_foodgroup(struct fg_groups *g) -{ - const char *fgn = g->connection->name; - const ip_subnet *lsn = &g->connection->spd.this.client; - size_t plen = strlen(policygroups_dir) + 1 + strlen(fgn) + 1; - struct file_lex_position flp_space; - - if (plen > fg_path_space) - { - free(fg_path); - fg_path_space = plen + 10; - fg_path = malloc(fg_path_space); - } - snprintf(fg_path, fg_path_space, "%s/%s", policygroups_dir, fgn); - if (!lexopen(&flp_space, fg_path, TRUE)) - { - DBG(DBG_CONTROL, DBG_log("no group file \"%s\"", fg_path)); - } - else - { - plog("loading group \"%s\"", fg_path); - for (;;) - { - switch (flp->bdry) - { - case B_none: - { - /* !!! this test is not sufficient for distinguishing address families. - * We need a notation to specify that a FQDN is to be resolved to IPv6. - */ - const struct af_info *afi = strchr(tok, ':') == NULL - ? &af_inet4_info: &af_inet6_info; - ip_subnet sn; - err_t ugh; - - if (strchr(tok, '/') == NULL) - { - /* no /, so treat as /32 or V6 equivalent */ - ip_address t; - - ugh = ttoaddr(tok, 0, afi->af, &t); - if (ugh == NULL) - ugh = addrtosubnet(&t, &sn); - } - else - { - ugh = ttosubnet(tok, 0, afi->af, &sn); - } - - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s \"%s\"" - , flp->filename, flp->lino, ugh, tok); - } - else if (afi->af != AF_INET) - { - loglog(RC_LOG_SERIOUS - , "\"%s\" line %d: unsupported Address Family \"%s\"" - , flp->filename, flp->lino, tok); - } - else - { - /* Find where new entry ought to go in new_targets. */ - struct fg_targets **pp; - int r; - - for (pp = &new_targets; ; pp = &(*pp)->next) - { - if (*pp == NULL) - { - r = -1; /* end of list is infinite */ - break; - } - r = subnetcmp(lsn, &(*pp)->group->connection->spd.this.client); - if (r == 0) - r = subnetcmp(&sn, &(*pp)->subnet); - if (r <= 0) - break; - } - - if (r == 0) - { - char source[SUBNETTOT_BUF]; - - subnettot(lsn, 0, source, sizeof(source)); - loglog(RC_LOG_SERIOUS - , "\"%s\" line %d: subnet \"%s\", source %s, already \"%s\"" - , flp->filename - , flp->lino - , tok - , source - , (*pp)->group->connection->name); - } - else - { - struct fg_targets *f = malloc_thing(struct fg_targets); - - f->next = *pp; - f->group = g; - f->subnet = sn; - f->name = NULL; - *pp = f; - } - } - } - (void)shift(); /* next */ - continue; - - case B_record: - flp->bdry = B_none; /* eat the Record Boundary */ - (void)shift(); /* get real first token */ - continue; - - case B_file: - break; /* done */ - } - break; /* if we reach here, out of loop */ - } - lexclose(); - } -} - -static void free_targets(void) -{ - while (targets != NULL) - { - struct fg_targets *t = targets; - - targets = t->next; - free(t->name); - free(t); - } -} - -void load_groups(void) -{ - passert(new_targets == NULL); - - /* for each group, add config file targets into new_targets */ - { - struct fg_groups *g; - - for (g = groups; g != NULL; g = g->next) - if (oriented(*g->connection)) - read_foodgroup(g); - } - - /* dump new_targets */ - DBG(DBG_CONTROL, - { - struct fg_targets *t; - - for (t = new_targets; t != NULL; t = t->next) - { - char asource[SUBNETTOT_BUF]; - char atarget[SUBNETTOT_BUF]; - - subnettot(&t->group->connection->spd.this.client - , 0, asource, sizeof(asource)); - subnettot(&t->subnet, 0, atarget, sizeof(atarget)); - DBG_log("%s->%s %s" - , asource, atarget - , t->group->connection->name); - } - }); - - /* determine and deal with differences between targets and new_targets. - * structured like a merge. - */ - { - struct fg_targets *op = targets - , *np = new_targets; - - while (op != NULL && np != NULL) - { - int r = subnetcmp(&op->group->connection->spd.this.client - , &np->group->connection->spd.this.client); - - if (r == 0) - r = subnetcmp(&op->subnet, &np->subnet); - - if (r == 0 && op->group == np->group) - { - /* unchanged -- steal name & skip over */ - np->name = op->name; - op->name = NULL; - op = op->next; - np = np->next; - } - else - { - /* note: following cases overlap! */ - if (r <= 0) - { - remove_group_instance(op->group->connection, op->name); - op = op->next; - } - if (r >= 0) - { - np->name = add_group_instance(np->group->connection, &np->subnet); - np = np->next; - } - } - } - for (; op != NULL; op = op->next) - remove_group_instance(op->group->connection, op->name); - for (; np != NULL; np = np->next) - np->name = add_group_instance(np->group->connection, &np->subnet); - - /* update: new_targets replaces targets */ - free_targets(); - targets = new_targets; - new_targets = NULL; - } -} - - -void add_group(connection_t *c) -{ - struct fg_groups *g = malloc_thing(struct fg_groups); - - g->next = groups; - groups = g; - - g->connection = c; -} - -static struct fg_groups *find_group(const connection_t *c) -{ - struct fg_groups *g; - - for (g = groups; g != NULL && g->connection != c; g = g->next) - ; - return g; -} - -void route_group(connection_t *c) -{ - /* it makes no sense to route a connection that is ISAKMP-only */ - if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy)) - { - loglog(RC_ROUTE, "cannot route an ISAKMP-only group connection"); - } - else - { - struct fg_groups *g = find_group(c); - struct fg_targets *t; - - passert(g != NULL); - g->connection->policy |= POLICY_GROUTED; - for (t = targets; t != NULL; t = t->next) - { - if (t->group == g) - { - connection_t *ci = con_by_name(t->name, FALSE); - - if (ci != NULL) - { - set_cur_connection(ci); - if (!trap_connection(ci)) - whack_log(RC_ROUTE, "could not route"); - set_cur_connection(c); - } - } - } - } -} - -void unroute_group(connection_t *c) -{ - struct fg_groups *g = find_group(c); - struct fg_targets *t; - - passert(g != NULL); - g->connection->policy &= ~POLICY_GROUTED; - for (t = targets; t != NULL; t = t->next) - { - if (t->group == g) - { - connection_t *ci = con_by_name(t->name, FALSE); - - if (ci != NULL) - { - set_cur_connection(ci); - unroute_connection(ci); - set_cur_connection(c); - } - } - } -} - -void delete_group(const connection_t *c) -{ - struct fg_groups *g; - - /* find and remove from groups */ - { - struct fg_groups **pp; - - for (pp = &groups; (g = *pp)->connection != c; pp = &(*pp)->next) - ; - - *pp = g->next; - } - - /* find and remove from targets */ - { - struct fg_targets **pp; - - for (pp = &targets; *pp != NULL; ) - { - struct fg_targets *t = *pp; - - if (t->group == g) - { - *pp = t->next; - remove_group_instance(t->group->connection, t->name); - free(t); - /* pp is ready for next iteration */ - } - else - { - pp = &t->next; - } - } - } - - free(g); -} |