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$"); 54122107Sume 5555505Sshin#include <sys/types.h> 5655505Sshin#include <sys/param.h> 5755505Sshin#include <sys/socket.h> 5855505Sshin 5955505Sshin#include <netinet/in.h> 60171135Sgnn#include <netipsec/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 yylex(void); 9255505Sshin 93122107Sumeextern char *__libipsecyytext; /*XXX*/ 94122107Sume 9555505Sshin%} 9655505Sshin 9755505Sshin%union { 9855505Sshin u_int num; 9955505Sshin struct _val { 10055505Sshin int len; 10155505Sshin char *buf; 10255505Sshin } val; 10355505Sshin} 10455505Sshin 10562583Sitojun%token DIR ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY 10655505Sshin%token IPADDRESS 10755505Sshin%token ME ANY 10855505Sshin%token SLASH HYPHEN 10955505Sshin%type <num> DIR ACTION PROTOCOL MODE LEVEL 11062583Sitojun%type <val> IPADDRESS LEVEL_SPECIFY 11155505Sshin 11255505Sshin%% 11355505Sshinpolicy_spec 11455505Sshin : DIR ACTION 11555505Sshin { 11655505Sshin p_dir = $1; 11755505Sshin p_type = $2; 11855505Sshin 11955505Sshin if (init_x_policy()) 12055505Sshin return -1; 12155505Sshin } 12255505Sshin rules 12362583Sitojun | DIR 12462583Sitojun { 12562583Sitojun p_dir = $1; 12662583Sitojun p_type = 0; /* ignored it by kernel */ 12762583Sitojun 12862583Sitojun if (init_x_policy()) 12962583Sitojun return -1; 13062583Sitojun } 13155505Sshin ; 13255505Sshin 13355505Sshinrules 13455505Sshin : /*NOTHING*/ 13555505Sshin | rules rule { 13655505Sshin if (rule_check() < 0) 13755505Sshin return -1; 13855505Sshin 13955505Sshin if (set_x_request(p_src, p_dst) < 0) 14055505Sshin return -1; 14155505Sshin 14255505Sshin policy_parse_request_init(); 14355505Sshin } 14455505Sshin ; 14555505Sshin 14655505Sshinrule 14755505Sshin : protocol SLASH mode SLASH addresses SLASH level 14855505Sshin | protocol SLASH mode SLASH addresses SLASH 14955505Sshin | protocol SLASH mode SLASH addresses 15055505Sshin | protocol SLASH mode SLASH 15155505Sshin | protocol SLASH mode SLASH SLASH level 15255505Sshin | protocol SLASH mode 15355505Sshin | protocol SLASH { 15462583Sitojun __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; 15555505Sshin return -1; 15655505Sshin } 15755505Sshin | protocol { 15862583Sitojun __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; 15955505Sshin return -1; 16055505Sshin } 16155505Sshin ; 16255505Sshin 16355505Sshinprotocol 16455505Sshin : PROTOCOL { p_protocol = $1; } 16555505Sshin ; 16655505Sshin 16755505Sshinmode 16855505Sshin : MODE { p_mode = $1; } 16955505Sshin ; 17055505Sshin 17155505Sshinlevel 17262583Sitojun : LEVEL { 17362583Sitojun p_level = $1; 17462583Sitojun p_reqid = 0; 17562583Sitojun } 17662583Sitojun | LEVEL_SPECIFY { 17762583Sitojun p_level = IPSEC_LEVEL_UNIQUE; 17862583Sitojun p_reqid = atol($1.buf); /* atol() is good. */ 17962583Sitojun } 18055505Sshin ; 18155505Sshin 18255505Sshinaddresses 18355505Sshin : IPADDRESS { 18455505Sshin p_src = parse_sockaddr(&$1); 18555505Sshin if (p_src == NULL) 18655505Sshin return -1; 18755505Sshin } 18855505Sshin HYPHEN 18955505Sshin IPADDRESS { 19055505Sshin p_dst = parse_sockaddr(&$4); 19155505Sshin if (p_dst == NULL) 19255505Sshin return -1; 19355505Sshin } 19455505Sshin | ME HYPHEN ANY { 19555505Sshin if (p_dir != IPSEC_DIR_OUTBOUND) { 19662583Sitojun __ipsec_errcode = EIPSEC_INVAL_DIR; 19755505Sshin return -1; 19855505Sshin } 19955505Sshin } 20055505Sshin | ANY HYPHEN ME { 20155505Sshin if (p_dir != IPSEC_DIR_INBOUND) { 20262583Sitojun __ipsec_errcode = EIPSEC_INVAL_DIR; 20355505Sshin return -1; 20455505Sshin } 20555505Sshin } 20655505Sshin /* 20755505Sshin | ME HYPHEN ME 20855505Sshin */ 20955505Sshin ; 21055505Sshin 21155505Sshin%% 21255505Sshin 21355505Sshinvoid 21455505Sshinyyerror(msg) 21555505Sshin char *msg; 21655505Sshin{ 21762583Sitojun fprintf(stderr, "libipsec: %s while parsing \"%s\"\n", 21862583Sitojun msg, __libipsecyytext); 21962583Sitojun 22055505Sshin return; 22155505Sshin} 22255505Sshin 22355505Sshinstatic struct sockaddr * 22455505Sshinparse_sockaddr(buf) 22555505Sshin struct _val *buf; 22655505Sshin{ 22755505Sshin struct addrinfo hints, *res; 22855505Sshin char *serv = NULL; 22955505Sshin int error; 23055505Sshin struct sockaddr *newaddr = NULL; 23155505Sshin 23255505Sshin memset(&hints, 0, sizeof(hints)); 23355505Sshin hints.ai_family = PF_UNSPEC; 23455505Sshin hints.ai_flags = AI_NUMERICHOST; 23555505Sshin error = getaddrinfo(buf->buf, serv, &hints, &res); 23662583Sitojun if (error != 0) { 23762583Sitojun yyerror("invalid IP address"); 23862583Sitojun __ipsec_set_strerror(gai_strerror(error)); 23955505Sshin return NULL; 24055505Sshin } 24155505Sshin 24255505Sshin if (res->ai_addr == NULL) { 24362583Sitojun yyerror("invalid IP address"); 24462583Sitojun __ipsec_set_strerror(gai_strerror(error)); 24555505Sshin return NULL; 24655505Sshin } 24755505Sshin 24855505Sshin newaddr = malloc(res->ai_addr->sa_len); 24955505Sshin if (newaddr == NULL) { 25062583Sitojun __ipsec_errcode = EIPSEC_NO_BUFS; 25155505Sshin freeaddrinfo(res); 25255505Sshin return NULL; 25355505Sshin } 25455505Sshin memcpy(newaddr, res->ai_addr, res->ai_addr->sa_len); 25555505Sshin 25655505Sshin freeaddrinfo(res); 25755505Sshin 25862583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 25955505Sshin return newaddr; 26055505Sshin} 26155505Sshin 26255505Sshinstatic int 26355505Sshinrule_check() 26455505Sshin{ 26555505Sshin if (p_type == IPSEC_POLICY_IPSEC) { 26655505Sshin if (p_protocol == IPPROTO_IP) { 26762583Sitojun __ipsec_errcode = EIPSEC_NO_PROTO; 26855505Sshin return -1; 26955505Sshin } 27055505Sshin 27155505Sshin if (p_mode != IPSEC_MODE_TRANSPORT 27255505Sshin && p_mode != IPSEC_MODE_TUNNEL) { 27362583Sitojun __ipsec_errcode = EIPSEC_INVAL_MODE; 27455505Sshin return -1; 27555505Sshin } 27655505Sshin 27755505Sshin if (p_src == NULL && p_dst == NULL) { 27855505Sshin if (p_mode != IPSEC_MODE_TRANSPORT) { 27962583Sitojun __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 28055505Sshin return -1; 28155505Sshin } 28255505Sshin } 28355505Sshin else if (p_src->sa_family != p_dst->sa_family) { 28462583Sitojun __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; 28555505Sshin return -1; 28655505Sshin } 28755505Sshin } 28855505Sshin 28962583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 29055505Sshin return 0; 29155505Sshin} 29255505Sshin 29355505Sshinstatic int 29455505Sshininit_x_policy() 29555505Sshin{ 29655505Sshin struct sadb_x_policy *p; 29755505Sshin 29855505Sshin tlen = sizeof(struct sadb_x_policy); 29955505Sshin 30055505Sshin pbuf = malloc(tlen); 30155505Sshin if (pbuf == NULL) { 30262583Sitojun __ipsec_errcode = EIPSEC_NO_BUFS; 30355505Sshin return -1; 30455505Sshin } 305122107Sume memset(pbuf, 0, tlen); 30655505Sshin p = (struct sadb_x_policy *)pbuf; 30755505Sshin p->sadb_x_policy_len = 0; /* must update later */ 30855505Sshin p->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 30955505Sshin p->sadb_x_policy_type = p_type; 31055505Sshin p->sadb_x_policy_dir = p_dir; 311122107Sume p->sadb_x_policy_id = 0; 312122107Sume 31355505Sshin offset = tlen; 31455505Sshin 31562583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 31655505Sshin return 0; 31755505Sshin} 31855505Sshin 31955505Sshinstatic int 32055505Sshinset_x_request(src, dst) 32155505Sshin struct sockaddr *src, *dst; 32255505Sshin{ 32355505Sshin struct sadb_x_ipsecrequest *p; 32455505Sshin int reqlen; 32555505Sshin 32655505Sshin reqlen = sizeof(*p) 32755505Sshin + (src ? src->sa_len : 0) 32855505Sshin + (dst ? dst->sa_len : 0); 32955505Sshin tlen += reqlen; /* increment to total length */ 33055505Sshin 33155505Sshin pbuf = realloc(pbuf, tlen); 33255505Sshin if (pbuf == NULL) { 33362583Sitojun __ipsec_errcode = EIPSEC_NO_BUFS; 33455505Sshin return -1; 33555505Sshin } 33655505Sshin p = (struct sadb_x_ipsecrequest *)&pbuf[offset]; 33755505Sshin p->sadb_x_ipsecrequest_len = reqlen; 33855505Sshin p->sadb_x_ipsecrequest_proto = p_protocol; 33955505Sshin p->sadb_x_ipsecrequest_mode = p_mode; 34055505Sshin p->sadb_x_ipsecrequest_level = p_level; 34162583Sitojun p->sadb_x_ipsecrequest_reqid = p_reqid; 34255505Sshin offset += sizeof(*p); 34355505Sshin 34455505Sshin if (set_sockaddr(src) || set_sockaddr(dst)) 34555505Sshin return -1; 34655505Sshin 34762583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 34855505Sshin return 0; 34955505Sshin} 35055505Sshin 35155505Sshinstatic int 35255505Sshinset_sockaddr(addr) 35355505Sshin struct sockaddr *addr; 35455505Sshin{ 35555505Sshin if (addr == NULL) { 35662583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 35755505Sshin return 0; 35855505Sshin } 35955505Sshin 36055505Sshin /* tlen has already incremented */ 36155505Sshin 36255505Sshin memcpy(&pbuf[offset], addr, addr->sa_len); 36355505Sshin 36455505Sshin offset += addr->sa_len; 36555505Sshin 36662583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 36755505Sshin return 0; 36855505Sshin} 36955505Sshin 37055505Sshinstatic void 37155505Sshinpolicy_parse_request_init() 37255505Sshin{ 37355505Sshin p_protocol = IPPROTO_IP; 37455505Sshin p_mode = IPSEC_MODE_ANY; 37555505Sshin p_level = IPSEC_LEVEL_DEFAULT; 37662583Sitojun p_reqid = 0; 37755505Sshin if (p_src != NULL) { 37855505Sshin free(p_src); 37955505Sshin p_src = NULL; 38055505Sshin } 38155505Sshin if (p_dst != NULL) { 38255505Sshin free(p_dst); 38355505Sshin p_dst = NULL; 38455505Sshin } 38555505Sshin 38655505Sshin return; 38755505Sshin} 38855505Sshin 38955505Sshinstatic caddr_t 39055505Sshinpolicy_parse(msg, msglen) 39155505Sshin char *msg; 39255505Sshin int msglen; 39355505Sshin{ 39455505Sshin int error; 39555505Sshin pbuf = NULL; 39655505Sshin tlen = 0; 39755505Sshin 39855505Sshin /* initialize */ 39955505Sshin p_dir = IPSEC_DIR_INVALID; 40055505Sshin p_type = IPSEC_POLICY_DISCARD; 40155505Sshin policy_parse_request_init(); 40255505Sshin __policy__strbuffer__init__(msg); 40355505Sshin 40455505Sshin error = yyparse(); /* it must be set errcode. */ 405122107Sume __policy__strbuffer__free__(); 406122107Sume 40755505Sshin if (error) { 40855505Sshin if (pbuf != NULL) 40955505Sshin free(pbuf); 41055505Sshin return NULL; 41155505Sshin } 41255505Sshin 41355505Sshin /* update total length */ 41455505Sshin ((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen); 41555505Sshin 41662583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 41755505Sshin 41855505Sshin return pbuf; 41955505Sshin} 42055505Sshin 42155505Sshincaddr_t 42255505Sshinipsec_set_policy(msg, msglen) 42355505Sshin char *msg; 42455505Sshin int msglen; 42555505Sshin{ 42655505Sshin caddr_t policy; 42755505Sshin 42855505Sshin policy = policy_parse(msg, msglen); 42955505Sshin if (policy == NULL) { 43062583Sitojun if (__ipsec_errcode == EIPSEC_NO_ERROR) 43162583Sitojun __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 43255505Sshin return NULL; 43355505Sshin } 43455505Sshin 43562583Sitojun __ipsec_errcode = EIPSEC_NO_ERROR; 43655505Sshin return policy; 43755505Sshin} 43855505Sshin 439