📄 foodgroups.c
字号:
/* 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. * * RCSID $Id: foodgroups.c,v 1.20 2004/04/29 03:59:32 mcr Exp $ */#include <unistd.h>#include <string.h>#include <stdio.h>#include <stddef.h>#include <stdlib.h>#include <sys/queue.h>#include <openswan.h>#include "constants.h"#include "defs.h"#include "id.h"#include "x509.h"#include "pgp.h"#include "certs.h"#include "smartcard.h"#ifdef XAUTH_USEPAM#include <security/pam_appl.h>#endif#include "connections.h" /* needs id.h */#include "foodgroups.h"#include "kernel.h" /* needs connections.h */#include "lex.h"#include "log.h"#include "whack.h"#include "paths.h"/* Food group config files are found in directory fg_path */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; struct connection *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 intipcmp(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 intsubnetcmp(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 voidread_foodgroup(struct fg_groups *g){ const char *fgn = g->connection->name; const ip_subnet *lsn = &g->connection->spd.this.client; size_t plen = strlen(ipsec_dir) + sizeof("/policies/") + 1 + strlen(fgn) + 1; struct file_lex_position flp_space; if (plen > fg_path_space) { pfreeany(fg_path); fg_path_space = plen + 10; fg_path = alloc_bytes(fg_path_space, "policy group path"); } snprintf(fg_path, fg_path_space, "%s/policies/%s", ipsec_dir, fgn); if (!lexopen(&flp_space, fg_path, TRUE)) { char cwd[PATH_MAX]; DBG(DBG_CONTROL , DBG_log("no group file \"%s\" (pwd:%s)" , fg_path , getcwd(cwd, sizeof(cwd)))); } else { openswan_log("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 = alloc_thing(struct fg_targets, "fg_target"); 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 voidfree_targets(void){ while (targets != NULL) { struct fg_targets *t = targets; targets = t->next; pfreeany(t->name); pfree(t); }}voidload_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; }}voidadd_group(struct connection *c){ struct fg_groups *g = alloc_thing(struct fg_groups, "policy group"); g->next = groups; groups = g; g->connection = c;}static struct fg_groups *find_group(const struct connection *c){ struct fg_groups *g; for (g = groups; g != NULL && g->connection != c; g = g->next) ; return g;}voidroute_group(struct connection *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) { struct connection *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); } } } }}voidunroute_group(struct connection *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) { struct connection *ci = con_by_name(t->name, FALSE); if (ci != NULL) { set_cur_connection(ci); unroute_connection(ci); set_cur_connection(c); } } }}voiddelete_group(const struct connection *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); pfree(t); /* pp is ready for next iteration */ } else { pp = &t->next; } } } pfree(g);}/* * Local Variables: * c-basic-offset:4 * c-style: pluto * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -