1290931Srodrigc/* $OpenBSD: parse.y,v 1.18 2015/01/16 06:40:22 deraadt Exp $ */ 2290931Srodrigc/* $FreeBSD: stable/11/usr.sbin/ypldap/parse.y 330965 2018-03-15 02:25:28Z eadler $ */ 3290931Srodrigc 4290931Srodrigc/* 5290931Srodrigc * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 6290931Srodrigc * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org> 7290931Srodrigc * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 8290931Srodrigc * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org> 9290931Srodrigc * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> 10290931Srodrigc * Copyright (c) 2001 Markus Friedl. All rights reserved. 11290931Srodrigc * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 12290931Srodrigc * Copyright (c) 2001 Theo de Raadt. All rights reserved. 13290931Srodrigc * 14290931Srodrigc * Permission to use, copy, modify, and distribute this software for any 15290931Srodrigc * purpose with or without fee is hereby granted, provided that the above 16290931Srodrigc * copyright notice and this permission notice appear in all copies. 17290931Srodrigc * 18290931Srodrigc * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 19290931Srodrigc * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 20290931Srodrigc * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 21290931Srodrigc * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 22290931Srodrigc * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 23290931Srodrigc * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 24290931Srodrigc * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 25290931Srodrigc */ 26290931Srodrigc 27290931Srodrigc%{ 28290931Srodrigc#include <sys/types.h> 29290937Srodrigc#include <sys/param.h> 30290931Srodrigc#include <sys/time.h> 31290931Srodrigc#include <sys/queue.h> 32290931Srodrigc#include <sys/tree.h> 33290931Srodrigc#include <sys/socket.h> 34290931Srodrigc#include <sys/stat.h> 35290931Srodrigc 36290931Srodrigc#include <netinet/in.h> 37290931Srodrigc#include <arpa/inet.h> 38290931Srodrigc 39290931Srodrigc#include <ctype.h> 40290931Srodrigc#include <err.h> 41290931Srodrigc#include <errno.h> 42290931Srodrigc#include <event.h> 43290931Srodrigc#include <fcntl.h> 44290931Srodrigc#include <limits.h> 45290931Srodrigc#include <netdb.h> 46290931Srodrigc#include <pwd.h> 47290931Srodrigc#include <stdarg.h> 48290931Srodrigc#include <stdio.h> 49290931Srodrigc#include <stdlib.h> 50290931Srodrigc#include <string.h> 51290931Srodrigc#include <syslog.h> 52290931Srodrigc#include <unistd.h> 53290931Srodrigc 54290931Srodrigc#include "ypldap.h" 55290931Srodrigc 56290931SrodrigcTAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); 57290931Srodrigcstatic struct file { 58290931Srodrigc TAILQ_ENTRY(file) entry; 59290931Srodrigc FILE *stream; 60290931Srodrigc char *name; 61290931Srodrigc int lineno; 62290931Srodrigc int errors; 63290931Srodrigc} *file, *topfile; 64290931Srodrigcstruct file *pushfile(const char *, int); 65290931Srodrigcint popfile(void); 66290931Srodrigcint check_file_secrecy(int, const char *); 67290931Srodrigcint yyparse(void); 68290931Srodrigcint yylex(void); 69290931Srodrigcint yyerror(const char *, ...) 70290931Srodrigc __attribute__((__format__ (printf, 1, 2))) 71290931Srodrigc __attribute__((__nonnull__ (1))); 72290931Srodrigcint kw_cmp(const void *, const void *); 73290931Srodrigcint lookup(char *); 74290931Srodrigcint lgetc(int); 75290931Srodrigcint lungetc(int); 76290931Srodrigcint findeol(void); 77290931Srodrigc 78290931SrodrigcTAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 79290931Srodrigcstruct sym { 80290931Srodrigc TAILQ_ENTRY(sym) entry; 81290931Srodrigc int used; 82290931Srodrigc int persist; 83290931Srodrigc char *nam; 84290931Srodrigc char *val; 85290931Srodrigc}; 86290931Srodrigcint symset(const char *, const char *, int); 87290931Srodrigcchar *symget(const char *); 88290931Srodrigc 89290931Srodrigcstruct env *conf = NULL; 90290931Srodrigcstruct idm *idm = NULL; 91290931Srodrigcstatic int errors = 0; 92290931Srodrigc 93290931Srodrigctypedef struct { 94290931Srodrigc union { 95290931Srodrigc int64_t number; 96290931Srodrigc char *string; 97290931Srodrigc } v; 98290931Srodrigc int lineno; 99290931Srodrigc} YYSTYPE; 100290931Srodrigc 101290931Srodrigc%} 102290931Srodrigc 103290931Srodrigc%token SERVER FILTER ATTRIBUTE BASEDN BINDDN GROUPDN BINDCRED MAPS CHANGE DOMAIN PROVIDE 104290931Srodrigc%token USER GROUP TO EXPIRE HOME SHELL GECOS UID GID INTERVAL 105290931Srodrigc%token PASSWD NAME FIXED LIST GROUPNAME GROUPPASSWD GROUPGID MAP 106290931Srodrigc%token INCLUDE DIRECTORY CLASS PORT ERROR GROUPMEMBERS 107290931Srodrigc%token <v.string> STRING 108290931Srodrigc%token <v.number> NUMBER 109290931Srodrigc%type <v.number> opcode attribute 110290931Srodrigc%type <v.string> port 111290931Srodrigc 112290931Srodrigc%% 113290931Srodrigc 114290931Srodrigcgrammar : /* empty */ 115290931Srodrigc | grammar '\n' 116290931Srodrigc | grammar include '\n' 117290931Srodrigc | grammar varset '\n' 118290931Srodrigc | grammar directory '\n' 119290931Srodrigc | grammar main '\n' 120290931Srodrigc | grammar error '\n' { file->errors++; } 121290931Srodrigc ; 122290931Srodrigc 123290931Srodrigcnl : '\n' optnl 124290931Srodrigc ; 125290931Srodrigc 126290931Srodrigcoptnl : '\n' optnl 127290931Srodrigc | /* empty */ 128290931Srodrigc ; 129290931Srodrigc 130290931Srodrigc 131290931Srodrigcinclude : INCLUDE STRING { 132290931Srodrigc struct file *nfile; 133290931Srodrigc 134290931Srodrigc if ((nfile = pushfile($2, 0)) == NULL) { 135290931Srodrigc yyerror("failed to include file %s", $2); 136290931Srodrigc free($2); 137290931Srodrigc YYERROR; 138290931Srodrigc } 139290931Srodrigc free($2); 140290931Srodrigc 141290931Srodrigc file = nfile; 142290931Srodrigc lungetc('\n'); 143290931Srodrigc } 144290931Srodrigc ; 145290931Srodrigc 146290931Srodrigcvarset : STRING '=' STRING { 147330965Seadler char *s = $1; 148330965Seadler while (*s++) { 149330965Seadler if (isspace((unsigned char) *s)) { 150330965Seadler yyerror("macro name cannot contain " 151330965Seadler "whitespace"); 152330965Seadler YYERROR; 153330965Seadler } 154330965Seadler } 155290931Srodrigc if (symset($1, $3, 0) == -1) 156290931Srodrigc fatal("cannot store variable"); 157290931Srodrigc free($1); 158290931Srodrigc free($3); 159290931Srodrigc } 160290931Srodrigc ; 161290931Srodrigc 162290931Srodrigcport : /* empty */ { $$ = NULL; } 163290931Srodrigc | PORT STRING { $$ = $2; } 164290931Srodrigc ; 165290931Srodrigc 166290931Srodrigcopcode : GROUP { $$ = 0; } 167290931Srodrigc | PASSWD { $$ = 1; } 168290931Srodrigc ; 169290931Srodrigc 170290931Srodrigc 171290931Srodrigcattribute : NAME { $$ = 0; } 172290931Srodrigc | PASSWD { $$ = 1; } 173290931Srodrigc | UID { $$ = 2; } 174290931Srodrigc | GID { $$ = 3; } 175290931Srodrigc | CLASS { $$ = 4; } 176290931Srodrigc | CHANGE { $$ = 5; } 177290931Srodrigc | EXPIRE { $$ = 6; } 178290931Srodrigc | GECOS { $$ = 7; } 179290931Srodrigc | HOME { $$ = 8; } 180290931Srodrigc | SHELL { $$ = 9; } 181290931Srodrigc | GROUPNAME { $$ = 10; } 182290931Srodrigc | GROUPPASSWD { $$ = 11; } 183290931Srodrigc | GROUPGID { $$ = 12; } 184290931Srodrigc | GROUPMEMBERS { $$ = 13; } 185290931Srodrigc ; 186290931Srodrigc 187290931Srodrigcdiropt : BINDDN STRING { 188290931Srodrigc idm->idm_flags |= F_NEEDAUTH; 189290931Srodrigc if (strlcpy(idm->idm_binddn, $2, 190290931Srodrigc sizeof(idm->idm_binddn)) >= 191290931Srodrigc sizeof(idm->idm_binddn)) { 192290931Srodrigc yyerror("directory binddn truncated"); 193290931Srodrigc free($2); 194290931Srodrigc YYERROR; 195290931Srodrigc } 196290931Srodrigc free($2); 197290931Srodrigc } 198290931Srodrigc | BINDCRED STRING { 199290931Srodrigc idm->idm_flags |= F_NEEDAUTH; 200290931Srodrigc if (strlcpy(idm->idm_bindcred, $2, 201290931Srodrigc sizeof(idm->idm_bindcred)) >= 202290931Srodrigc sizeof(idm->idm_bindcred)) { 203290931Srodrigc yyerror("directory bindcred truncated"); 204290931Srodrigc free($2); 205290931Srodrigc YYERROR; 206290931Srodrigc } 207290931Srodrigc free($2); 208290931Srodrigc } 209290931Srodrigc | BASEDN STRING { 210290931Srodrigc if (strlcpy(idm->idm_basedn, $2, 211290931Srodrigc sizeof(idm->idm_basedn)) >= 212290931Srodrigc sizeof(idm->idm_basedn)) { 213290931Srodrigc yyerror("directory basedn truncated"); 214290931Srodrigc free($2); 215290931Srodrigc YYERROR; 216290931Srodrigc } 217290931Srodrigc free($2); 218290931Srodrigc } 219290931Srodrigc | GROUPDN STRING { 220290931Srodrigc if(strlcpy(idm->idm_groupdn, $2, 221290931Srodrigc sizeof(idm->idm_groupdn)) >= 222290931Srodrigc sizeof(idm->idm_groupdn)) { 223290931Srodrigc yyerror("directory groupdn truncated"); 224290931Srodrigc free($2); 225290931Srodrigc YYERROR; 226290931Srodrigc } 227290931Srodrigc free($2); 228290931Srodrigc } 229290931Srodrigc | opcode FILTER STRING { 230290931Srodrigc if (strlcpy(idm->idm_filters[$1], $3, 231290931Srodrigc sizeof(idm->idm_filters[$1])) >= 232290931Srodrigc sizeof(idm->idm_filters[$1])) { 233290931Srodrigc yyerror("filter truncated"); 234290931Srodrigc free($3); 235290931Srodrigc YYERROR; 236290931Srodrigc } 237290931Srodrigc free($3); 238290931Srodrigc } 239290931Srodrigc | ATTRIBUTE attribute MAPS TO STRING { 240290931Srodrigc if (strlcpy(idm->idm_attrs[$2], $5, 241290931Srodrigc sizeof(idm->idm_attrs[$2])) >= 242290931Srodrigc sizeof(idm->idm_attrs[$2])) { 243290931Srodrigc yyerror("attribute truncated"); 244290931Srodrigc free($5); 245290931Srodrigc YYERROR; 246290931Srodrigc } 247290931Srodrigc free($5); 248290931Srodrigc } 249290931Srodrigc | FIXED ATTRIBUTE attribute STRING { 250290931Srodrigc if (strlcpy(idm->idm_attrs[$3], $4, 251290931Srodrigc sizeof(idm->idm_attrs[$3])) >= 252290931Srodrigc sizeof(idm->idm_attrs[$3])) { 253290931Srodrigc yyerror("attribute truncated"); 254290931Srodrigc free($4); 255290931Srodrigc YYERROR; 256290931Srodrigc } 257290931Srodrigc idm->idm_flags |= F_FIXED_ATTR($3); 258290931Srodrigc free($4); 259290931Srodrigc } 260290931Srodrigc | LIST attribute MAPS TO STRING { 261290931Srodrigc if (strlcpy(idm->idm_attrs[$2], $5, 262290931Srodrigc sizeof(idm->idm_attrs[$2])) >= 263290931Srodrigc sizeof(idm->idm_attrs[$2])) { 264290931Srodrigc yyerror("attribute truncated"); 265290931Srodrigc free($5); 266290931Srodrigc YYERROR; 267290931Srodrigc } 268290931Srodrigc idm->idm_list |= F_LIST($2); 269290931Srodrigc free($5); 270290931Srodrigc } 271290931Srodrigc ; 272290931Srodrigc 273290931Srodrigcdirectory : DIRECTORY STRING port { 274290931Srodrigc if ((idm = calloc(1, sizeof(*idm))) == NULL) 275290931Srodrigc fatal(NULL); 276290931Srodrigc idm->idm_id = conf->sc_maxid++; 277290931Srodrigc 278290931Srodrigc if (strlcpy(idm->idm_name, $2, 279290931Srodrigc sizeof(idm->idm_name)) >= 280290931Srodrigc sizeof(idm->idm_name)) { 281290931Srodrigc yyerror("attribute truncated"); 282290931Srodrigc free($2); 283290931Srodrigc YYERROR; 284290931Srodrigc } 285290931Srodrigc 286290931Srodrigc free($2); 287290931Srodrigc } '{' optnl diropts '}' { 288290931Srodrigc TAILQ_INSERT_TAIL(&conf->sc_idms, idm, idm_entry); 289290931Srodrigc idm = NULL; 290290931Srodrigc } 291290931Srodrigc ; 292290931Srodrigc 293290931Srodrigcmain : INTERVAL NUMBER { 294290931Srodrigc conf->sc_conf_tv.tv_sec = $2; 295290931Srodrigc conf->sc_conf_tv.tv_usec = 0; 296290931Srodrigc } 297290931Srodrigc | DOMAIN STRING { 298290931Srodrigc if (strlcpy(conf->sc_domainname, $2, 299290931Srodrigc sizeof(conf->sc_domainname)) >= 300290931Srodrigc sizeof(conf->sc_domainname)) { 301290931Srodrigc yyerror("domainname truncated"); 302290931Srodrigc free($2); 303290931Srodrigc YYERROR; 304290931Srodrigc } 305290931Srodrigc free($2); 306290931Srodrigc } 307290931Srodrigc | PROVIDE MAP STRING { 308290931Srodrigc if (strcmp($3, "passwd.byname") == 0) 309290931Srodrigc conf->sc_flags |= YPMAP_PASSWD_BYNAME; 310290931Srodrigc else if (strcmp($3, "passwd.byuid") == 0) 311290931Srodrigc conf->sc_flags |= YPMAP_PASSWD_BYUID; 312290931Srodrigc else if (strcmp($3, "master.passwd.byname") == 0) 313290931Srodrigc conf->sc_flags |= YPMAP_MASTER_PASSWD_BYNAME; 314290931Srodrigc else if (strcmp($3, "master.passwd.byuid") == 0) 315290931Srodrigc conf->sc_flags |= YPMAP_MASTER_PASSWD_BYUID; 316290931Srodrigc else if (strcmp($3, "group.byname") == 0) 317290931Srodrigc conf->sc_flags |= YPMAP_GROUP_BYNAME; 318290931Srodrigc else if (strcmp($3, "group.bygid") == 0) 319290931Srodrigc conf->sc_flags |= YPMAP_GROUP_BYGID; 320290931Srodrigc else if (strcmp($3, "netid.byname") == 0) 321290931Srodrigc conf->sc_flags |= YPMAP_NETID_BYNAME; 322290931Srodrigc else { 323290931Srodrigc yyerror("unsupported map type: %s", $3); 324290931Srodrigc free($3); 325290931Srodrigc YYERROR; 326290931Srodrigc } 327290931Srodrigc free($3); 328290931Srodrigc } 329290931Srodrigc ; 330290931Srodrigc 331290931Srodrigcdiropts : diropts diropt nl 332290931Srodrigc | diropt optnl 333290931Srodrigc ; 334290931Srodrigc 335290931Srodrigc%% 336290931Srodrigc 337290931Srodrigcstruct keywords { 338290931Srodrigc const char *k_name; 339290931Srodrigc int k_val; 340290931Srodrigc}; 341290931Srodrigc 342290931Srodrigcint 343290931Srodrigcyyerror(const char *fmt, ...) 344290931Srodrigc{ 345290931Srodrigc va_list ap; 346290931Srodrigc char *msg; 347290931Srodrigc 348290931Srodrigc file->errors++; 349290931Srodrigc va_start(ap, fmt); 350290931Srodrigc if (vasprintf(&msg, fmt, ap) == -1) 351290931Srodrigc fatalx("yyerror vasprintf"); 352290931Srodrigc va_end(ap); 353290931Srodrigc logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); 354290931Srodrigc free(msg); 355290931Srodrigc return (0); 356290931Srodrigc} 357290931Srodrigc 358290931Srodrigcint 359290931Srodrigckw_cmp(const void *k, const void *e) 360290931Srodrigc{ 361290931Srodrigc return (strcmp(k, ((const struct keywords *)e)->k_name)); 362290931Srodrigc} 363290931Srodrigc 364290931Srodrigcint 365290931Srodrigclookup(char *s) 366290931Srodrigc{ 367290931Srodrigc /* this has to be sorted always */ 368290931Srodrigc static const struct keywords keywords[] = { 369290931Srodrigc { "attribute", ATTRIBUTE }, 370290931Srodrigc { "basedn", BASEDN }, 371290931Srodrigc { "bindcred", BINDCRED }, 372290931Srodrigc { "binddn", BINDDN }, 373290931Srodrigc { "change", CHANGE }, 374290931Srodrigc { "class", CLASS }, 375290931Srodrigc { "directory", DIRECTORY }, 376290931Srodrigc { "domain", DOMAIN }, 377290931Srodrigc { "expire", EXPIRE }, 378290931Srodrigc { "filter", FILTER }, 379290931Srodrigc { "fixed", FIXED }, 380290931Srodrigc { "gecos", GECOS }, 381290931Srodrigc { "gid", GID }, 382290931Srodrigc { "group", GROUP }, 383290931Srodrigc { "groupdn", GROUPDN }, 384290931Srodrigc { "groupgid", GROUPGID }, 385290931Srodrigc { "groupmembers", GROUPMEMBERS }, 386290931Srodrigc { "groupname", GROUPNAME }, 387290931Srodrigc { "grouppasswd", GROUPPASSWD }, 388290931Srodrigc { "home", HOME }, 389290931Srodrigc { "include", INCLUDE }, 390290931Srodrigc { "interval", INTERVAL }, 391290931Srodrigc { "list", LIST }, 392290931Srodrigc { "map", MAP }, 393290931Srodrigc { "maps", MAPS }, 394290931Srodrigc { "name", NAME }, 395290931Srodrigc { "passwd", PASSWD }, 396290931Srodrigc { "port", PORT }, 397290931Srodrigc { "provide", PROVIDE }, 398290931Srodrigc { "server", SERVER }, 399290931Srodrigc { "shell", SHELL }, 400290931Srodrigc { "to", TO }, 401290931Srodrigc { "uid", UID }, 402290931Srodrigc { "user", USER }, 403290931Srodrigc }; 404290931Srodrigc const struct keywords *p; 405290931Srodrigc 406290931Srodrigc p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 407290931Srodrigc sizeof(keywords[0]), kw_cmp); 408290931Srodrigc 409290931Srodrigc if (p) 410290931Srodrigc return (p->k_val); 411290931Srodrigc else 412290931Srodrigc return (STRING); 413290931Srodrigc} 414290931Srodrigc 415290931Srodrigc#define MAXPUSHBACK 128 416290931Srodrigc 417290931Srodrigcu_char *parsebuf; 418290931Srodrigcint parseindex; 419290931Srodrigcu_char pushback_buffer[MAXPUSHBACK]; 420290931Srodrigcint pushback_index = 0; 421290931Srodrigc 422290931Srodrigcint 423290931Srodrigclgetc(int quotec) 424290931Srodrigc{ 425290931Srodrigc int c, next; 426290931Srodrigc 427290931Srodrigc if (parsebuf) { 428290931Srodrigc /* Read character from the parsebuffer instead of input. */ 429290931Srodrigc if (parseindex >= 0) { 430290931Srodrigc c = parsebuf[parseindex++]; 431290931Srodrigc if (c != '\0') 432290931Srodrigc return (c); 433290931Srodrigc parsebuf = NULL; 434290931Srodrigc } else 435290931Srodrigc parseindex++; 436290931Srodrigc } 437290931Srodrigc 438290931Srodrigc if (pushback_index) 439290931Srodrigc return (pushback_buffer[--pushback_index]); 440290931Srodrigc 441290931Srodrigc if (quotec) { 442290931Srodrigc if ((c = getc(file->stream)) == EOF) { 443290931Srodrigc yyerror("reached end of file while parsing " 444290931Srodrigc "quoted string"); 445290931Srodrigc if (file == topfile || popfile() == EOF) 446290931Srodrigc return (EOF); 447290931Srodrigc return (quotec); 448290931Srodrigc } 449290931Srodrigc return (c); 450290931Srodrigc } 451290931Srodrigc 452290931Srodrigc while ((c = getc(file->stream)) == '\\') { 453290931Srodrigc next = getc(file->stream); 454290931Srodrigc if (next != '\n') { 455290931Srodrigc c = next; 456290931Srodrigc break; 457290931Srodrigc } 458290931Srodrigc yylval.lineno = file->lineno; 459290931Srodrigc file->lineno++; 460290931Srodrigc } 461290931Srodrigc 462290931Srodrigc while (c == EOF) { 463290931Srodrigc if (file == topfile || popfile() == EOF) 464290931Srodrigc return (EOF); 465290931Srodrigc c = getc(file->stream); 466290931Srodrigc } 467290931Srodrigc return (c); 468290931Srodrigc} 469290931Srodrigc 470290931Srodrigcint 471290931Srodrigclungetc(int c) 472290931Srodrigc{ 473290931Srodrigc if (c == EOF) 474290931Srodrigc return (EOF); 475290931Srodrigc if (parsebuf) { 476290931Srodrigc parseindex--; 477290931Srodrigc if (parseindex >= 0) 478290931Srodrigc return (c); 479290931Srodrigc } 480290931Srodrigc if (pushback_index < MAXPUSHBACK-1) 481290931Srodrigc return (pushback_buffer[pushback_index++] = c); 482290931Srodrigc else 483290931Srodrigc return (EOF); 484290931Srodrigc} 485290931Srodrigc 486290931Srodrigcint 487290931Srodrigcfindeol(void) 488290931Srodrigc{ 489290931Srodrigc int c; 490290931Srodrigc 491290931Srodrigc parsebuf = NULL; 492290931Srodrigc 493290931Srodrigc /* skip to either EOF or the first real EOL */ 494290931Srodrigc while (1) { 495290931Srodrigc if (pushback_index) 496290931Srodrigc c = pushback_buffer[--pushback_index]; 497290931Srodrigc else 498290931Srodrigc c = lgetc(0); 499290931Srodrigc if (c == '\n') { 500290931Srodrigc file->lineno++; 501290931Srodrigc break; 502290931Srodrigc } 503290931Srodrigc if (c == EOF) 504290931Srodrigc break; 505290931Srodrigc } 506290931Srodrigc return (ERROR); 507290931Srodrigc} 508290931Srodrigc 509290931Srodrigcint 510290931Srodrigcyylex(void) 511290931Srodrigc{ 512290931Srodrigc u_char buf[8096]; 513290931Srodrigc u_char *p, *val; 514290931Srodrigc int quotec, next, c; 515290931Srodrigc int token; 516290931Srodrigc 517290931Srodrigctop: 518290931Srodrigc p = buf; 519290931Srodrigc while ((c = lgetc(0)) == ' ' || c == '\t') 520290931Srodrigc ; /* nothing */ 521290931Srodrigc 522290931Srodrigc yylval.lineno = file->lineno; 523290931Srodrigc if (c == '#') 524290931Srodrigc while ((c = lgetc(0)) != '\n' && c != EOF) 525290931Srodrigc ; /* nothing */ 526290931Srodrigc if (c == '$' && parsebuf == NULL) { 527290931Srodrigc while (1) { 528290931Srodrigc if ((c = lgetc(0)) == EOF) 529290931Srodrigc return (0); 530290931Srodrigc 531290931Srodrigc if (p + 1 >= buf + sizeof(buf) - 1) { 532290931Srodrigc yyerror("string too long"); 533290931Srodrigc return (findeol()); 534290931Srodrigc } 535290931Srodrigc if (isalnum(c) || c == '_') { 536290931Srodrigc *p++ = c; 537290931Srodrigc continue; 538290931Srodrigc } 539290931Srodrigc *p = '\0'; 540290931Srodrigc lungetc(c); 541290931Srodrigc break; 542290931Srodrigc } 543290931Srodrigc val = symget(buf); 544290931Srodrigc if (val == NULL) { 545290931Srodrigc yyerror("macro '%s' not defined", buf); 546290931Srodrigc return (findeol()); 547290931Srodrigc } 548290931Srodrigc parsebuf = val; 549290931Srodrigc parseindex = 0; 550290931Srodrigc goto top; 551290931Srodrigc } 552290931Srodrigc 553290931Srodrigc switch (c) { 554290931Srodrigc case '\'': 555290931Srodrigc case '"': 556290931Srodrigc quotec = c; 557290931Srodrigc while (1) { 558290931Srodrigc if ((c = lgetc(quotec)) == EOF) 559290931Srodrigc return (0); 560290931Srodrigc if (c == '\n') { 561290931Srodrigc file->lineno++; 562290931Srodrigc continue; 563290931Srodrigc } else if (c == '\\') { 564290931Srodrigc if ((next = lgetc(quotec)) == EOF) 565290931Srodrigc return (0); 566290931Srodrigc if (next == quotec || c == ' ' || c == '\t') 567290931Srodrigc c = next; 568290931Srodrigc else if (next == '\n') { 569290931Srodrigc file->lineno++; 570290931Srodrigc continue; 571290931Srodrigc } else 572290931Srodrigc lungetc(next); 573290931Srodrigc } else if (c == quotec) { 574290931Srodrigc *p = '\0'; 575290931Srodrigc break; 576290931Srodrigc } else if (c == '\0') { 577290931Srodrigc yyerror("syntax error"); 578290931Srodrigc return (findeol()); 579290931Srodrigc } 580290931Srodrigc if (p + 1 >= buf + sizeof(buf) - 1) { 581290931Srodrigc yyerror("string too long"); 582290931Srodrigc return (findeol()); 583290931Srodrigc } 584290931Srodrigc *p++ = c; 585290931Srodrigc } 586290931Srodrigc yylval.v.string = strdup(buf); 587290931Srodrigc if (yylval.v.string == NULL) 588290931Srodrigc err(1, "yylex: strdup"); 589290931Srodrigc return (STRING); 590290931Srodrigc } 591290931Srodrigc 592290931Srodrigc#define allowed_to_end_number(x) \ 593290931Srodrigc (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 594290931Srodrigc 595290931Srodrigc if (c == '-' || isdigit(c)) { 596290931Srodrigc do { 597290931Srodrigc *p++ = c; 598290931Srodrigc if ((unsigned)(p-buf) >= sizeof(buf)) { 599290931Srodrigc yyerror("string too long"); 600290931Srodrigc return (findeol()); 601290931Srodrigc } 602290931Srodrigc } while ((c = lgetc(0)) != EOF && isdigit(c)); 603290931Srodrigc lungetc(c); 604290931Srodrigc if (p == buf + 1 && buf[0] == '-') 605290931Srodrigc goto nodigits; 606290931Srodrigc if (c == EOF || allowed_to_end_number(c)) { 607290931Srodrigc const char *errstr = NULL; 608290931Srodrigc 609290931Srodrigc *p = '\0'; 610290931Srodrigc yylval.v.number = strtonum(buf, LLONG_MIN, 611290931Srodrigc LLONG_MAX, &errstr); 612290931Srodrigc if (errstr) { 613290931Srodrigc yyerror("\"%s\" invalid number: %s", 614290931Srodrigc buf, errstr); 615290931Srodrigc return (findeol()); 616290931Srodrigc } 617290931Srodrigc return (NUMBER); 618290931Srodrigc } else { 619290931Srodrigcnodigits: 620290931Srodrigc while (p > buf + 1) 621290931Srodrigc lungetc(*--p); 622290931Srodrigc c = *--p; 623290931Srodrigc if (c == '-') 624290931Srodrigc return (c); 625290931Srodrigc } 626290931Srodrigc } 627290931Srodrigc 628290931Srodrigc#define allowed_in_string(x) \ 629290931Srodrigc (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 630290931Srodrigc x != '{' && x != '}' && x != '<' && x != '>' && \ 631290931Srodrigc x != '!' && x != '=' && x != '#' && \ 632290931Srodrigc x != ',')) 633290931Srodrigc 634290931Srodrigc if (isalnum(c) || c == ':' || c == '_') { 635290931Srodrigc do { 636290931Srodrigc *p++ = c; 637290931Srodrigc if ((unsigned)(p-buf) >= sizeof(buf)) { 638290931Srodrigc yyerror("string too long"); 639290931Srodrigc return (findeol()); 640290931Srodrigc } 641290931Srodrigc } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 642290931Srodrigc lungetc(c); 643290931Srodrigc *p = '\0'; 644290931Srodrigc if ((token = lookup(buf)) == STRING) 645290931Srodrigc if ((yylval.v.string = strdup(buf)) == NULL) 646290931Srodrigc err(1, "yylex: strdup"); 647290931Srodrigc return (token); 648290931Srodrigc } 649290931Srodrigc if (c == '\n') { 650290931Srodrigc yylval.lineno = file->lineno; 651290931Srodrigc file->lineno++; 652290931Srodrigc } 653290931Srodrigc if (c == EOF) 654290931Srodrigc return (0); 655290931Srodrigc return (c); 656290931Srodrigc} 657290931Srodrigc 658290931Srodrigcint 659290931Srodrigccheck_file_secrecy(int fd, const char *fname) 660290931Srodrigc{ 661290931Srodrigc struct stat st; 662290931Srodrigc 663290931Srodrigc if (fstat(fd, &st)) { 664290931Srodrigc log_warn("cannot stat %s", fname); 665290931Srodrigc return (-1); 666290931Srodrigc } 667290931Srodrigc if (st.st_uid != 0 && st.st_uid != getuid()) { 668290931Srodrigc log_warnx("%s: owner not root or current user", fname); 669290931Srodrigc return (-1); 670290931Srodrigc } 671290931Srodrigc if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { 672290931Srodrigc log_warnx("%s: group writable or world read/writable", fname); 673290931Srodrigc return (-1); 674290931Srodrigc } 675290931Srodrigc return (0); 676290931Srodrigc} 677290931Srodrigc 678290931Srodrigcstruct file * 679290931Srodrigcpushfile(const char *name, int secret) 680290931Srodrigc{ 681290931Srodrigc struct file *nfile; 682290931Srodrigc 683290931Srodrigc if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 684290931Srodrigc log_warn("malloc"); 685290931Srodrigc return (NULL); 686290931Srodrigc } 687290931Srodrigc if ((nfile->name = strdup(name)) == NULL) { 688290931Srodrigc log_warn("malloc"); 689290931Srodrigc free(nfile); 690290931Srodrigc return (NULL); 691290931Srodrigc } 692290931Srodrigc if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 693290931Srodrigc log_warn("%s", nfile->name); 694290931Srodrigc free(nfile->name); 695290931Srodrigc free(nfile); 696290931Srodrigc return (NULL); 697290931Srodrigc } else if (secret && 698290931Srodrigc check_file_secrecy(fileno(nfile->stream), nfile->name)) { 699290931Srodrigc fclose(nfile->stream); 700290931Srodrigc free(nfile->name); 701290931Srodrigc free(nfile); 702290931Srodrigc return (NULL); 703290931Srodrigc } 704290931Srodrigc nfile->lineno = 1; 705290931Srodrigc TAILQ_INSERT_TAIL(&files, nfile, entry); 706290931Srodrigc return (nfile); 707290931Srodrigc} 708290931Srodrigc 709290931Srodrigcint 710290931Srodrigcpopfile(void) 711290931Srodrigc{ 712290931Srodrigc struct file *prev; 713290931Srodrigc 714290931Srodrigc if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 715290931Srodrigc prev->errors += file->errors; 716290931Srodrigc 717290931Srodrigc TAILQ_REMOVE(&files, file, entry); 718290931Srodrigc fclose(file->stream); 719290931Srodrigc free(file->name); 720290931Srodrigc free(file); 721290931Srodrigc file = prev; 722290931Srodrigc return (file ? 0 : EOF); 723290931Srodrigc} 724290931Srodrigc 725290931Srodrigcint 726290931Srodrigcparse_config(struct env *x_conf, const char *filename, int opts) 727290931Srodrigc{ 728290931Srodrigc struct sym *sym, *next; 729290931Srodrigc 730290931Srodrigc conf = x_conf; 731290931Srodrigc bzero(conf, sizeof(*conf)); 732290931Srodrigc 733290931Srodrigc TAILQ_INIT(&conf->sc_idms); 734290931Srodrigc conf->sc_conf_tv.tv_sec = DEFAULT_INTERVAL; 735290931Srodrigc conf->sc_conf_tv.tv_usec = 0; 736290931Srodrigc 737290931Srodrigc errors = 0; 738290931Srodrigc 739290931Srodrigc if ((file = pushfile(filename, 1)) == NULL) { 740290931Srodrigc return (-1); 741290931Srodrigc } 742290931Srodrigc topfile = file; 743290931Srodrigc 744290931Srodrigc /* 745290931Srodrigc * parse configuration 746290931Srodrigc */ 747290931Srodrigc setservent(1); 748290931Srodrigc yyparse(); 749290931Srodrigc endservent(); 750290931Srodrigc errors = file->errors; 751290931Srodrigc popfile(); 752290931Srodrigc 753290931Srodrigc /* Free macros and check which have not been used. */ 754290931Srodrigc for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { 755290931Srodrigc next = TAILQ_NEXT(sym, entry); 756290931Srodrigc if ((opts & YPLDAP_OPT_VERBOSE) && !sym->used) 757290931Srodrigc fprintf(stderr, "warning: macro '%s' not " 758290931Srodrigc "used\n", sym->nam); 759290931Srodrigc if (!sym->persist) { 760290931Srodrigc free(sym->nam); 761290931Srodrigc free(sym->val); 762290931Srodrigc TAILQ_REMOVE(&symhead, sym, entry); 763290931Srodrigc free(sym); 764290931Srodrigc } 765290931Srodrigc } 766290931Srodrigc 767290931Srodrigc if (errors) { 768290931Srodrigc return (-1); 769290931Srodrigc } 770290931Srodrigc 771290931Srodrigc return (0); 772290931Srodrigc} 773290931Srodrigc 774290931Srodrigcint 775290931Srodrigcsymset(const char *nam, const char *val, int persist) 776290931Srodrigc{ 777290931Srodrigc struct sym *sym; 778290931Srodrigc 779290931Srodrigc for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 780290931Srodrigc sym = TAILQ_NEXT(sym, entry)) 781290931Srodrigc ; /* nothing */ 782290931Srodrigc 783290931Srodrigc if (sym != NULL) { 784290931Srodrigc if (sym->persist == 1) 785290931Srodrigc return (0); 786290931Srodrigc else { 787290931Srodrigc free(sym->nam); 788290931Srodrigc free(sym->val); 789290931Srodrigc TAILQ_REMOVE(&symhead, sym, entry); 790290931Srodrigc free(sym); 791290931Srodrigc } 792290931Srodrigc } 793290931Srodrigc if ((sym = calloc(1, sizeof(*sym))) == NULL) 794290931Srodrigc return (-1); 795290931Srodrigc 796290931Srodrigc sym->nam = strdup(nam); 797290931Srodrigc if (sym->nam == NULL) { 798290931Srodrigc free(sym); 799290931Srodrigc return (-1); 800290931Srodrigc } 801290931Srodrigc sym->val = strdup(val); 802290931Srodrigc if (sym->val == NULL) { 803290931Srodrigc free(sym->nam); 804290931Srodrigc free(sym); 805290931Srodrigc return (-1); 806290931Srodrigc } 807290931Srodrigc sym->used = 0; 808290931Srodrigc sym->persist = persist; 809290931Srodrigc TAILQ_INSERT_TAIL(&symhead, sym, entry); 810290931Srodrigc return (0); 811290931Srodrigc} 812290931Srodrigc 813290931Srodrigcint 814290931Srodrigccmdline_symset(char *s) 815290931Srodrigc{ 816290931Srodrigc char *sym, *val; 817290931Srodrigc int ret; 818290931Srodrigc size_t len; 819290931Srodrigc 820290931Srodrigc if ((val = strrchr(s, '=')) == NULL) 821290931Srodrigc return (-1); 822290931Srodrigc 823290931Srodrigc len = strlen(s) - strlen(val) + 1; 824290931Srodrigc if ((sym = malloc(len)) == NULL) 825290931Srodrigc errx(1, "cmdline_symset: malloc"); 826290931Srodrigc 827290931Srodrigc (void)strlcpy(sym, s, len); 828290931Srodrigc 829290931Srodrigc ret = symset(sym, val + 1, 1); 830290931Srodrigc free(sym); 831290931Srodrigc 832290931Srodrigc return (ret); 833290931Srodrigc} 834290931Srodrigc 835290931Srodrigcchar * 836290931Srodrigcsymget(const char *nam) 837290931Srodrigc{ 838290931Srodrigc struct sym *sym; 839290931Srodrigc 840290931Srodrigc TAILQ_FOREACH(sym, &symhead, entry) 841290931Srodrigc if (strcmp(nam, sym->nam) == 0) { 842290931Srodrigc sym->used = 1; 843290931Srodrigc return (sym->val); 844290931Srodrigc } 845290931Srodrigc return (NULL); 846290931Srodrigc} 847