%{ /* * Copyright (c) 2001 Ian Freislich * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * $Id: parser.y,v 1.6 2003/01/24 12:01:25 ianf Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "popd.h" int yylex(void); static struct radius_s *radius = NULL; extern struct config config; int yyline = 0; %} %union { char text[1024]; int num; }; %token ADDRESS_FAMILY %token AUTHENTICATION %token AUTODELETE %token CHECK_PASSWORDS %token COMMAND_LOGGING %token DELIVERY_TIME %token DEBUG_MODE %token DISABLE_TOP %token DISABLE_UIDL %token FALSIFY_UIDL %token FORMAT %token HASH_DEPTH %token FASCIST_LOGGING %token INACTIVITY_TIMEOUT %token INET4 %token INET6 %token INTERACTIVE_DEBUG %token ISFALSE %token ISTRUE %token LISTEN %token LOCAL_USERS %token MAIL %token MAILBOX %token MAILDIR %token MAILDIRCOMPAT %token MAILIDX %token MESSAGE_SIZE %token POP3_PROXY %token PROXY %token PROXY_ADDRESS %token PROXY_PORT %token PRIVATE_KEY %token RADIUS %token RADIUS_PORT %token R_TIMEOUT %token SORT_BY %token SPOOL %token SSL %token SSL_BOTH %token SSL_MODE %token SSL_PROXY %token SSL_SERVER %token TRIES %token UNSPEC %token USER %token VIRTUAL_SERVER %token WIRE_FORMAT %token NUMBER %token ADDRESS %token APOP_SECRETS %token BULLETINS %token CERTIFICATE %token DEFAULT_REALM %token ETC_DIRECTORY %token EXPIRE_AFTER %token HOST %token IPADDR %token IPPORT %token PORT %token PRIVATE_KEY %token REMOVE_AFTER %token SECRET %token VIRTUAL_PASSWORDS %% config: global next_global ; global: DEBUG_MODE ISTRUE ';' { config.debug = TRUE; } | DEBUG_MODE ISFALSE ';' { config.debug = FALSE; } | BULLETINS ';' { config.bulletindir = xmalloc(strlen(yylval.text) + 1); strcpy(config.bulletindir, yylval.text); } | DEFAULT_REALM ';' { config.defaultrealm = xmalloc(strlen(yylval.text) + 1); strcpy(config.defaultrealm, yylval.text); } | DISABLE_UIDL ISTRUE ';' { config.flags &= ~MAILBOX_F_ENABLEUIDL; } | DISABLE_UIDL ISFALSE ';' { config.flags |= MAILBOX_F_ENABLEUIDL; } | DISABLE_TOP ISTRUE ';' { config.flags &= ~MAILBOX_F_ENABLETOP; } | DISABLE_TOP ISFALSE ';' { config.flags |= MAILBOX_F_ENABLETOP; } | AUTODELETE ISTRUE ';' { config.flags |= MAILBOX_F_AUTODELETE; } | AUTODELETE ISFALSE ';' { config.flags &= ~MAILBOX_F_AUTODELETE; } | FASCIST_LOGGING ISTRUE ';' { config.flags |= MAILBOX_F_FASCIST_LOG; } | FASCIST_LOGGING ISFALSE ';' { config.flags &= ~MAILBOX_F_FASCIST_LOG; } | COMMAND_LOGGING ISTRUE ';' { config.flags |= MAILBOX_F_CMD_LOG; } | COMMAND_LOGGING ISFALSE ';' { config.flags &= ~MAILBOX_F_CMD_LOG; } | LOCAL_USERS ISTRUE ';' { config.localuser = TRUE; } | LOCAL_USERS ISFALSE ';' { config.localuser = FALSE; } | ETC_DIRECTORY ';' { config.etcdir = xmalloc(strlen(yylval.text) + 1); strcpy(config.etcdir, yylval.text); } | INACTIVITY_TIMEOUT NUMBER ';' { config.timeout = yylval.num; } | INTERACTIVE_DEBUG ISTRUE ';' { config.daemonise = FALSE; } | INTERACTIVE_DEBUG ISFALSE ';' { config.daemonise = TRUE; } | VIRTUAL_SERVER ISTRUE ';' { config.virtual = TRUE; } | VIRTUAL_SERVER ISFALSE ';' { config.virtual = FALSE; } | USER ';' { config.user = xmalloc(strlen(yylval.text) + 1); strcpy(config.user, yylval.text); } | AUTHENTICATION '{' authentication next_authentication '}' { } | LISTEN '{' listen next_listen '}' { } | MAIL '{' mail next_mail '}' { } | POP3_PROXY '{' proxy next_proxy '}' { } | SSL '{' ssl next_ssl '}' { } ; listen: ADDRESS_FAMILY INET4 ';' { config.family = PF_INET; } | ADDRESS_FAMILY INET6 ';' { config.family = PF_INET6; } | ADDRESS_FAMILY UNSPEC ';' { config.family = PF_UNSPEC; } | port | address ; address: ADDRESS ';' { #ifdef USE_IPV6 struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = config.family; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(yylval.text, NULL, &hints, &res)) #else if (!inet_aton(yylval.text, &config.bind_address)) #endif yyerror("Invalid address"); #ifdef USE_IPV6 freeaddrinfo(res); config.bind_address = xmalloc(strlen(yylval.text) + 1); strcpy(config.bind_address, yylval.text); #endif } ; port: PORT ';' { #ifdef USE_IPV6 struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = config.family; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(NULL, yylval.text, &hints, &res)) yyerror("Invalid port number"); freeaddrinfo(res); config.port = xmalloc(strlen(yylval.text) + 1); strcpy(config.port, yylval.text); #else config.port = htons(atoi(yylval.text)); #endif } ; authentication: CHECK_PASSWORDS ISTRUE ';' { config.pwcheck = TRUE; } | CHECK_PASSWORDS ISFALSE ';' { config.pwcheck = FALSE; } | APOP_SECRETS ';' { config.secrets = xmalloc(strlen(yylval.text) + 1); strcpy(config.secrets, yylval.text); } | VIRTUAL_PASSWORDS ';' { config.dbfile = xmalloc(strlen(yylval.text) + 1); strcpy(config.dbfile, yylval.text); } | RADIUS { if (radius == NULL) radius = xcalloc(1, sizeof(struct radius_s)); radius->port = -1; radius->tries = -1; radius->timeout = -1; } '{' radius next_radius '}' { struct servent *servent; int i; for (i = 0; config.radius && config.radius[i].host; i++); config.radius = xrealloc(config.radius, (i + 2) * sizeof(struct radius_s)); memcpy(&(config.radius[i]), radius, sizeof(struct radius_s)); if (config.radius[i].port == -1) { if ((servent = getservbyname("radius", "udp"))) { config.radius[i].port = ntohs(servent->s_port); } else { fprintf(stderr, "Couldn't get radius port from services\n"); exit(EX_PROTOCOL); } } if (config.radius[i].timeout == -1) config.radius[i].timeout = RADIUS_TIMEOUT; if (config.radius[i].tries == -1) config.radius[i].tries = RADIUS_TRIES; config.radius[i + 1].host = NULL; free(radius); radius = NULL; } ; proxy: PROXY ISTRUE ';' { config.proxy = TRUE; } | PROXY ISFALSE ';' { config.proxy = FALSE; } | PROXY_PORT NUMBER ';' { config.proxy_port = htons(yylval.num); } | PROXY_ADDRESS IPADDR ';' { if (!inet_aton(yylval.text, &config.proxy_addr)) yyerror("Invalid address"); } ; radius: HOST ';' { radius->host = xmalloc(strlen(yylval.text) + 1); strcpy(radius->host, yylval.text); } | PORT ';' { radius->port = atoi(yylval.text); } | SECRET ';' { radius->secret = xmalloc(strlen(yylval.text) + 1); strcpy(radius->secret, yylval.text); } | R_TIMEOUT NUMBER ';' { radius->timeout = yylval.num; } | TRIES NUMBER ';' { radius->tries = yylval.num; } ; mail: BULLETINS ';' { config.bulletindir = xmalloc(strlen(yylval.text) + 1); strcpy(config.bulletindir, yylval.text); } | SPOOL ';' { config.maildir = xmalloc(strlen(yylval.text) + 1); strcpy(config.maildir, yylval.text); } | FORMAT MAILBOX ';' { config.flags &= ~MAILBOX_F_MAILMASK; config.flags |= MAILBOX_F_MAILBOX; } | FORMAT MAILDIR ';' { config.flags &= ~MAILBOX_F_MAILMASK; config.flags |= MAILBOX_F_MAILDIR; } | FORMAT MAILDIRCOMPAT ';' { config.flags &= ~MAILBOX_F_MAILMASK; config.flags |= MAILBOX_F_MAILDIRCOMPAT; } | FORMAT MAILIDX ';' { config.flags &= ~MAILBOX_F_MAILMASK; config.flags |= MAILBOX_F_MAILIDX; } | HASH_DEPTH NUMBER ';' { config.hashdepth = yylval.num; } | WIRE_FORMAT ISTRUE ';' { config.flags |= MAILBOX_F_WIREFORMAT; } | WIRE_FORMAT ISFALSE ';' { config.flags &= ~MAILBOX_F_WIREFORMAT; } | EXPIRE_AFTER ';' { config.expire = atosec(yylval.text); } | REMOVE_AFTER ';' { config.remove = atosec(yylval.text); } | FALSIFY_UIDL ISTRUE ';' { config.flags |= MAILBOX_F_FALSEUIDL; } | FALSIFY_UIDL ISFALSE ';' { config.flags &= ~MAILBOX_F_FALSEUIDL; } | AUTODELETE ISTRUE ';' { config.flags |= MAILBOX_F_AUTODELETE; } | AUTODELETE ISFALSE ';' { config.flags &= ~MAILBOX_F_AUTODELETE; } | SORT_BY DELIVERY_TIME ';' { config.flags &= ~MAILBOX_F_SORTMASK; config.flags |= MAILBOX_F_SORT_TIME; } | SORT_BY MESSAGE_SIZE ';' { config.flags &= ~MAILBOX_F_SORTMASK; config.flags |= MAILBOX_F_SORT_SIZE; } ; ssl: CERTIFICATE ';' { #ifdef USE_SSL config.ssl_cert = xmalloc(strlen(yylval.text) + 1); strcpy(config.ssl_cert, yylval.text); #endif } | PRIVATE_KEY ';' { #ifdef USE_SSL config.ssl_key = xmalloc(strlen(yylval.text) + 1); strcpy(config.ssl_key, yylval.text); #endif } | SSL_MODE SSL_SERVER ';' { #ifdef USE_SSL config.ssl_server = TRUE; config.ssl_proxy = FALSE; #endif } | SSL_MODE SSL_PROXY ';' { #ifdef USE_SSL config.ssl_server = FALSE; config.ssl_proxy = TRUE; #endif } | SSL_MODE SSL_BOTH ';' { #ifdef USE_SSL config.ssl_server = TRUE; config.ssl_proxy = TRUE; #endif } ; next_authentication: authentication next_authentication | ; next_global: global next_global | ; next_listen: listen next_listen | ; next_mail: mail next_mail | ; next_proxy: proxy next_proxy | ; next_radius: radius next_radius | ; next_ssl: ssl next_ssl | ; %% void yyerror(char *s) { syslog(LOG_NOTICE, "parser error: %s at line %d\n", s, yyline + 1); exit(EX_CONFIG); }