summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorDaniel Hartmeier <dhartmei@cvs.openbsd.org>2002-05-09 19:58:43 +0000
committerDaniel Hartmeier <dhartmei@cvs.openbsd.org>2002-05-09 19:58:43 +0000
commit2aa85f49b68e153438ffc0397599407bb9e7df59 (patch)
tree6cb5167c099832fa6d9816d0914366ee2ee2eb89 /sbin
parentc5057b445eb5f3ca96e2ad2aaca33a2eacc660ff (diff)
Introduce user based filtering. Rules can specify ruid and euid (real and
effective user ID) much like ports. The user of a packet is either the user that opens an outgoing connection, the one that listens on a socket, or 'unknown' if the firewall is not a connection endpoint (for forwarded connections). Socket uid lookup code from jwk@bug.it.
Diffstat (limited to 'sbin')
-rw-r--r--sbin/pfctl/parse.y328
-rw-r--r--sbin/pfctl/pfctl_parser.c70
2 files changed, 231 insertions, 167 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 13fa80b595a..caaba9e4acb 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.61 2002/04/24 18:10:25 dhartmei Exp $ */
+/* $OpenBSD: parse.y,v 1.62 2002/05/09 19:58:42 dhartmei Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -46,6 +46,7 @@
#include <string.h>
#include <ctype.h>
#include <err.h>
+#include <pwd.h>
#include "pfctl_parser.h"
@@ -82,6 +83,12 @@ struct node_port {
struct node_port *next;
};
+struct node_uid {
+ uid_t uid[2];
+ u_int8_t op;
+ struct node_uid *next;
+};
+
struct node_icmp {
u_int8_t code;
u_int8_t type;
@@ -98,20 +105,11 @@ int rule_consistent(struct pf_rule *);
int yyparse(void);
struct pf_rule_addr *new_addr(void);
void ipmask(struct pf_addr *, u_int8_t);
-void expand_rule_hosts(struct pf_rule *,
- struct node_if *, struct node_proto *,
- struct node_host *, struct node_port *,
- struct node_host *, struct node_port *,
- struct node_icmp *);
-void expand_rule_protos(struct pf_rule *,
- struct node_if *, struct node_proto *,
- struct node_host *, struct node_port *,
- struct node_host *, struct node_port *,
- struct node_icmp *);
void expand_rule(struct pf_rule *,
struct node_if *, struct node_proto *,
struct node_host *, struct node_port *,
struct node_host *, struct node_port *,
+ struct node_uid *, struct node_uid *,
struct node_icmp *);
struct sym {
@@ -148,6 +146,7 @@ typedef struct {
struct node_icmp *icmp;
struct node_host *host;
struct node_port *port;
+ struct node_uid *uid;
struct peer peer;
struct {
struct peer src, dst;
@@ -172,12 +171,12 @@ typedef struct {
%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
%token MINTTL IPV6ADDR ERROR ALLOWOPTS FASTROUTE ROUTETO DUPTO NO LABEL
-%token NOROUTE FRAGMENT
+%token NOROUTE FRAGMENT RUID EUID
%token <v.string> STRING
%token <v.number> NUMBER
%token <v.i> PORTUNARY PORTBINARY
%type <v.interface> interface if_list if_item_not if_item
-%type <v.number> port icmptype icmp6type minttl
+%type <v.number> port icmptype icmp6type minttl uid
%type <v.i> no dir log quick af keep nodf allowopts fragment
%type <v.b> action flag flags blockspec
%type <v.range> dport rport
@@ -187,6 +186,7 @@ typedef struct {
%type <v.peer> ipportspec
%type <v.host> ipspec xhost host address host_list IPV6ADDR
%type <v.port> portspec port_list port_item
+%type <v.uid> ruid euid uid_list uid_item
%type <v.route> route
%type <v.redirection> redirection
%type <v.string> label
@@ -213,7 +213,7 @@ varset : STRING PORTUNARY STRING
}
;
-pfrule : action dir log quick interface route af proto fromto flags icmpspec keep fragment nodf minttl allowopts label
+pfrule : action dir log quick interface route af proto fromto ruid euid flags icmpspec keep fragment nodf minttl allowopts label
{
struct pf_rule r;
@@ -234,18 +234,18 @@ pfrule : action dir log quick interface route af proto fromto flags icmpspec ke
r.af = $7;
- r.flags = $10.b1;
- r.flagset = $10.b2;
+ r.flags = $12.b1;
+ r.flagset = $12.b2;
- r.keep_state = $12;
+ r.keep_state = $14;
- if ($13)
+ if ($15)
r.rule_flag |= PFRULE_FRAGMENT;
- if ($14)
+ if ($16)
r.rule_flag |= PFRULE_NODF;
- if ($15)
- r.min_ttl = $15;
- r.allow_opts = $16;
+ if ($17)
+ r.min_ttl = $17;
+ r.allow_opts = $18;
if ($6.rt) {
r.rt = $6.rt;
@@ -268,18 +268,18 @@ pfrule : action dir log quick interface route af proto fromto flags icmpspec ke
}
}
- if ($17) {
- if (strlen($17) >= PF_RULE_LABEL_SIZE) {
+ if ($19) {
+ if (strlen($19) >= PF_RULE_LABEL_SIZE) {
yyerror("rule label too long (max "
"%d chars)", PF_RULE_LABEL_SIZE-1);
YYERROR;
}
- strlcpy(r.label, $17, sizeof(r.label));
- free($17);
+ strlcpy(r.label, $19, sizeof(r.label));
+ free($19);
}
expand_rule(&r, $5, $8, $9.src.host, $9.src.port,
- $9.dst.host, $9.dst.port, $11);
+ $9.dst.host, $9.dst.port, $10, $11, $13);
}
;
@@ -620,6 +620,71 @@ port : NUMBER {
}
;
+ruid : /* empty */ { $$ = NULL; }
+ | RUID uid_item { $$ = $2; }
+ | RUID '{' uid_list '}' { $$ = $3; }
+ ;
+
+euid : /* empty */ { $$ = NULL; }
+ | EUID uid_item { $$ = $2; }
+ | EUID '{' uid_list '}' { $$ = $3; }
+ ;
+
+uid_list : uid_item { $$ = $1; }
+ | uid_list ',' uid_item { $3->next = $1; $$ = $3; }
+ ;
+
+uid_item : uid {
+ $$ = malloc(sizeof(struct node_uid));
+ if ($$ == NULL)
+ err(1, "uid_item: malloc");
+ $$->uid[0] = $1;
+ $$->uid[1] = $1;
+ $$->op = PF_OP_EQ;
+ $$->next = NULL;
+ }
+ | PORTUNARY uid {
+ $$ = malloc(sizeof(struct node_uid));
+ if ($$ == NULL)
+ err(1, "uid_item: malloc");
+ $$->uid[0] = $2;
+ $$->uid[1] = $2;
+ $$->op = $1;
+ $$->next = NULL;
+ }
+ | uid PORTBINARY uid {
+ $$ = malloc(sizeof(struct node_uid));
+ if ($$ == NULL)
+ err(1, "uid_item: malloc");
+ $$->uid[0] = $1;
+ $$->uid[1] = $3;
+ $$->op = $2;
+ $$->next = NULL;
+ }
+ ;
+
+uid : NUMBER {
+ if ($1 < 0 || $1 >= UID_MAX) {
+ yyerror("illegal uid value %d", $1);
+ YYERROR;
+ }
+ $$ = $1;
+ }
+ | STRING {
+ if (!strcmp($1, "unknown"))
+ $$ = UID_MAX;
+ else {
+ struct passwd *pw;
+
+ if ((pw = getpwnam($1)) == NULL) {
+ yyerror("unknown user %s", $1);
+ YYERROR;
+ }
+ $$ = pw->pw_uid;
+ }
+ }
+ ;
+
flag : STRING {
int f;
@@ -1320,6 +1385,8 @@ struct keywords {
int k_val;
};
+/* macro gore, but you should've seen the prior indentation nightmare... */
+
#define CHECK_ROOT(T,r) \
do { \
if (r == NULL) { \
@@ -1340,126 +1407,24 @@ struct keywords {
} \
} while (0)
-void expand_rule_hosts(struct pf_rule *r,
- struct node_if *interface, struct node_proto *proto,
- struct node_host *src_hosts, struct node_port *src_ports,
- struct node_host *dst_hosts, struct node_port *dst_ports,
- struct node_icmp *icmp_type)
-{
- struct node_host *src_host, *dst_host;
- struct node_port *src_port, *dst_port;
- int nomatch = 0;
-
- src_host = src_hosts;
- while (src_host != NULL) {
- src_port = src_ports;
- while (src_port != NULL) {
- dst_host = dst_hosts;
- while (dst_host != NULL) {
- dst_port = dst_ports;
- while (dst_port != NULL) {
- memcpy(r->ifname, interface->ifname,
- sizeof(r->ifname));
- r->proto = proto->proto;
- r->src.addr = src_host->addr;
- r->src.mask = src_host->mask;
- r->src.noroute = src_host->noroute;
- r->src.not = src_host->not;
- r->src.port[0] = src_port->port[0];
- r->src.port[1] = src_port->port[1];
- r->src.port_op = src_port->op;
- r->dst.addr = dst_host->addr;
- r->dst.mask = dst_host->mask;
- r->dst.noroute = dst_host->noroute;
- r->dst.not = dst_host->not;
- r->dst.port[0] = dst_port->port[0];
- r->dst.port[1] = dst_port->port[1];
- r->dst.port_op = dst_port->op;
- r->type = icmp_type->type;
- r->code = icmp_type->code;
-
- if ((src_host->af && dst_host->af &&
- r->af) && (src_host->af !=
- dst_host->af ||
- src_host->af != r->af ||
- dst_host->af != r->af)) {
- yyerror("address family"
- " mismatch");
- nomatch++;
- } else if ((src_host->af &&
- dst_host->af) &&
- (src_host->af != dst_host->af)) {
- yyerror("address family"
- " mismatch");
- nomatch++;
- } else if ((src_host->af && r->af) &&
- (src_host->af != r->af)) {
- yyerror("address family"
- " mismatch");
- nomatch++;
- } else if ((dst_host->af && r->af) &&
- (dst_host->af != r->af)) {
- yyerror("address family"
- " mismatch");
- nomatch++;
- } else if (src_host->af && !r->af) {
- r->af = src_host->af;
- } else if (dst_host->af && !r->af) {
- r->af= dst_host->af;
- }
-
- if (icmp_type->proto &&
- r->proto != icmp_type->proto) {
- yyerror("icmp-type mismatch");
- nomatch++;
- }
-
- if (rule_consistent(r) < 0 || nomatch)
- yyerror("skipping rule "
- "due to errors");
- else {
- r->nr = pf->rule_nr++;
- pfctl_add_rule(pf, r);
- }
- dst_port = dst_port->next;
- }
- dst_host = dst_host->next;
- }
- src_port = src_port->next;
- }
- src_host = src_host->next;
- }
-}
-
-void expand_rule_protos(struct pf_rule *r,
- struct node_if *interface, struct node_proto *protos,
- struct node_host *src_hosts, struct node_port *src_ports,
- struct node_host *dst_hosts, struct node_port *dst_ports,
- struct node_icmp *icmp_types)
-{
- struct node_proto *proto;
- struct node_icmp *icmp_type;
-
- proto = protos;
- while (proto != NULL) {
- icmp_type = icmp_types;
- while (icmp_type != NULL) {
- expand_rule_hosts(r, interface, proto, src_hosts,
- src_ports, dst_hosts, dst_ports, icmp_type);
- icmp_type = icmp_type->next;
- }
- proto = proto->next;
- }
-}
+#define LOOP_THROUGH(T,n,r,C) \
+ do { \
+ T *n = r; \
+ while (n != NULL) { \
+ C; \
+ n = n->next; \
+ } \
+ } while (0)
void
expand_rule(struct pf_rule *r,
struct node_if *interfaces, struct node_proto *protos,
struct node_host *src_hosts, struct node_port *src_ports,
struct node_host *dst_hosts, struct node_port *dst_ports,
+ struct node_uid *ruids, struct node_uid *euids,
struct node_icmp *icmp_types)
{
- struct node_if *interface;
+ int nomatch = 0;
CHECK_ROOT(struct node_if, interfaces);
CHECK_ROOT(struct node_proto, protos);
@@ -1467,14 +1432,81 @@ expand_rule(struct pf_rule *r,
CHECK_ROOT(struct node_port, src_ports);
CHECK_ROOT(struct node_host, dst_hosts);
CHECK_ROOT(struct node_port, dst_ports);
+ CHECK_ROOT(struct node_uid, ruids);
+ CHECK_ROOT(struct node_uid, euids);
CHECK_ROOT(struct node_icmp, icmp_types);
- interface = interfaces;
- while (interface != NULL) {
- expand_rule_protos(r, interface, protos, src_hosts,
- src_ports, dst_hosts, dst_ports, icmp_types);
- interface = interface->next;
- }
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ LOOP_THROUGH(struct node_proto, proto, protos,
+ LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
+ LOOP_THROUGH(struct node_host, src_host, src_hosts,
+ LOOP_THROUGH(struct node_port, src_port, src_ports,
+ LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
+ LOOP_THROUGH(struct node_port, dst_port, dst_ports,
+ LOOP_THROUGH(struct node_uid, ruid, ruids,
+ LOOP_THROUGH(struct node_uid, euid, euids,
+
+ memcpy(r->ifname, interface->ifname, sizeof(r->ifname));
+ r->proto = proto->proto;
+ r->src.addr = src_host->addr;
+ r->src.mask = src_host->mask;
+ r->src.noroute = src_host->noroute;
+ r->src.not = src_host->not;
+ r->src.port[0] = src_port->port[0];
+ r->src.port[1] = src_port->port[1];
+ r->src.port_op = src_port->op;
+ r->dst.addr = dst_host->addr;
+ r->dst.mask = dst_host->mask;
+ r->dst.noroute = dst_host->noroute;
+ r->dst.not = dst_host->not;
+ r->dst.port[0] = dst_port->port[0];
+ r->dst.port[1] = dst_port->port[1];
+ r->dst.port_op = dst_port->op;
+ r->ruid.op = ruid->op;
+ r->ruid.uid[0] = ruid->uid[0];
+ r->ruid.uid[1] = ruid->uid[1];
+ r->euid.op = euid->op;
+ r->euid.uid[0] = euid->uid[0];
+ r->euid.uid[1] = euid->uid[1];
+ r->type = icmp_type->type;
+ r->code = icmp_type->code;
+
+ if ((src_host->af && dst_host->af && r->af) &&
+ (src_host->af != dst_host->af || src_host->af != r->af ||
+ dst_host->af != r->af)) {
+ yyerror("address family mismatch");
+ nomatch++;
+ } else if ((src_host->af && dst_host->af) &&
+ (src_host->af != dst_host->af)) {
+ yyerror("address family mismatch");
+ nomatch++;
+ } else if ((src_host->af && r->af) &&
+ (src_host->af != r->af)) {
+ yyerror("address family mismatch");
+ nomatch++;
+ } else if ((dst_host->af && r->af) &&
+ (dst_host->af != r->af)) {
+ yyerror("address family mismatch");
+ nomatch++;
+ } else if (src_host->af && !r->af) {
+ r->af = src_host->af;
+ } else if (dst_host->af && !r->af) {
+ r->af= dst_host->af;
+ }
+
+ if (icmp_type->proto && r->proto != icmp_type->proto) {
+ yyerror("icmp-type mismatch");
+ nomatch++;
+ }
+
+ if (rule_consistent(r) < 0 || nomatch)
+ yyerror("skipping rule due to errors");
+ else {
+ r->nr = pf->rule_nr++;
+ pfctl_add_rule(pf, r);
+ }
+
+ )))))))));
FREE_LIST(struct node_if, interfaces);
FREE_LIST(struct node_proto, protos);
@@ -1482,12 +1514,14 @@ expand_rule(struct pf_rule *r,
FREE_LIST(struct node_port, src_ports);
FREE_LIST(struct node_host, dst_hosts);
FREE_LIST(struct node_port, dst_ports);
+ FREE_LIST(struct node_uid, ruids);
+ FREE_LIST(struct node_uid, euids);
FREE_LIST(struct node_icmp, icmp_types);
-
}
#undef FREE_LIST
#undef CHECK_ROOT
+#undef LOOP_THROUGH
int
kw_cmp(k, e)
@@ -1508,6 +1542,7 @@ lookup(char *s)
{ "block", BLOCK},
{ "code", CODE},
{ "dup-to", DUPTO},
+ { "euid", EUID},
{ "fastroute", FASTROUTE},
{ "flags", FLAGS},
{ "fragment", FRAGMENT},
@@ -1539,6 +1574,7 @@ lookup(char *s)
{ "return-icmp6",RETURNICMP6},
{ "return-rst", RETURNRST},
{ "route-to", ROUTETO},
+ { "ruid", RUID},
{ "scrub", SCRUB},
{ "state", STATE},
{ "to", TO},
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 84bb987be3a..9d4739e0696 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.c,v 1.67 2002/05/05 21:40:22 dhartmei Exp $ */
+/* $OpenBSD: pfctl_parser.c,v 1.68 2002/05/09 19:58:42 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -58,7 +58,9 @@ int unmask (struct pf_addr *, u_int8_t);
void print_addr (struct pf_addr_wrap *, struct pf_addr *, u_int8_t);
void print_host (struct pf_state_host *, u_int8_t, int);
void print_seq (struct pf_state_peer *);
+void print_op (u_int8_t, const char *, const char *);
void print_port (u_int8_t, u_int16_t, u_int16_t, char *);
+void print_uid (u_int8_t, uid_t, uid_t, const char *);
void print_flags (u_int8_t);
char *tcpflags = "FSRPAU";
@@ -351,35 +353,55 @@ print_seq(struct pf_state_peer *p)
}
void
-print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto)
+print_op(u_int8_t op, const char *a1, const char *a2)
{
- struct servent *s = getservbyport(p1, proto);
-
- p1 = ntohs(p1);
- p2 = ntohs(p2);
- printf("port ");
if (op == PF_OP_IRG)
- printf("%u >< %u ", p1, p2);
+ printf("%s >< %s ", a1, a2);
else if (op == PF_OP_XRG)
- printf("%u <> %u ", p1, p2);
+ printf("%s <> %s ", a1, a2);
else if (op == PF_OP_EQ) {
- if (s != NULL)
- printf("= %s ", s->s_name);
- else
- printf("= %u ", p1);
+ printf("= %s ", a1);
} else if (op == PF_OP_NE) {
- if (s != NULL)
- printf("!= %s ", s->s_name);
- else
- printf("!= %u ", p1);
+ printf("!= %s ", a1);
} else if (op == PF_OP_LT)
- printf("< %u ", p1);
+ printf("< %s ", a1);
else if (op == PF_OP_LE)
- printf("<= %u ", p1);
+ printf("<= %s ", a1);
else if (op == PF_OP_GT)
- printf("> %u ", p1);
+ printf("> %s ", a1);
else if (op == PF_OP_GE)
- printf(">= %u ", p1);
+ printf(">= %s ", a1);
+}
+
+void
+print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto)
+{
+ char a1[5], a2[5];
+ struct servent *s = getservbyport(p1, proto);
+
+ p1 = ntohs(p1);
+ p2 = ntohs(p2);
+ snprintf(a1, sizeof(a1), "%u", p1);
+ snprintf(a2, sizeof(a2), "%u", p2);
+ printf("port ");
+ if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE))
+ print_op(op, s->s_name, a2);
+ else
+ print_op(op, a1, a2);
+}
+
+void
+print_uid(u_int8_t op, uid_t u1, uid_t u2, const char *t)
+{
+ char a1[5], a2[5];
+
+ snprintf(a1, sizeof(a1), "%u", u1);
+ snprintf(a2, sizeof(a2), "%u", u2);
+ printf("%s ", t);
+ if (u1 == UID_MAX && (op == PF_OP_EQ || op == PF_OP_NE))
+ print_op(op, "unknown", a2);
+ else
+ print_op(op, a1, a2);
}
void
@@ -781,6 +803,12 @@ print_rule(struct pf_rule *r)
r->dst.port[1],
r->proto == IPPROTO_TCP ? "tcp" : "udp");
}
+ if (r->ruid.op) {
+ print_uid(r->ruid.op, r->ruid.uid[0], r->ruid.uid[1], "ruid");
+ }
+ if (r->euid.op) {
+ print_uid(r->euid.op, r->euid.uid[0], r->euid.uid[1], "euid");
+ }
if (r->flags || r->flagset) {
printf("flags ");
print_flags(r->flags);