/* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* KAME $Id: parse.y,v 1.1 1999/07/02 17:41:24 itojun Exp $ */ %{ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vchar.h" #define ATOX(c) \ (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) )) u_int p_type; u_int32_t p_spi; struct sockaddr *p_src, *p_dst, *p_proxy; u_int p_ports, p_portd, p_prefs, p_prefd, p_upper; u_int p_satype, p_ext, p_alg_enc, p_alg_auth, p_replay; u_int p_key_enc_len, p_key_auth_len; caddr_t p_key_enc, p_key_auth; time_t p_lt_hard, p_lt_soft; u_int p_policy_len; char *p_policy; /* temporary buffer */ static struct sockaddr *pp_addr; static u_int pp_prefix = ~0; static u_int pp_port = 0; static caddr_t pp_key; extern u_char m_buf[BUFSIZ]; extern int m_len; extern char cmdarg[8192]; extern int f_debug; int setkeymsg __P((void)); static int setvarbuf __P((int *, struct sadb_ext *, int, caddr_t, int)); void parse_init __P((void)); void free_buffer __P((void)); extern int setkeymsg __P((void)); extern int sendkeymsg __P((void)); extern int yylex __P((void)); extern void yyerror __P((char *)); %} %union { unsigned long num; vchar_t val; } %token EOT %token ADD GET DELETE FLUSH DUMP %token IP4_ADDRESS IP6_ADDRESS PREFIX PORT HOSTNAME %token UP_PROTO PR_ESP PR_AH PR_IPCOMP %token DECSTRING QUOTEDSTRING HEXSTRING %token F_PROTOCOL F_AUTH F_ENC F_REPLAY F_COMP F_RAWCPI %token ALG_AUTH ALG_ENC ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_COMP EXTENSION %token F_LIFETIME_HARD F_LIFETIME_SOFT /* SPD management */ %token SPDADD SPDDELETE SPDDUMP SPDFLUSH %token F_POLICY PL_REQUESTS %% commands: /* empty */ | commands command { if (f_debug) { printf("cmdarg:\n%s\n", cmdarg); } else { setkeymsg(); sendkeymsg(); } free_buffer(); parse_init(); } ; command: add_command | get_command | delete_command | flush_command | dump_command | spdadd_command | spddelete_command | spddump_command | spdflush_command ; /* commands concerned with management, there is in tail of this file. */ /* add command */ add_command: ADD { p_type = yylval.num; } selector_spec protocol_spec lifetime_hard lifetime_soft EOT ; /* delete */ delete_command: DELETE { p_type = yylval.num; } selector_spec protocol_spec0 EOT ; /* get command */ get_command: GET { p_type = yylval.num; } selector_spec protocol_spec0 EOT ; /* flush */ flush_command: FLUSH { p_type = yylval.num; } protocol_spec0 EOT ; /* dump */ dump_command: DUMP { p_type = yylval.num; } protocol_spec0 EOT ; /* selector_spec */ selector_spec: src_spec dst_spec upper_spec spi proxy_spec ; src_spec: ip_address { p_src = pp_addr; } prefix { p_prefs = pp_prefix; /* initialize */ pp_prefix = ~0; } port { _INPORTBYSA(p_src) = pp_port; p_ports = pp_port; /* initialize */ pp_port = 0; } ; dst_spec: ip_address { p_dst = pp_addr; } prefix { p_prefd = pp_prefix; /* initialize */ pp_prefix = ~0; } port { _INPORTBYSA(p_dst) = pp_port; p_portd = pp_port; /* initialize */ pp_port = 0; } ; upper_spec: DECSTRING { p_upper = $1.num; } | UP_PROTO { p_upper = $1.num; } | PR_ESP { p_upper = IPPROTO_ESP; }; | PR_AH { p_upper = IPPROTO_AH; }; | PR_IPCOMP { p_upper = IPPROTO_IPCOMP; }; ; spi: DECSTRING { p_spi = yylval.num; } | HEXSTRING { caddr_t bp; caddr_t yp = yylval.val.buf; char buf0[4], buf[4]; int i, j; /* sanity check */ if (yylval.val.len > 4) { yyerror("SPI too big."); return -1; } bp = buf0; while (*yp) { *bp = (ATOX(yp[0]) << 4) | ATOX(yp[1]); yp += 2, bp++; } /* initialize */ for (i = 0; i < 4; i++) buf[i] = 0; for (j = yylval.val.len - 1, i = 3; j >= 0; j--, i--) buf[i] = buf0[j]; /* XXX: endian */ p_spi = ntohl(*(u_int32_t *)buf); } ; proxy_spec: /* empty */ | ip_address { p_proxy = pp_addr; } ; protocol_spec0: /* empty */ | F_PROTOCOL PR_ESP { p_satype = SADB_SATYPE_ESP; } | F_PROTOCOL PR_AH { p_satype = SADB_SATYPE_AH; } | F_PROTOCOL PR_IPCOMP { p_satype = SADB_X_SATYPE_IPCOMP; } ; protocol_spec: F_PROTOCOL PR_ESP { p_satype = SADB_SATYPE_ESP; if (yylval.num == 1) p_ext |= SADB_X_EXT_OLD; else p_ext &= ~SADB_X_EXT_OLD; } extensions esp_specification | F_PROTOCOL PR_AH { p_satype = SADB_SATYPE_AH; if (yylval.num == 1) p_ext |= SADB_X_EXT_OLD; else p_ext &= ~SADB_X_EXT_OLD; } ah_specification | F_PROTOCOL PR_IPCOMP { p_satype = SADB_X_SATYPE_IPCOMP; } ipcomp_specification ; extensions: /* empty */ | extensions extension ; extension: EXTENSION { p_ext |= yylval.num; } ; esp_specification: /* empty */ | esp_specification esp_spec ; esp_spec: F_ENC alg_enc enc_keys | F_AUTH ALG_AUTH { if (p_ext & SADB_X_EXT_OLD) { yyerror("algorithm mismatched."); return -1; } p_alg_auth = yylval.num; } auth_key | F_REPLAY DECSTRING { if (p_ext & SADB_X_EXT_OLD) { yyerror("algorithm mismatched."); return -1; } p_replay = yylval.num; } ; /* XXX: I wanna delete it. */ alg_enc: ALG_ENC { p_alg_enc = yylval.num; } | ALG_ENC_DESDERIV { p_alg_enc = yylval.num; if (p_ext & SADB_X_EXT_OLD) { yyerror("algorithm mismatched."); return -1; } p_ext |= SADB_X_EXT_DERIV; } | ALG_ENC_DES32IV { p_alg_enc = yylval.num; if (!(p_ext & SADB_X_EXT_OLD)) { yyerror("algorithm mismatched."); return -1; } p_ext |= SADB_X_EXT_IV4B; } ; ah_specification: /* empty */ | ah_specification ah_spec ; ah_spec: F_AUTH ALG_AUTH { p_alg_auth = yylval.num; } auth_key | F_REPLAY DECSTRING { if (p_ext & SADB_X_EXT_OLD) { yyerror("algorithm mismatched."); return -1; } p_replay = yylval.num; } ; ipcomp_specification : /* empty */ | ipcomp_specification ipcomp_spec ; ipcomp_spec : F_COMP ALG_COMP { p_alg_enc = yylval.num; } | F_RAWCPI { p_ext |= SADB_X_EXT_RAWCPI; } ; enc_keys: /* empty */ | enc_keys enc_key ; enc_key: key_string { p_key_enc_len = yylval.val.len; p_key_enc = pp_key; if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT, p_alg_enc, PFKEY_UNUNIT64(p_key_enc_len)) < 0) { yyerror(ipsec_strerror()); return -1; } } ; auth_key: /* empty */ | key_string { p_key_auth_len = yylval.val.len; p_key_auth = pp_key; if (ipsec_check_keylen(SADB_EXT_SUPPORTED_AUTH, p_alg_auth, PFKEY_UNUNIT64(p_key_auth_len)) < 0) { yyerror(ipsec_strerror()); return -1; } } ; key_string: QUOTEDSTRING { if ((pp_key = malloc(yylval.val.len)) == 0) return -1; memcpy(pp_key, yylval.val.buf, yylval.val.len); } | HEXSTRING { caddr_t bp; caddr_t yp = yylval.val.buf; if ((pp_key = malloc(yylval.val.len)) == 0) return -1; memset(pp_key, 0, yylval.val.len); bp = pp_key; while (*yp) { *bp = (ATOX(yp[0]) << 4) | ATOX(yp[1]); yp += 2, bp++; } } ; /* lifetime */ lifetime_hard: /* empty */ | F_LIFETIME_HARD DECSTRING { p_lt_hard = yylval.num; } ; lifetime_soft: /* empty */ | F_LIFETIME_SOFT DECSTRING { p_lt_soft = yylval.num; } ; ip_address: IP4_ADDRESS { struct sockaddr_in *in; u_int sa_len = yylval.val.len; if ((in = (struct sockaddr_in *)malloc(sa_len)) == 0) return -1; memset((caddr_t)in, 0, sa_len); in->sin_family = PF_INET; in->sin_len = sa_len; (void)inet_pton(PF_INET, yylval.val.buf, &in->sin_addr); pp_addr = (struct sockaddr *)in; } | IP6_ADDRESS { #ifdef INET6 struct sockaddr_in6 *in6; u_int sa_len = yylval.val.len; if ((in6 = (struct sockaddr_in6 *)malloc(sa_len)) == 0) return -1; memset((caddr_t)in6, 0, sa_len); in6->sin6_family = PF_INET6; in6->sin6_len = sa_len; (void)inet_pton(PF_INET6, yylval.val.buf, &in6->sin6_addr); pp_addr = (struct sockaddr *)in6; #else yyerror("IPv6 address not supported"); #endif } ; prefix: /* empty */ | PREFIX { pp_prefix = yylval.num; } ; port: /* empty */ | PORT { pp_port = htons(yylval.num); } ; /* definition about command for SPD management */ /* spdadd */ spdadd_command: SPDADD { p_type = yylval.num; p_satype = SADB_SATYPE_UNSPEC; } src_spec dst_spec upper_spec policy_spec EOT ; policy_spec: F_POLICY policy_requests { int len; if ((len = ipsec_get_policylen($2.val.buf)) < 0) { yyerror(ipsec_strerror()); return -1; } if ((p_policy = malloc(len)) == NULL) { yyerror("malloc"); return -1; } if ((len = ipsec_set_policy(p_policy, len, $2.val.buf)) < 0) { yyerror(ipsec_strerror()); free(p_policy); p_policy = NULL; return -1; } p_policy_len += len; } ; policy_requests: /* empty */ | PL_REQUESTS { $$ = $1; } ; spddelete_command: SPDDELETE { p_type = yylval.num; p_satype = SADB_SATYPE_UNSPEC; } src_spec dst_spec upper_spec EOT ; spddump_command: SPDDUMP { p_type = yylval.num; p_satype = SADB_SATYPE_UNSPEC; } EOT ; spdflush_command: SPDFLUSH { p_type = yylval.num; p_satype = SADB_SATYPE_UNSPEC; } EOT ; %% int setkeymsg() { struct sadb_msg m_msg; m_msg.sadb_msg_version = PF_KEY_V2; m_msg.sadb_msg_type = p_type; m_msg.sadb_msg_errno = 0; m_msg.sadb_msg_satype = p_satype; m_msg.sadb_msg_reserved = 0; m_msg.sadb_msg_seq = 0; m_msg.sadb_msg_pid = getpid(); m_len = sizeof(struct sadb_msg); memcpy(m_buf, &m_msg, m_len); switch (p_type) { case SADB_FLUSH: case SADB_DUMP: break; case SADB_ADD: /* set encryption algorithm, if present. */ if (p_satype != SADB_X_SATYPE_IPCOMP && p_alg_enc != SADB_EALG_NONE) { struct sadb_key m_key; m_key.sadb_key_len = PFKEY_UNIT64(sizeof(m_key) + PFKEY_ALIGN8(p_key_enc_len)); m_key.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; m_key.sadb_key_bits = p_key_enc_len * 8; m_key.sadb_key_reserved = 0; setvarbuf(&m_len, (struct sadb_ext *)&m_key, sizeof(m_key), (caddr_t)p_key_enc, p_key_enc_len); } /* set authentication algorithm, if present. */ if (p_alg_auth != SADB_AALG_NONE) { struct sadb_key m_key; m_key.sadb_key_len = PFKEY_UNIT64(sizeof(m_key) + PFKEY_ALIGN8(p_key_auth_len)); m_key.sadb_key_exttype = SADB_EXT_KEY_AUTH; m_key.sadb_key_bits = p_key_auth_len * 8; m_key.sadb_key_reserved = 0; setvarbuf(&m_len, (struct sadb_ext *)&m_key, sizeof(m_key), (caddr_t)p_key_auth, p_key_auth_len); } /* set lifetime for HARD */ if (p_lt_hard != 0) { struct sadb_lifetime m_lt; u_int len = sizeof(struct sadb_lifetime); m_lt.sadb_lifetime_len = PFKEY_UNIT64(len); m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; m_lt.sadb_lifetime_allocations = 0; m_lt.sadb_lifetime_bytes = 0; m_lt.sadb_lifetime_addtime = p_lt_hard; m_lt.sadb_lifetime_usetime = 0; memcpy(m_buf + m_len, &m_lt, len); m_len += len; } /* set lifetime for SOFT */ if (p_lt_soft != 0) { struct sadb_lifetime m_lt; u_int len = sizeof(struct sadb_lifetime); m_lt.sadb_lifetime_len = PFKEY_UNIT64(len); m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; m_lt.sadb_lifetime_allocations = 0; m_lt.sadb_lifetime_bytes = 0; m_lt.sadb_lifetime_addtime = p_lt_soft; m_lt.sadb_lifetime_usetime = 0; memcpy(m_buf + m_len, &m_lt, len); m_len += len; } /* FALLTHROUGH */ case SADB_DELETE: case SADB_GET: { struct sadb_sa m_sa; struct sadb_address m_addr; u_int len; len = sizeof(struct sadb_sa); m_sa.sadb_sa_len = PFKEY_UNIT64(len); m_sa.sadb_sa_exttype = SADB_EXT_SA; m_sa.sadb_sa_spi = htonl(p_spi); m_sa.sadb_sa_replay = p_replay; m_sa.sadb_sa_state = 0; m_sa.sadb_sa_auth = p_alg_auth; m_sa.sadb_sa_encrypt = p_alg_enc; m_sa.sadb_sa_flags = p_ext; memcpy(m_buf + m_len, &m_sa, len); m_len += len; /* set proxy, if present. */ if (p_proxy != 0) { m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + PFKEY_ALIGN8(p_proxy->sa_len)); m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; m_addr.sadb_address_proto = 0; m_addr.sadb_address_prefixlen = (p_proxy->sa_family == PF_INET ? 32 : 128); m_addr.sadb_address_reserved = 0; setvarbuf(&m_len, (struct sadb_ext *)&m_addr, sizeof(m_addr), (caddr_t)p_proxy, p_proxy->sa_len); } /* set src */ m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + PFKEY_ALIGN8(p_src->sa_len)); m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; m_addr.sadb_address_proto = p_upper; m_addr.sadb_address_prefixlen = (p_prefs != ~0 ? p_prefs : (p_src->sa_family == PF_INET ? 32 : 128)); m_addr.sadb_address_reserved = 0; setvarbuf(&m_len, (struct sadb_ext *)&m_addr, sizeof(m_addr), (caddr_t)p_src, p_src->sa_len); /* set dst */ m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + PFKEY_ALIGN8(p_dst->sa_len)); m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST; m_addr.sadb_address_proto = p_upper; m_addr.sadb_address_prefixlen = (p_prefd != ~0 ? p_prefd : (p_dst->sa_family == PF_INET ? 32 : 128)); m_addr.sadb_address_reserved = 0; setvarbuf(&m_len, (struct sadb_ext *)&m_addr, sizeof(m_addr), (caddr_t)p_dst, p_dst->sa_len); } break; /* for SPD management */ case SADB_X_SPDFLUSH: case SADB_X_SPDDUMP: break; case SADB_X_SPDADD: { ((struct sadb_x_policy *)p_policy)->sadb_x_policy_len = PFKEY_UNIT64(p_policy_len); memcpy(m_buf + m_len, p_policy, p_policy_len); m_len += p_policy_len; free(p_policy); p_policy = NULL; } /* FALLTHROUGH */ case SADB_X_SPDDELETE: { struct sadb_address m_addr; /* set src */ m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + PFKEY_ALIGN8(p_src->sa_len)); m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; m_addr.sadb_address_proto = p_upper; m_addr.sadb_address_prefixlen = (p_prefs != ~0 ? p_prefs : (p_src->sa_family == PF_INET ? 32 : 128)); m_addr.sadb_address_reserved = 0; setvarbuf(&m_len, (struct sadb_ext *)&m_addr, sizeof(m_addr), (caddr_t)p_src, p_src->sa_len); /* set dst */ m_addr.sadb_address_len = PFKEY_UNIT64(sizeof(m_addr) + PFKEY_ALIGN8(p_dst->sa_len)); m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST; m_addr.sadb_address_proto = p_upper; m_addr.sadb_address_prefixlen = (p_prefd != ~0 ? p_prefd : (p_dst->sa_family == PF_INET ? 32 : 128)); m_addr.sadb_address_reserved = 0; setvarbuf(&m_len, (struct sadb_ext *)&m_addr, sizeof(m_addr), (caddr_t)p_dst, p_dst->sa_len); } break; } ((struct sadb_msg *)m_buf)->sadb_msg_len = PFKEY_UNIT64(m_len); return 0; } static int setvarbuf(off, ebuf, elen, vbuf, vlen) caddr_t vbuf; struct sadb_ext *ebuf; int *off, elen, vlen; { memset(m_buf + *off, 0, PFKEY_UNUNIT64(ebuf->sadb_ext_len)); memcpy(m_buf + *off, (caddr_t)ebuf, elen); memcpy(m_buf + *off + elen, vbuf, vlen); (*off) += PFKEY_ALIGN8(elen + vlen); return 0; } void parse_init() { p_type = 0; p_spi = 0; p_src = 0, p_dst = 0, p_proxy = 0; p_ports = p_portd = 0; p_prefs = p_prefd = 0; p_upper = 0; p_satype = 0; p_ext = SADB_X_EXT_NONE; p_alg_enc = SADB_EALG_NONE; p_alg_auth = SADB_AALG_NONE; p_replay = 0; p_key_enc_len = p_key_auth_len = 0; p_key_enc = p_key_auth = 0; p_lt_hard = p_lt_soft = 0; p_policy_len = 0; p_policy = NULL; memset(cmdarg, 0, sizeof(cmdarg)); return; } void free_buffer() { if (p_src) free(p_src); if (p_dst) free(p_dst); if (p_proxy) free(p_proxy); if (p_key_enc) free(p_key_enc); if (p_key_auth) free(p_key_auth); return; }