policy_parse.y revision 122107
1122107Sume/* $KAME: policy_parse.y,v 1.14 2003/06/27 03:39:20 itojun Exp $ */ 262583Sitojun 355505Sshin/* 455505Sshin * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 555505Sshin * All rights reserved. 655505Sshin * 755505Sshin * Redistribution and use in source and binary forms, with or without 855505Sshin * modification, are permitted provided that the following conditions 955505Sshin * are met: 1055505Sshin * 1. Redistributions of source code must retain the above copyright 1155505Sshin * notice, this list of conditions and the following disclaimer. 1255505Sshin * 2. Redistributions in binary form must reproduce the above copyright 1355505Sshin * notice, this list of conditions and the following disclaimer in the 1455505Sshin * documentation and/or other materials provided with the distribution. 1555505Sshin * 3. Neither the name of the project nor the names of its contributors 1655505Sshin * may be used to endorse or promote products derived from this software 1755505Sshin * without specific prior written permission. 1855505Sshin * 1955505Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2055505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2155505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2255505Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2355505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2455505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2555505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2655505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2755505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2855505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2955505Sshin * SUCH DAMAGE. 3055505Sshin */ 3155505Sshin 3255505Sshin/* 3355505Sshin * IN/OUT bound policy configuration take place such below: 3455505Sshin * in <policy> 3555505Sshin * out <policy> 3655505Sshin * 3755505Sshin * <policy> is one of following: 3855505Sshin * "discard", "none", "ipsec <requests>", "entrust", "bypass", 3955505Sshin * 4055505Sshin * The following requests are accepted as <requests>: 4155505Sshin * 4255505Sshin * protocol/mode/src-dst/level 4355505Sshin * protocol/mode/src-dst parsed as protocol/mode/src-dst/default 4455505Sshin * protocol/mode/src-dst/ parsed as protocol/mode/src-dst/default 4555505Sshin * protocol/transport parsed as protocol/mode/any-any/default 4655505Sshin * protocol/transport//level parsed as protocol/mode/any-any/level 4755505Sshin * 4855505Sshin * You can concatenate these requests with either ' '(single space) or '\n'. 4955505Sshin */ 5055505Sshin 5155505Sshin%{ 52122107Sume#include <sys/cdefs.h> 53122107Sume__FBSDID("$FreeBSD: head/lib/libipsec/policy_parse.y 122107 2003-11-05 09:41:23Z ume $"); 54122107Sume 5555505Sshin#include <sys/types.h> 5655505Sshin#include <sys/param.h> 5755505Sshin#include <sys/socket.h> 5855505Sshin 5955505Sshin#include <netinet/in.h> 6055505Sshin#include <netinet6/ipsec.h> 6155505Sshin 6255505Sshin#include <stdlib.h> 6355505Sshin#include <stdio.h> 6455505Sshin#include <string.h> 6555505Sshin#include <netdb.h> 6655505Sshin 6755505Sshin#include "ipsec_strerror.h" 6855505Sshin 6962583Sitojun#define ATOX(c) \ 7055505Sshin (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) )) 7155505Sshin 7255505Sshinstatic caddr_t pbuf = NULL; /* sadb_x_policy buffer */ 7355505Sshinstatic int tlen = 0; /* total length of pbuf */ 7455505Sshinstatic int offset = 0; /* offset of pbuf */ 7562583Sitojunstatic int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid; 7655505Sshinstatic struct sockaddr *p_src = NULL; 7755505Sshinstatic struct sockaddr *p_dst = NULL; 7855505Sshin 7962583Sitojunstruct _val; 8092917Sobrienextern void yyerror(char *msg); 8192917Sobrienstatic struct sockaddr *parse_sockaddr(struct _val *buf); 8292917Sobrienstatic int rule_check(void); 8392917Sobrienstatic int init_x_policy(void); 8492917Sobrienstatic int set_x_request(struct sockaddr *src, struct sockaddr *dst); 8592917Sobrienstatic int set_sockaddr(struct sockaddr *addr); 8692917Sobrienstatic void policy_parse_request_init(void); 8792917Sobrienstatic caddr_t policy_parse(char *msg, int msglen); 8855505Sshin 8992917Sobrienextern void __policy__strbuffer__init__(char *msg); 90122107Sumeextern void __policy__strbuffer__free__(void); 9192917Sobrienextern int yyparse(void); 9292917Sobrienextern int yylex(void); 9355505Sshin 94122107Sumeextern char *__libipsecyytext; /*XXX*/ 95122107Sume 9655505Sshin%} 9755505Sshin 9855505Sshin%union { 9955505Sshin u_int num; 10055505Sshin struct _val { 10155505Sshin int len; 10255505Sshin char *buf; 10355505Sshin } val; 10455505Sshin} 10555505Sshin 10662583Sitojun%token DIR ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY 10755505Sshin%token IPADDRESS 10855505Sshin%token ME ANY 10955505Sshin%token SLASH HYPHEN 11055505Sshin%type <num> DIR ACTION PROTOCOL MODE LEVEL 11162583Sitojun%type <val> IPADDRESS LEVEL_SPECIFY 11255505Sshin 11355505Sshin%% 11455505Sshinpolicy_spec 11555505Sshin : DIR ACTION 11655505Sshin { 11755505Sshin p_dir = $1; 11855505Sshin p_type = $2; 11955505Sshin 12055505Sshin if (init_x_policy()) 12155505Sshin return -1; 12255505Sshin } 12355505Sshin rules 12462583Sitojun | DIR 12562583Sitojun { 12662583Sitojun p_dir = $1; 12762583Sitojun p_type = 0; /* ignored it by kernel */ 12862583Sitojun 12962583Sitojun if (init_x_policy()) 13062583Sitojun return -1; 13162583Sitojun } 13255505Sshin ; 13355505Sshin 13455505Sshinrules 13555505Sshin : /*NOTHING*/ 13655505Sshin | rules rule { 13755505Sshin if (rule_check() < 0) 13855505Sshin return -1; 13955505Sshin 14055505Sshin if (set_x_request(p_src, p_dst) < 0) 14155505Sshin return -1; 14255505Sshin 14355505Sshin policy_parse_request_init(); 14455505Sshin } 14555505Sshin ; 14655505Sshin 14755505Sshinrule 14855505Sshin : protocol SLASH mode SLASH addresses SLASH level 14955505Sshin | protocol SLASH mode SLASH addresses SLASH 15055505Sshin | protocol SLASH mode SLASH addresses 15155505Sshin | protocol SLASH mode SLASH 15255505Sshin | protocol SLASH mode SLASH SLASH level 15355505Sshin | protocol SLASH mode 15455505Sshin | protocol SLASH { 15562583Sitojun __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; 15655505Sshin return -1; 15755505Sshin } 15855505Sshin | protocol { 15962583Sitojun __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; 16055505Sshin return -1; 16155505Sshin } 16255505Sshin ; 16355505Sshin 16455505Sshinprotocol 16555505Sshin : PROTOCOL { p_protocol = $1; } 16655505Sshin ; 16755505Sshin 16855505Sshinmode 16955505Sshin : MODE { p_mode = $1; } 17055505Sshin ; 17155505Sshin 17255505Sshinlevel 17362583Sitojun : LEVEL { 17462583Sitojun p_level = $1; 17562583Sitojun p_reqid = 0; 17662583Sitojun } 17762583Sitojun | LEVEL_SPECIFY { 17862583Sitojun p_level = IPSEC_LEVEL_UNIQUE; 17962583Sitojun p_reqid = atol($1.buf); /* atol() is good. */ 18062583Sitojun } 18155505Sshin ; 18255505Sshin 18355505Sshinaddresses 18455505Sshin : IPADDRESS { 18555505Sshin p_src = parse_sockaddr(&$1); 18655505Sshin if (p_src == NULL) 18755505Sshin return -1; 18855505Sshin } 18955505Sshin HYPHEN 19055505Sshin IPADDRESS { 19155505Sshin p_dst = parse_sockaddr(&$4); 19255505Sshin if (p_dst == NULL) 19355505Sshin return -1; 19455505Sshin } 19555505Sshin | ME HYPHEN ANY { 19655505Sshin if (p_dir != IPSEC_DIR_OUTBOUND) { 19762583Sitojun __ipsec_errcode = EIPSEC_INVAL_DIR; 19855505Sshin return -1; 19955505Sshin } 20055505Sshin } 20155505Sshin | ANY HYPHEN ME { 20255505Sshin if (p_dir != IPSEC_DIR_INBOUND) { 20362583Sitojun __ipsec_errcode = EIPSEC_INVAL_DIR; 20455505Sshin return -1; 20555505Sshin } 20655505Sshin } 20755505Sshin /* 20855505Sshin | ME HYPHEN ME 20955505Sshin */ 21055505Sshin ; 21155505Sshin 21255505Sshin%% 21355505Sshin 21455505Sshinvoid 21555505Sshinyyerror(msg) 21655505Sshin char *msg; 21755505Sshin{ 21862583Sitojun fprintf(stderr, "libipsec: %s while parsing \"%s\"\n", 21962583Sitojun msg, __libipsecyytext); 22062583Sitojun 22155505Sshin return; 22255505Sshin} 22355505Sshin 22455505Sshinstatic struct sockaddr * 22555505Sshinparse_sockaddr(buf) 22655505Sshin struct _val *buf; 22755505Sshin{ 22855505Sshin struct addrinfo hints, *res; 22955505Sshin char *serv = NULL; 23055505Sshin int error; 23155505Sshin struct sockaddr *newaddr = NULL; 23255505Sshin 23355505Sshin memset(&hints, 0, sizeof(hints)); 23455505Sshin hints.ai_family = PF_UNSPEC; 23555505Sshin hints.ai_flags = AI_NUMERICHOST; 23655505Sshin error = getaddrinfo(buf->buf, serv, &hints, &res); 23762583Sitojun if (error != 0) { 23862583Sitojun yyerror("invalid IP address"); 23962583Sitojun __ipsec_set_strerror(gai_strerror(error)); 24055505Sshin return NULL; 24155505Sshin } 24255505Sshin 24355505Sshin if (res->ai_addr == NULL) { 24462583Sitojun yyerror("invalid IP address"); 24562583Sitojun __ipsec_set_strerror(gai_strerror(error)); 24655505Sshin return NULL; 24755505Sshin } 24855505Sshin 24955505Sshin newaddr = malloc(res->ai_addr->sa_len); 25055505Sshin if (newaddr == NULL) { 25162583Sitojun __ipsec_errcode = EIPSEC_NO_BUFS; 25255505Sshin freeaddrinfo(res); 25355505Sshin return NULL; 25455505Sshin } 25555505Sshin memcpy(newaddr, res->ai_addr, res->ai_addr->sa_len); 25655505Sshin 25755505Sshin freeaddrinfo(res); 25855505Sshin 25962583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 26055505Sshin return newaddr; 26155505Sshin} 26255505Sshin 26355505Sshinstatic int 26455505Sshinrule_check() 26555505Sshin{ 26655505Sshin if (p_type == IPSEC_POLICY_IPSEC) { 26755505Sshin if (p_protocol == IPPROTO_IP) { 26862583Sitojun __ipsec_errcode = EIPSEC_NO_PROTO; 26955505Sshin return -1; 27055505Sshin } 27155505Sshin 27255505Sshin if (p_mode != IPSEC_MODE_TRANSPORT 27355505Sshin && p_mode != IPSEC_MODE_TUNNEL) { 27462583Sitojun __ipsec_errcode = EIPSEC_INVAL_MODE; 27555505Sshin return -1; 27655505Sshin } 27755505Sshin 27855505Sshin if (p_src == NULL && p_dst == NULL) { 27955505Sshin if (p_mode != IPSEC_MODE_TRANSPORT) { 28062583Sitojun __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 28155505Sshin return -1; 28255505Sshin } 28355505Sshin } 28455505Sshin else if (p_src->sa_family != p_dst->sa_family) { 28562583Sitojun __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; 28655505Sshin return -1; 28755505Sshin } 28855505Sshin } 28955505Sshin 29062583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 29155505Sshin return 0; 29255505Sshin} 29355505Sshin 29455505Sshinstatic int 29555505Sshininit_x_policy() 29655505Sshin{ 29755505Sshin struct sadb_x_policy *p; 29855505Sshin 29955505Sshin tlen = sizeof(struct sadb_x_policy); 30055505Sshin 30155505Sshin pbuf = malloc(tlen); 30255505Sshin if (pbuf == NULL) { 30362583Sitojun __ipsec_errcode = EIPSEC_NO_BUFS; 30455505Sshin return -1; 30555505Sshin } 306122107Sume memset(pbuf, 0, tlen); 30755505Sshin p = (struct sadb_x_policy *)pbuf; 30855505Sshin p->sadb_x_policy_len = 0; /* must update later */ 30955505Sshin p->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 31055505Sshin p->sadb_x_policy_type = p_type; 31155505Sshin p->sadb_x_policy_dir = p_dir; 312122107Sume p->sadb_x_policy_id = 0; 313122107Sume 31455505Sshin offset = tlen; 31555505Sshin 31662583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 31755505Sshin return 0; 31855505Sshin} 31955505Sshin 32055505Sshinstatic int 32155505Sshinset_x_request(src, dst) 32255505Sshin struct sockaddr *src, *dst; 32355505Sshin{ 32455505Sshin struct sadb_x_ipsecrequest *p; 32555505Sshin int reqlen; 32655505Sshin 32755505Sshin reqlen = sizeof(*p) 32855505Sshin + (src ? src->sa_len : 0) 32955505Sshin + (dst ? dst->sa_len : 0); 33055505Sshin tlen += reqlen; /* increment to total length */ 33155505Sshin 33255505Sshin pbuf = realloc(pbuf, tlen); 33355505Sshin if (pbuf == NULL) { 33462583Sitojun __ipsec_errcode = EIPSEC_NO_BUFS; 33555505Sshin return -1; 33655505Sshin } 33755505Sshin p = (struct sadb_x_ipsecrequest *)&pbuf[offset]; 33855505Sshin p->sadb_x_ipsecrequest_len = reqlen; 33955505Sshin p->sadb_x_ipsecrequest_proto = p_protocol; 34055505Sshin p->sadb_x_ipsecrequest_mode = p_mode; 34155505Sshin p->sadb_x_ipsecrequest_level = p_level; 34262583Sitojun p->sadb_x_ipsecrequest_reqid = p_reqid; 34355505Sshin offset += sizeof(*p); 34455505Sshin 34555505Sshin if (set_sockaddr(src) || set_sockaddr(dst)) 34655505Sshin return -1; 34755505Sshin 34862583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 34955505Sshin return 0; 35055505Sshin} 35155505Sshin 35255505Sshinstatic int 35355505Sshinset_sockaddr(addr) 35455505Sshin struct sockaddr *addr; 35555505Sshin{ 35655505Sshin if (addr == NULL) { 35762583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 35855505Sshin return 0; 35955505Sshin } 36055505Sshin 36155505Sshin /* tlen has already incremented */ 36255505Sshin 36355505Sshin memcpy(&pbuf[offset], addr, addr->sa_len); 36455505Sshin 36555505Sshin offset += addr->sa_len; 36655505Sshin 36762583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 36855505Sshin return 0; 36955505Sshin} 37055505Sshin 37155505Sshinstatic void 37255505Sshinpolicy_parse_request_init() 37355505Sshin{ 37455505Sshin p_protocol = IPPROTO_IP; 37555505Sshin p_mode = IPSEC_MODE_ANY; 37655505Sshin p_level = IPSEC_LEVEL_DEFAULT; 37762583Sitojun p_reqid = 0; 37855505Sshin if (p_src != NULL) { 37955505Sshin free(p_src); 38055505Sshin p_src = NULL; 38155505Sshin } 38255505Sshin if (p_dst != NULL) { 38355505Sshin free(p_dst); 38455505Sshin p_dst = NULL; 38555505Sshin } 38655505Sshin 38755505Sshin return; 38855505Sshin} 38955505Sshin 39055505Sshinstatic caddr_t 39155505Sshinpolicy_parse(msg, msglen) 39255505Sshin char *msg; 39355505Sshin int msglen; 39455505Sshin{ 39555505Sshin int error; 39655505Sshin pbuf = NULL; 39755505Sshin tlen = 0; 39855505Sshin 39955505Sshin /* initialize */ 40055505Sshin p_dir = IPSEC_DIR_INVALID; 40155505Sshin p_type = IPSEC_POLICY_DISCARD; 40255505Sshin policy_parse_request_init(); 40355505Sshin __policy__strbuffer__init__(msg); 40455505Sshin 40555505Sshin error = yyparse(); /* it must be set errcode. */ 406122107Sume __policy__strbuffer__free__(); 407122107Sume 40855505Sshin if (error) { 40955505Sshin if (pbuf != NULL) 41055505Sshin free(pbuf); 41155505Sshin return NULL; 41255505Sshin } 41355505Sshin 41455505Sshin /* update total length */ 41555505Sshin ((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen); 41655505Sshin 41762583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 41855505Sshin 41955505Sshin return pbuf; 42055505Sshin} 42155505Sshin 42255505Sshincaddr_t 42355505Sshinipsec_set_policy(msg, msglen) 42455505Sshin char *msg; 42555505Sshin int msglen; 42655505Sshin{ 42755505Sshin caddr_t policy; 42855505Sshin 42955505Sshin policy = policy_parse(msg, msglen); 43055505Sshin if (policy == NULL) { 43162583Sitojun if (__ipsec_errcode == EIPSEC_NO_ERROR) 43262583Sitojun __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 43355505Sshin return NULL; 43455505Sshin } 43555505Sshin 43662583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 43755505Sshin return policy; 43855505Sshin} 43955505Sshin 440