1*73492e0cSclaudio /* $OpenBSD: parse.y,v 1.37 2023/07/18 13:06:33 claudio Exp $ */
2f6242408Spyr
3f6242408Spyr /*
4f6242408Spyr * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5f6242408Spyr * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
6f6242408Spyr * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
7f6242408Spyr * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
8f6242408Spyr * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
9f6242408Spyr * Copyright (c) 2001 Markus Friedl. All rights reserved.
10f6242408Spyr * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
11f6242408Spyr * Copyright (c) 2001 Theo de Raadt. All rights reserved.
12f6242408Spyr *
13f6242408Spyr * Permission to use, copy, modify, and distribute this software for any
14f6242408Spyr * purpose with or without fee is hereby granted, provided that the above
15f6242408Spyr * copyright notice and this permission notice appear in all copies.
16f6242408Spyr *
17f6242408Spyr * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
18f6242408Spyr * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
19f6242408Spyr * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
20f6242408Spyr * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21f6242408Spyr * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
22f6242408Spyr * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
23f6242408Spyr * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24f6242408Spyr */
25f6242408Spyr
26f6242408Spyr %{
27f6242408Spyr #include <sys/types.h>
28f6242408Spyr #include <sys/time.h>
29f6242408Spyr #include <sys/queue.h>
30f6242408Spyr #include <sys/tree.h>
31f6242408Spyr #include <sys/socket.h>
32f6242408Spyr #include <sys/stat.h>
33f6242408Spyr
34f6242408Spyr #include <netinet/in.h>
35f6242408Spyr #include <arpa/inet.h>
36f6242408Spyr
37f6242408Spyr #include <ctype.h>
38f6242408Spyr #include <err.h>
39f6242408Spyr #include <errno.h>
40f6242408Spyr #include <event.h>
41f6242408Spyr #include <fcntl.h>
42f6242408Spyr #include <limits.h>
43f6242408Spyr #include <netdb.h>
44f6242408Spyr #include <pwd.h>
45f6242408Spyr #include <stdarg.h>
46f6242408Spyr #include <stdio.h>
47f6242408Spyr #include <stdlib.h>
48f6242408Spyr #include <string.h>
494a1d3eaaSsthen #include <syslog.h>
5085f89112Sjsing #include <tls.h>
51f6242408Spyr #include <unistd.h>
52f6242408Spyr
53f6242408Spyr #include "ypldap.h"
54*73492e0cSclaudio #include "log.h"
55f6242408Spyr
56f6242408Spyr TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
57f6242408Spyr static struct file {
58f6242408Spyr TAILQ_ENTRY(file) entry;
59f6242408Spyr FILE *stream;
60f6242408Spyr char *name;
61b83b389fSdenis size_t ungetpos;
62b83b389fSdenis size_t ungetsize;
63b83b389fSdenis u_char *ungetbuf;
64b83b389fSdenis int eof_reached;
65f6242408Spyr int lineno;
66f6242408Spyr int errors;
67f6242408Spyr } *file, *topfile;
68f6242408Spyr struct file *pushfile(const char *, int);
69f6242408Spyr int popfile(void);
70f6242408Spyr int check_file_secrecy(int, const char *);
71f6242408Spyr int yyparse(void);
72f6242408Spyr int yylex(void);
730f79392cSdoug int yyerror(const char *, ...)
740f79392cSdoug __attribute__((__format__ (printf, 1, 2)))
750f79392cSdoug __attribute__((__nonnull__ (1)));
76f6242408Spyr int kw_cmp(const void *, const void *);
77f6242408Spyr int lookup(char *);
78b83b389fSdenis int igetc(void);
79f6242408Spyr int lgetc(int);
80b83b389fSdenis void lungetc(int);
81f6242408Spyr int findeol(void);
82f6242408Spyr
83f6242408Spyr TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
84f6242408Spyr struct sym {
85f6242408Spyr TAILQ_ENTRY(sym) entry;
86f6242408Spyr int used;
87f6242408Spyr int persist;
88f6242408Spyr char *nam;
89f6242408Spyr char *val;
90f6242408Spyr };
91f6242408Spyr int symset(const char *, const char *, int);
92f6242408Spyr char *symget(const char *);
93f6242408Spyr
94f6242408Spyr struct env *conf = NULL;
95f6242408Spyr struct idm *idm = NULL;
96f6242408Spyr static int errors = 0;
97f6242408Spyr
98f6242408Spyr typedef struct {
99f6242408Spyr union {
100f6242408Spyr int64_t number;
101f6242408Spyr char *string;
102f6242408Spyr } v;
103f6242408Spyr int lineno;
104f6242408Spyr } YYSTYPE;
105f6242408Spyr
106f6242408Spyr %}
107f6242408Spyr
108b8ccc478Sjmatthew %token SERVER FILTER ATTRIBUTE BASEDN BINDDN GROUPDN BINDCRED MAPS CHANGE DOMAIN PROVIDE
109f6242408Spyr %token USER GROUP TO EXPIRE HOME SHELL GECOS UID GID INTERVAL
110ec4ad443Saschrijver %token PASSWD NAME FIXED LIST GROUPNAME GROUPPASSWD GROUPGID MAP
11132814761Sjmatthew %token INCLUDE DIRECTORY CLASS PORT ERROR GROUPMEMBERS LDAPS TLS CAFILE
11240c94266Sjmatthew %token BIND LOCAL PORTMAP BINDEXT CERTFILE KEYFILE
113f6242408Spyr %token <v.string> STRING
114f6242408Spyr %token <v.number> NUMBER
1156106e71cSaschrijver %type <v.number> opcode attribute
11632814761Sjmatthew %type <v.number> port
11732814761Sjmatthew %type <v.number> ssl
118f6242408Spyr
119f6242408Spyr %%
120f6242408Spyr
121f6242408Spyr grammar : /* empty */
122f6242408Spyr | grammar '\n'
123f6242408Spyr | grammar include '\n'
124f6242408Spyr | grammar varset '\n'
125f6242408Spyr | grammar directory '\n'
126f6242408Spyr | grammar main '\n'
127f6242408Spyr | grammar error '\n' { file->errors++; }
128f6242408Spyr ;
129f6242408Spyr
130f6242408Spyr nl : '\n' optnl
131f6242408Spyr ;
132f6242408Spyr
133f6242408Spyr optnl : '\n' optnl
134f6242408Spyr | /* empty */
135f6242408Spyr ;
136f6242408Spyr
1376106e71cSaschrijver
138f6242408Spyr include : INCLUDE STRING {
139f6242408Spyr struct file *nfile;
140f6242408Spyr
141b83b389fSdenis if ((nfile = pushfile($2, 1)) == NULL) {
142f6242408Spyr yyerror("failed to include file %s", $2);
143f6242408Spyr free($2);
144f6242408Spyr YYERROR;
145f6242408Spyr }
146f6242408Spyr free($2);
147f6242408Spyr
148f6242408Spyr file = nfile;
149f6242408Spyr lungetc('\n');
150f6242408Spyr }
151f6242408Spyr ;
152f6242408Spyr
153f6242408Spyr varset : STRING '=' STRING {
1540c7b4ca6Sbenno char *s = $1;
1550c7b4ca6Sbenno while (*s++) {
1560c7b4ca6Sbenno if (isspace((unsigned char)*s)) {
1570c7b4ca6Sbenno yyerror("macro name cannot contain "
1580c7b4ca6Sbenno "whitespace");
15916a0a906Skrw free($1);
16016a0a906Skrw free($3);
1610c7b4ca6Sbenno YYERROR;
1620c7b4ca6Sbenno }
1630c7b4ca6Sbenno }
164f6242408Spyr if (symset($1, $3, 0) == -1)
165f6242408Spyr fatal("cannot store variable");
166f6242408Spyr free($1);
167f6242408Spyr free($3);
168f6242408Spyr }
169f6242408Spyr ;
170f6242408Spyr
17132814761Sjmatthew port : PORT STRING {
17232814761Sjmatthew struct servent *servent;
17332814761Sjmatthew
17432814761Sjmatthew servent = getservbyname($2, "tcp");
17532814761Sjmatthew if (servent == NULL) {
17632814761Sjmatthew yyerror("port %s is invalid", $2);
17732814761Sjmatthew free($2);
17832814761Sjmatthew YYERROR;
17932814761Sjmatthew }
18032814761Sjmatthew $$ = ntohs(servent->s_port);
18132814761Sjmatthew free($2);
18232814761Sjmatthew }
18332814761Sjmatthew | PORT NUMBER {
1840ead3a23Sflorian if ($2 <= 0 || $2 > (int)USHRT_MAX) {
18532814761Sjmatthew yyerror("invalid port: %lld", $2);
18632814761Sjmatthew YYERROR;
18732814761Sjmatthew }
18832814761Sjmatthew $$ = $2;
18932814761Sjmatthew }
19032814761Sjmatthew | /* empty */ {
19132814761Sjmatthew $$ = 0;
19232814761Sjmatthew }
193f6242408Spyr ;
194f6242408Spyr
195f6242408Spyr opcode : GROUP { $$ = 0; }
196f6242408Spyr | PASSWD { $$ = 1; }
197f6242408Spyr ;
198f6242408Spyr
1996106e71cSaschrijver
200f6242408Spyr attribute : NAME { $$ = 0; }
201f6242408Spyr | PASSWD { $$ = 1; }
202f6242408Spyr | UID { $$ = 2; }
203f6242408Spyr | GID { $$ = 3; }
204f6242408Spyr | CLASS { $$ = 4; }
205f6242408Spyr | CHANGE { $$ = 5; }
206f6242408Spyr | EXPIRE { $$ = 6; }
207f6242408Spyr | GECOS { $$ = 7; }
208f6242408Spyr | HOME { $$ = 8; }
209f6242408Spyr | SHELL { $$ = 9; }
210f6242408Spyr | GROUPNAME { $$ = 10; }
211f6242408Spyr | GROUPPASSWD { $$ = 11; }
212f6242408Spyr | GROUPGID { $$ = 12; }
213f6242408Spyr | GROUPMEMBERS { $$ = 13; }
214f6242408Spyr ;
215f6242408Spyr
216f6242408Spyr diropt : BINDDN STRING {
21740c94266Sjmatthew if (idm->idm_bindext != 0) {
21840c94266Sjmatthew yyerror("can't specify multiple bind types");
21940c94266Sjmatthew free($2);
22040c94266Sjmatthew YYERROR;
22140c94266Sjmatthew }
222f6242408Spyr idm->idm_flags |= F_NEEDAUTH;
223f6242408Spyr if (strlcpy(idm->idm_binddn, $2,
224f6242408Spyr sizeof(idm->idm_binddn)) >=
225f6242408Spyr sizeof(idm->idm_binddn)) {
226f6242408Spyr yyerror("directory binddn truncated");
227f6242408Spyr free($2);
228f6242408Spyr YYERROR;
229f6242408Spyr }
230f6242408Spyr free($2);
231f6242408Spyr }
232af720893Saschrijver | BINDCRED STRING {
23340c94266Sjmatthew if (idm->idm_bindext != 0) {
23440c94266Sjmatthew yyerror("can't specify multiple bind types");
23540c94266Sjmatthew free($2);
23640c94266Sjmatthew YYERROR;
23740c94266Sjmatthew }
238af720893Saschrijver idm->idm_flags |= F_NEEDAUTH;
239af720893Saschrijver if (strlcpy(idm->idm_bindcred, $2,
240af720893Saschrijver sizeof(idm->idm_bindcred)) >=
241af720893Saschrijver sizeof(idm->idm_bindcred)) {
242af720893Saschrijver yyerror("directory bindcred truncated");
243af720893Saschrijver free($2);
244af720893Saschrijver YYERROR;
245af720893Saschrijver }
246af720893Saschrijver free($2);
247af720893Saschrijver }
24840c94266Sjmatthew | BINDEXT STRING {
24940c94266Sjmatthew if (idm->idm_flags & F_NEEDAUTH) {
25040c94266Sjmatthew yyerror("can't specify multiple bind types");
25140c94266Sjmatthew free($2);
25240c94266Sjmatthew YYERROR;
25340c94266Sjmatthew }
25440c94266Sjmatthew idm->idm_flags |= F_NEEDAUTH;
25540c94266Sjmatthew idm->idm_bindext = 1;
25640c94266Sjmatthew if (strlcpy(idm->idm_bindextid, $2,
25740c94266Sjmatthew sizeof(idm->idm_bindextid)) >=
25840c94266Sjmatthew sizeof(idm->idm_bindextid)) {
25940c94266Sjmatthew yyerror("directory bindext truncated");
26040c94266Sjmatthew free($2);
26140c94266Sjmatthew YYERROR;
26240c94266Sjmatthew }
26340c94266Sjmatthew free($2);
26440c94266Sjmatthew }
26540c94266Sjmatthew | BINDEXT {
26640c94266Sjmatthew if (idm->idm_flags & F_NEEDAUTH) {
26740c94266Sjmatthew yyerror("can't specify multiple bind types");
26840c94266Sjmatthew YYERROR;
26940c94266Sjmatthew }
27040c94266Sjmatthew idm->idm_flags |= F_NEEDAUTH;
27140c94266Sjmatthew idm->idm_bindext = 1;
27240c94266Sjmatthew idm->idm_bindextid[0] = '\0';
27340c94266Sjmatthew }
27440c94266Sjmatthew | CERTFILE STRING {
27540c94266Sjmatthew if (idm->idm_tls_config == NULL) {
27640c94266Sjmatthew yyerror("can't set cert file without tls"
27740c94266Sjmatthew " enabled");
27840c94266Sjmatthew free($2);
27940c94266Sjmatthew YYERROR;
28040c94266Sjmatthew }
28140c94266Sjmatthew if (tls_config_set_cert_file(idm->idm_tls_config, $2)
28240c94266Sjmatthew == -1) {
28340c94266Sjmatthew yyerror("tls set cert file failed: %s",
28440c94266Sjmatthew tls_config_error(
28540c94266Sjmatthew idm->idm_tls_config));
28640c94266Sjmatthew free($2);
28740c94266Sjmatthew YYERROR;
28840c94266Sjmatthew }
28940c94266Sjmatthew }
29040c94266Sjmatthew | KEYFILE STRING {
29140c94266Sjmatthew if (idm->idm_tls_config == NULL) {
29240c94266Sjmatthew yyerror("can't set key file without tls"
29340c94266Sjmatthew " enabled");
29440c94266Sjmatthew free($2);
29540c94266Sjmatthew YYERROR;
29640c94266Sjmatthew }
29740c94266Sjmatthew if (tls_config_set_key_file(idm->idm_tls_config, $2)
29840c94266Sjmatthew == -1) {
29940c94266Sjmatthew yyerror("tls set key file failed: %s",
30040c94266Sjmatthew tls_config_error(
30140c94266Sjmatthew idm->idm_tls_config));
30240c94266Sjmatthew free($2);
30340c94266Sjmatthew YYERROR;
30440c94266Sjmatthew }
30540c94266Sjmatthew }
306af720893Saschrijver | BASEDN STRING {
307af720893Saschrijver if (strlcpy(idm->idm_basedn, $2,
308af720893Saschrijver sizeof(idm->idm_basedn)) >=
309af720893Saschrijver sizeof(idm->idm_basedn)) {
310ec4ad443Saschrijver yyerror("directory basedn truncated");
311af720893Saschrijver free($2);
312af720893Saschrijver YYERROR;
313af720893Saschrijver }
314af720893Saschrijver free($2);
315af720893Saschrijver }
316b8ccc478Sjmatthew | GROUPDN STRING {
317b8ccc478Sjmatthew if(strlcpy(idm->idm_groupdn, $2,
318b8ccc478Sjmatthew sizeof(idm->idm_groupdn)) >=
319b8ccc478Sjmatthew sizeof(idm->idm_groupdn)) {
320b8ccc478Sjmatthew yyerror("directory groupdn truncated");
321b8ccc478Sjmatthew free($2);
322b8ccc478Sjmatthew YYERROR;
323b8ccc478Sjmatthew }
324b8ccc478Sjmatthew free($2);
325b8ccc478Sjmatthew }
326f6242408Spyr | opcode FILTER STRING {
327f6242408Spyr if (strlcpy(idm->idm_filters[$1], $3,
328f6242408Spyr sizeof(idm->idm_filters[$1])) >=
329f6242408Spyr sizeof(idm->idm_filters[$1])) {
330f6242408Spyr yyerror("filter truncated");
331f6242408Spyr free($3);
332f6242408Spyr YYERROR;
333f6242408Spyr }
334f6242408Spyr free($3);
335f6242408Spyr }
336f6242408Spyr | ATTRIBUTE attribute MAPS TO STRING {
337f6242408Spyr if (strlcpy(idm->idm_attrs[$2], $5,
338f6242408Spyr sizeof(idm->idm_attrs[$2])) >=
339f6242408Spyr sizeof(idm->idm_attrs[$2])) {
340f6242408Spyr yyerror("attribute truncated");
341f6242408Spyr free($5);
342f6242408Spyr YYERROR;
343f6242408Spyr }
344f6242408Spyr free($5);
345f6242408Spyr }
346f6242408Spyr | FIXED ATTRIBUTE attribute STRING {
347f6242408Spyr if (strlcpy(idm->idm_attrs[$3], $4,
348f6242408Spyr sizeof(idm->idm_attrs[$3])) >=
349f6242408Spyr sizeof(idm->idm_attrs[$3])) {
350f6242408Spyr yyerror("attribute truncated");
351f6242408Spyr free($4);
352f6242408Spyr YYERROR;
353f6242408Spyr }
354f6242408Spyr idm->idm_flags |= F_FIXED_ATTR($3);
355f6242408Spyr free($4);
356f6242408Spyr }
357ec4ad443Saschrijver | LIST attribute MAPS TO STRING {
358ec4ad443Saschrijver if (strlcpy(idm->idm_attrs[$2], $5,
359ec4ad443Saschrijver sizeof(idm->idm_attrs[$2])) >=
360ec4ad443Saschrijver sizeof(idm->idm_attrs[$2])) {
361ec4ad443Saschrijver yyerror("attribute truncated");
362ec4ad443Saschrijver free($5);
363ec4ad443Saschrijver YYERROR;
364ec4ad443Saschrijver }
365ec4ad443Saschrijver idm->idm_list |= F_LIST($2);
366ec4ad443Saschrijver free($5);
367ec4ad443Saschrijver }
368f6242408Spyr ;
369f6242408Spyr
37032814761Sjmatthew ssl : /* empty */ { $$ = 0; }
37132814761Sjmatthew | LDAPS { $$ = F_SSL; }
37232814761Sjmatthew | TLS { $$ = F_STARTTLS; }
37332814761Sjmatthew ;
37432814761Sjmatthew
37532814761Sjmatthew directory : DIRECTORY STRING port ssl {
376f6242408Spyr if ((idm = calloc(1, sizeof(*idm))) == NULL)
377f6242408Spyr fatal(NULL);
378db474592Saschrijver idm->idm_id = conf->sc_maxid++;
379f6242408Spyr
380db474592Saschrijver if (strlcpy(idm->idm_name, $2,
381db474592Saschrijver sizeof(idm->idm_name)) >=
382db474592Saschrijver sizeof(idm->idm_name)) {
383db474592Saschrijver yyerror("attribute truncated");
384f6242408Spyr free($2);
385f6242408Spyr YYERROR;
386f6242408Spyr }
387f6242408Spyr free($2);
38832814761Sjmatthew
38932814761Sjmatthew idm->idm_port = $3;
39032814761Sjmatthew
39132814761Sjmatthew if ($4 != 0) {
39232814761Sjmatthew if (tls_init()) {
39332814761Sjmatthew yyerror("tls init failed");
39432814761Sjmatthew YYERROR;
39532814761Sjmatthew }
39632814761Sjmatthew
39732814761Sjmatthew idm->idm_flags |= $4;
39832814761Sjmatthew idm->idm_tls_config = tls_config_new();
39932814761Sjmatthew if (idm->idm_tls_config == NULL) {
40032814761Sjmatthew yyerror("tls config failed");
40132814761Sjmatthew YYERROR;
40232814761Sjmatthew }
40332814761Sjmatthew
40432814761Sjmatthew if (tls_config_set_protocols(
40532814761Sjmatthew idm->idm_tls_config,
40632814761Sjmatthew TLS_PROTOCOLS_ALL) == -1) {
40732814761Sjmatthew yyerror("tls set protocols failed: %s",
40832814761Sjmatthew tls_config_error(
40932814761Sjmatthew idm->idm_tls_config));
41032814761Sjmatthew tls_config_free(idm->idm_tls_config);
41132814761Sjmatthew idm->idm_tls_config = NULL;
41232814761Sjmatthew YYERROR;
41332814761Sjmatthew }
41432814761Sjmatthew if (tls_config_set_ciphers(idm->idm_tls_config,
41532814761Sjmatthew "compat") == -1) {
41632814761Sjmatthew yyerror("tls set ciphers failed: %s",
41732814761Sjmatthew tls_config_error(
41832814761Sjmatthew idm->idm_tls_config));
41932814761Sjmatthew tls_config_free(idm->idm_tls_config);
42032814761Sjmatthew idm->idm_tls_config = NULL;
42132814761Sjmatthew YYERROR;
42232814761Sjmatthew }
42332814761Sjmatthew
42432814761Sjmatthew if (tls_config_set_ca_file(idm->idm_tls_config,
42532814761Sjmatthew conf->sc_cafile) == -1) {
42632814761Sjmatthew yyerror("tls set CA bundle failed: %s",
42732814761Sjmatthew tls_config_error(
42832814761Sjmatthew idm->idm_tls_config));
42932814761Sjmatthew tls_config_free(idm->idm_tls_config);
43032814761Sjmatthew idm->idm_tls_config = NULL;
43132814761Sjmatthew YYERROR;
43232814761Sjmatthew }
43332814761Sjmatthew }
43432814761Sjmatthew
435f6242408Spyr } '{' optnl diropts '}' {
436f6242408Spyr TAILQ_INSERT_TAIL(&conf->sc_idms, idm, idm_entry);
437f6242408Spyr idm = NULL;
438f6242408Spyr }
439f6242408Spyr ;
440f6242408Spyr
441f6242408Spyr main : INTERVAL NUMBER {
442f6242408Spyr conf->sc_conf_tv.tv_sec = $2;
443f6242408Spyr conf->sc_conf_tv.tv_usec = 0;
444f6242408Spyr }
445f6242408Spyr | DOMAIN STRING {
446f6242408Spyr if (strlcpy(conf->sc_domainname, $2,
447f6242408Spyr sizeof(conf->sc_domainname)) >=
448f6242408Spyr sizeof(conf->sc_domainname)) {
449f6242408Spyr yyerror("domainname truncated");
450f6242408Spyr free($2);
451f6242408Spyr YYERROR;
452f6242408Spyr }
453f6242408Spyr free($2);
454f6242408Spyr }
455f6242408Spyr | PROVIDE MAP STRING {
456f6242408Spyr if (strcmp($3, "passwd.byname") == 0)
457f6242408Spyr conf->sc_flags |= YPMAP_PASSWD_BYNAME;
458f6242408Spyr else if (strcmp($3, "passwd.byuid") == 0)
459f6242408Spyr conf->sc_flags |= YPMAP_PASSWD_BYUID;
460f6242408Spyr else if (strcmp($3, "master.passwd.byname") == 0)
461f6242408Spyr conf->sc_flags |= YPMAP_MASTER_PASSWD_BYNAME;
462f6242408Spyr else if (strcmp($3, "master.passwd.byuid") == 0)
463f6242408Spyr conf->sc_flags |= YPMAP_MASTER_PASSWD_BYUID;
464f6242408Spyr else if (strcmp($3, "group.byname") == 0)
465f6242408Spyr conf->sc_flags |= YPMAP_GROUP_BYNAME;
466f6242408Spyr else if (strcmp($3, "group.bygid") == 0)
467f6242408Spyr conf->sc_flags |= YPMAP_GROUP_BYGID;
46833318bf8Saschrijver else if (strcmp($3, "netid.byname") == 0)
46933318bf8Saschrijver conf->sc_flags |= YPMAP_NETID_BYNAME;
470f6242408Spyr else {
471f6242408Spyr yyerror("unsupported map type: %s", $3);
472f6242408Spyr free($3);
473f6242408Spyr YYERROR;
474f6242408Spyr }
475f6242408Spyr free($3);
476f6242408Spyr }
47732814761Sjmatthew | CAFILE STRING {
47832814761Sjmatthew free(conf->sc_cafile);
47932814761Sjmatthew conf->sc_cafile = $2;
48032814761Sjmatthew }
48156f45a56Sjmatthew | BIND LOCAL {
48256f45a56Sjmatthew conf->sc_bind_mode = BIND_MODE_LOCAL;
48356f45a56Sjmatthew }
48456f45a56Sjmatthew | BIND PORTMAP {
48556f45a56Sjmatthew conf->sc_bind_mode = BIND_MODE_PORTMAP;
48656f45a56Sjmatthew }
487f6242408Spyr ;
488f6242408Spyr
489f6242408Spyr diropts : diropts diropt nl
490f6242408Spyr | diropt optnl
491f6242408Spyr ;
4926106e71cSaschrijver
493f6242408Spyr %%
494f6242408Spyr
495f6242408Spyr struct keywords {
496f6242408Spyr const char *k_name;
497f6242408Spyr int k_val;
498f6242408Spyr };
499f6242408Spyr
500f6242408Spyr int
yyerror(const char * fmt,...)501f6242408Spyr yyerror(const char *fmt, ...)
502f6242408Spyr {
503f6242408Spyr va_list ap;
504cd8337bcSbluhm char *msg;
505f6242408Spyr
506f6242408Spyr file->errors++;
507f6242408Spyr va_start(ap, fmt);
508cd8337bcSbluhm if (vasprintf(&msg, fmt, ap) == -1)
509cd8337bcSbluhm fatalx("yyerror vasprintf");
510f6242408Spyr va_end(ap);
511cd8337bcSbluhm logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
512cd8337bcSbluhm free(msg);
513f6242408Spyr return (0);
514f6242408Spyr }
515f6242408Spyr
516f6242408Spyr int
kw_cmp(const void * k,const void * e)517f6242408Spyr kw_cmp(const void *k, const void *e)
518f6242408Spyr {
519f6242408Spyr return (strcmp(k, ((const struct keywords *)e)->k_name));
520f6242408Spyr }
521f6242408Spyr
522f6242408Spyr int
lookup(char * s)523f6242408Spyr lookup(char *s)
524f6242408Spyr {
525f6242408Spyr /* this has to be sorted always */
526f6242408Spyr static const struct keywords keywords[] = {
527f6242408Spyr { "attribute", ATTRIBUTE },
528af720893Saschrijver { "basedn", BASEDN },
52956f45a56Sjmatthew { "bind", BIND },
530af720893Saschrijver { "bindcred", BINDCRED },
531f6242408Spyr { "binddn", BINDDN },
53240c94266Sjmatthew { "bindext", BINDEXT },
53332814761Sjmatthew { "cafile", CAFILE },
53440c94266Sjmatthew { "certfile", CERTFILE },
535f6242408Spyr { "change", CHANGE },
536f6242408Spyr { "class", CLASS },
537f6242408Spyr { "directory", DIRECTORY },
538f6242408Spyr { "domain", DOMAIN },
539f6242408Spyr { "expire", EXPIRE },
540f6242408Spyr { "filter", FILTER },
541f6242408Spyr { "fixed", FIXED },
542f6242408Spyr { "gecos", GECOS },
543f6242408Spyr { "gid", GID },
544f6242408Spyr { "group", GROUP },
545b8ccc478Sjmatthew { "groupdn", GROUPDN },
546f6242408Spyr { "groupgid", GROUPGID },
547f6242408Spyr { "groupmembers", GROUPMEMBERS },
548f6242408Spyr { "groupname", GROUPNAME },
549f6242408Spyr { "grouppasswd", GROUPPASSWD },
550f6242408Spyr { "home", HOME },
551f6242408Spyr { "include", INCLUDE },
552f6242408Spyr { "interval", INTERVAL },
55340c94266Sjmatthew { "keyfile", KEYFILE },
55432814761Sjmatthew { "ldaps", LDAPS },
555ec4ad443Saschrijver { "list", LIST },
55656f45a56Sjmatthew { "local", LOCAL },
557f6242408Spyr { "map", MAP },
558f6242408Spyr { "maps", MAPS },
559f6242408Spyr { "name", NAME },
560f6242408Spyr { "passwd", PASSWD },
561f6242408Spyr { "port", PORT },
56256f45a56Sjmatthew { "portmap", PORTMAP },
563f6242408Spyr { "provide", PROVIDE },
564f6242408Spyr { "server", SERVER },
565f6242408Spyr { "shell", SHELL },
56632814761Sjmatthew { "tls", TLS },
567f6242408Spyr { "to", TO },
568f6242408Spyr { "uid", UID },
569f6242408Spyr { "user", USER },
570f6242408Spyr };
571f6242408Spyr const struct keywords *p;
572f6242408Spyr
573f6242408Spyr p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
574f6242408Spyr sizeof(keywords[0]), kw_cmp);
575f6242408Spyr
576f6242408Spyr if (p)
577f6242408Spyr return (p->k_val);
578f6242408Spyr else
579f6242408Spyr return (STRING);
580f6242408Spyr }
581f6242408Spyr
582b83b389fSdenis #define START_EXPAND 1
583b83b389fSdenis #define DONE_EXPAND 2
584f6242408Spyr
585b83b389fSdenis static int expanding;
586b83b389fSdenis
587b83b389fSdenis int
igetc(void)588b83b389fSdenis igetc(void)
589b83b389fSdenis {
590b83b389fSdenis int c;
591b83b389fSdenis
592b83b389fSdenis while (1) {
593b83b389fSdenis if (file->ungetpos > 0)
594b83b389fSdenis c = file->ungetbuf[--file->ungetpos];
595b83b389fSdenis else
596b83b389fSdenis c = getc(file->stream);
597b83b389fSdenis
598b83b389fSdenis if (c == START_EXPAND)
599b83b389fSdenis expanding = 1;
600b83b389fSdenis else if (c == DONE_EXPAND)
601b83b389fSdenis expanding = 0;
602b83b389fSdenis else
603b83b389fSdenis break;
604b83b389fSdenis }
605b83b389fSdenis return (c);
606b83b389fSdenis }
607f6242408Spyr
608f6242408Spyr int
lgetc(int quotec)609f6242408Spyr lgetc(int quotec)
610f6242408Spyr {
611f6242408Spyr int c, next;
612f6242408Spyr
613f6242408Spyr if (quotec) {
614b83b389fSdenis if ((c = igetc()) == EOF) {
615f6242408Spyr yyerror("reached end of file while parsing "
616f6242408Spyr "quoted string");
617f6242408Spyr if (file == topfile || popfile() == EOF)
618f6242408Spyr return (EOF);
619f6242408Spyr return (quotec);
620f6242408Spyr }
621f6242408Spyr return (c);
622f6242408Spyr }
623f6242408Spyr
624b83b389fSdenis while ((c = igetc()) == '\\') {
625b83b389fSdenis next = igetc();
626f6242408Spyr if (next != '\n') {
627f6242408Spyr c = next;
628f6242408Spyr break;
629f6242408Spyr }
630f6242408Spyr yylval.lineno = file->lineno;
631f6242408Spyr file->lineno++;
632f6242408Spyr }
633f6242408Spyr
634b83b389fSdenis if (c == EOF) {
635b83b389fSdenis /*
636b83b389fSdenis * Fake EOL when hit EOF for the first time. This gets line
637b83b389fSdenis * count right if last line in included file is syntactically
638b83b389fSdenis * invalid and has no newline.
639b83b389fSdenis */
640b83b389fSdenis if (file->eof_reached == 0) {
641b83b389fSdenis file->eof_reached = 1;
642b83b389fSdenis return ('\n');
643b83b389fSdenis }
644f6242408Spyr while (c == EOF) {
645f6242408Spyr if (file == topfile || popfile() == EOF)
646f6242408Spyr return (EOF);
647b83b389fSdenis c = igetc();
648b83b389fSdenis }
649f6242408Spyr }
650f6242408Spyr return (c);
651f6242408Spyr }
652f6242408Spyr
653b83b389fSdenis void
lungetc(int c)654f6242408Spyr lungetc(int c)
655f6242408Spyr {
656f6242408Spyr if (c == EOF)
657b83b389fSdenis return;
658b83b389fSdenis
659b83b389fSdenis if (file->ungetpos >= file->ungetsize) {
660b83b389fSdenis void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
661b83b389fSdenis if (p == NULL)
662b83b389fSdenis err(1, "lungetc");
663b83b389fSdenis file->ungetbuf = p;
664b83b389fSdenis file->ungetsize *= 2;
665f6242408Spyr }
666b83b389fSdenis file->ungetbuf[file->ungetpos++] = c;
667f6242408Spyr }
668f6242408Spyr
669f6242408Spyr int
findeol(void)670f6242408Spyr findeol(void)
671f6242408Spyr {
672f6242408Spyr int c;
673f6242408Spyr
674f6242408Spyr /* skip to either EOF or the first real EOL */
675f6242408Spyr while (1) {
676f6242408Spyr c = lgetc(0);
677f6242408Spyr if (c == '\n') {
678f6242408Spyr file->lineno++;
679f6242408Spyr break;
680f6242408Spyr }
681f6242408Spyr if (c == EOF)
682f6242408Spyr break;
683f6242408Spyr }
684f6242408Spyr return (ERROR);
685f6242408Spyr }
686f6242408Spyr
687f6242408Spyr int
yylex(void)688f6242408Spyr yylex(void)
689f6242408Spyr {
69008f6ba19Snaddy char buf[8096];
69108f6ba19Snaddy char *p, *val;
692f6242408Spyr int quotec, next, c;
693f6242408Spyr int token;
694f6242408Spyr
695f6242408Spyr top:
696f6242408Spyr p = buf;
697f6242408Spyr while ((c = lgetc(0)) == ' ' || c == '\t')
698f6242408Spyr ; /* nothing */
699f6242408Spyr
700f6242408Spyr yylval.lineno = file->lineno;
701f6242408Spyr if (c == '#')
702f6242408Spyr while ((c = lgetc(0)) != '\n' && c != EOF)
703f6242408Spyr ; /* nothing */
704b83b389fSdenis if (c == '$' && !expanding) {
705f6242408Spyr while (1) {
706f6242408Spyr if ((c = lgetc(0)) == EOF)
707f6242408Spyr return (0);
708f6242408Spyr
709f6242408Spyr if (p + 1 >= buf + sizeof(buf) - 1) {
710f6242408Spyr yyerror("string too long");
711f6242408Spyr return (findeol());
712f6242408Spyr }
713f6242408Spyr if (isalnum(c) || c == '_') {
714015d7b4dSbenno *p++ = c;
715f6242408Spyr continue;
716f6242408Spyr }
717f6242408Spyr *p = '\0';
718f6242408Spyr lungetc(c);
719f6242408Spyr break;
720f6242408Spyr }
721f6242408Spyr val = symget(buf);
722f6242408Spyr if (val == NULL) {
723f6242408Spyr yyerror("macro '%s' not defined", buf);
724f6242408Spyr return (findeol());
725f6242408Spyr }
726b83b389fSdenis p = val + strlen(val) - 1;
727b83b389fSdenis lungetc(DONE_EXPAND);
728b83b389fSdenis while (p >= val) {
72908f6ba19Snaddy lungetc((unsigned char)*p);
730b83b389fSdenis p--;
731b83b389fSdenis }
732b83b389fSdenis lungetc(START_EXPAND);
733f6242408Spyr goto top;
734f6242408Spyr }
735f6242408Spyr
736f6242408Spyr switch (c) {
737f6242408Spyr case '\'':
738f6242408Spyr case '"':
739f6242408Spyr quotec = c;
740f6242408Spyr while (1) {
741f6242408Spyr if ((c = lgetc(quotec)) == EOF)
742f6242408Spyr return (0);
743f6242408Spyr if (c == '\n') {
744f6242408Spyr file->lineno++;
745f6242408Spyr continue;
746f6242408Spyr } else if (c == '\\') {
747f6242408Spyr if ((next = lgetc(quotec)) == EOF)
748f6242408Spyr return (0);
749a1533359Ssashan if (next == quotec || next == ' ' ||
750a1533359Ssashan next == '\t')
751f6242408Spyr c = next;
752daf24110Shenning else if (next == '\n') {
753daf24110Shenning file->lineno++;
754f6242408Spyr continue;
755daf24110Shenning } else
756f6242408Spyr lungetc(next);
757f6242408Spyr } else if (c == quotec) {
758f6242408Spyr *p = '\0';
759f6242408Spyr break;
76041eef22fSjsg } else if (c == '\0') {
76141eef22fSjsg yyerror("syntax error");
76241eef22fSjsg return (findeol());
763f6242408Spyr }
764f6242408Spyr if (p + 1 >= buf + sizeof(buf) - 1) {
765f6242408Spyr yyerror("string too long");
766f6242408Spyr return (findeol());
767f6242408Spyr }
768015d7b4dSbenno *p++ = c;
769f6242408Spyr }
770f6242408Spyr yylval.v.string = strdup(buf);
771f6242408Spyr if (yylval.v.string == NULL)
772a062aa9dSkrw err(1, "%s", __func__);
773f6242408Spyr return (STRING);
774f6242408Spyr }
775f6242408Spyr
776f6242408Spyr #define allowed_to_end_number(x) \
777f6242408Spyr (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
778f6242408Spyr
779f6242408Spyr if (c == '-' || isdigit(c)) {
780f6242408Spyr do {
781f6242408Spyr *p++ = c;
782915c3f33Sderaadt if ((size_t)(p-buf) >= sizeof(buf)) {
783f6242408Spyr yyerror("string too long");
784f6242408Spyr return (findeol());
785f6242408Spyr }
786f6242408Spyr } while ((c = lgetc(0)) != EOF && isdigit(c));
787f6242408Spyr lungetc(c);
788f6242408Spyr if (p == buf + 1 && buf[0] == '-')
789f6242408Spyr goto nodigits;
790f6242408Spyr if (c == EOF || allowed_to_end_number(c)) {
791f6242408Spyr const char *errstr = NULL;
792f6242408Spyr
793f6242408Spyr *p = '\0';
794f6242408Spyr yylval.v.number = strtonum(buf, LLONG_MIN,
795f6242408Spyr LLONG_MAX, &errstr);
796f6242408Spyr if (errstr) {
797f6242408Spyr yyerror("\"%s\" invalid number: %s",
798f6242408Spyr buf, errstr);
799f6242408Spyr return (findeol());
800f6242408Spyr }
801f6242408Spyr return (NUMBER);
802f6242408Spyr } else {
803f6242408Spyr nodigits:
804f6242408Spyr while (p > buf + 1)
80508f6ba19Snaddy lungetc((unsigned char)*--p);
80608f6ba19Snaddy c = (unsigned char)*--p;
807f6242408Spyr if (c == '-')
808f6242408Spyr return (c);
809f6242408Spyr }
810f6242408Spyr }
811f6242408Spyr
812f6242408Spyr #define allowed_in_string(x) \
813f6242408Spyr (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
814f6242408Spyr x != '{' && x != '}' && x != '<' && x != '>' && \
815f6242408Spyr x != '!' && x != '=' && x != '#' && \
816f6242408Spyr x != ','))
817f6242408Spyr
818f6242408Spyr if (isalnum(c) || c == ':' || c == '_') {
819f6242408Spyr do {
820f6242408Spyr *p++ = c;
821915c3f33Sderaadt if ((size_t)(p-buf) >= sizeof(buf)) {
822f6242408Spyr yyerror("string too long");
823f6242408Spyr return (findeol());
824f6242408Spyr }
825f6242408Spyr } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
826f6242408Spyr lungetc(c);
827f6242408Spyr *p = '\0';
828f6242408Spyr if ((token = lookup(buf)) == STRING)
829f6242408Spyr if ((yylval.v.string = strdup(buf)) == NULL)
830a062aa9dSkrw err(1, "%s", __func__);
831f6242408Spyr return (token);
832f6242408Spyr }
833f6242408Spyr if (c == '\n') {
834f6242408Spyr yylval.lineno = file->lineno;
835f6242408Spyr file->lineno++;
836f6242408Spyr }
837f6242408Spyr if (c == EOF)
838f6242408Spyr return (0);
839f6242408Spyr return (c);
840f6242408Spyr }
841f6242408Spyr
842f6242408Spyr int
check_file_secrecy(int fd,const char * fname)843f6242408Spyr check_file_secrecy(int fd, const char *fname)
844f6242408Spyr {
845f6242408Spyr struct stat st;
846f6242408Spyr
847f6242408Spyr if (fstat(fd, &st)) {
848f6242408Spyr log_warn("cannot stat %s", fname);
849f6242408Spyr return (-1);
850f6242408Spyr }
851f6242408Spyr if (st.st_uid != 0 && st.st_uid != getuid()) {
852f6242408Spyr log_warnx("%s: owner not root or current user", fname);
853f6242408Spyr return (-1);
854f6242408Spyr }
8557140c133Shenning if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
8567140c133Shenning log_warnx("%s: group writable or world read/writable", fname);
857f6242408Spyr return (-1);
858f6242408Spyr }
859f6242408Spyr return (0);
860f6242408Spyr }
861f6242408Spyr
862f6242408Spyr struct file *
pushfile(const char * name,int secret)863f6242408Spyr pushfile(const char *name, int secret)
864f6242408Spyr {
865f6242408Spyr struct file *nfile;
866f6242408Spyr
8677fc93de0Stobias if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
8686a3d55f9Skrw log_warn("%s", __func__);
869f6242408Spyr return (NULL);
870f6242408Spyr }
8717fc93de0Stobias if ((nfile->name = strdup(name)) == NULL) {
8726a3d55f9Skrw log_warn("%s", __func__);
8737fc93de0Stobias free(nfile);
8747fc93de0Stobias return (NULL);
8757fc93de0Stobias }
876f6242408Spyr if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
8776a3d55f9Skrw log_warn("%s: %s", __func__, nfile->name);
878f6242408Spyr free(nfile->name);
879f6242408Spyr free(nfile);
880f6242408Spyr return (NULL);
881f6242408Spyr } else if (secret &&
882f6242408Spyr check_file_secrecy(fileno(nfile->stream), nfile->name)) {
883f6242408Spyr fclose(nfile->stream);
884f6242408Spyr free(nfile->name);
885f6242408Spyr free(nfile);
886f6242408Spyr return (NULL);
887f6242408Spyr }
888b83b389fSdenis nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
889b83b389fSdenis nfile->ungetsize = 16;
890b83b389fSdenis nfile->ungetbuf = malloc(nfile->ungetsize);
891b83b389fSdenis if (nfile->ungetbuf == NULL) {
8926a3d55f9Skrw log_warn("%s", __func__);
893b83b389fSdenis fclose(nfile->stream);
894b83b389fSdenis free(nfile->name);
895b83b389fSdenis free(nfile);
896b83b389fSdenis return (NULL);
897b83b389fSdenis }
898f6242408Spyr TAILQ_INSERT_TAIL(&files, nfile, entry);
899f6242408Spyr return (nfile);
900f6242408Spyr }
901f6242408Spyr
902f6242408Spyr int
popfile(void)903f6242408Spyr popfile(void)
904f6242408Spyr {
905f6242408Spyr struct file *prev;
906f6242408Spyr
907f6242408Spyr if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
908f6242408Spyr prev->errors += file->errors;
909f6242408Spyr
910f6242408Spyr TAILQ_REMOVE(&files, file, entry);
911f6242408Spyr fclose(file->stream);
912f6242408Spyr free(file->name);
913b83b389fSdenis free(file->ungetbuf);
914f6242408Spyr free(file);
915f6242408Spyr file = prev;
916f6242408Spyr return (file ? 0 : EOF);
917f6242408Spyr }
918f6242408Spyr
919f6242408Spyr int
parse_config(struct env * x_conf,const char * filename,int opts)920f6242408Spyr parse_config(struct env *x_conf, const char *filename, int opts)
921f6242408Spyr {
922f6242408Spyr struct sym *sym, *next;
923f6242408Spyr
924f6242408Spyr conf = x_conf;
925f6242408Spyr bzero(conf, sizeof(*conf));
926f6242408Spyr
927f6242408Spyr TAILQ_INIT(&conf->sc_idms);
928f6242408Spyr conf->sc_conf_tv.tv_sec = DEFAULT_INTERVAL;
929f6242408Spyr conf->sc_conf_tv.tv_usec = 0;
930fb0a89eeStedu conf->sc_cafile = strdup(tls_default_ca_cert_file());
93132814761Sjmatthew if (conf->sc_cafile == NULL) {
9326a3d55f9Skrw log_warn("%s", __func__);
93332814761Sjmatthew return (-1);
93432814761Sjmatthew }
93556f45a56Sjmatthew conf->sc_bind_mode = BIND_MODE_PORTMAP;
936f6242408Spyr
937f6242408Spyr errors = 0;
938f6242408Spyr
939385f9e8cSdlg if ((file = pushfile(filename, 1)) == NULL) {
940f6242408Spyr return (-1);
941f6242408Spyr }
942f6242408Spyr topfile = file;
943f6242408Spyr
944f6242408Spyr /*
945f6242408Spyr * parse configuration
946f6242408Spyr */
947f6242408Spyr setservent(1);
948f6242408Spyr yyparse();
949f6242408Spyr endservent();
950f6242408Spyr errors = file->errors;
951f6242408Spyr popfile();
952f6242408Spyr
953f6242408Spyr /* Free macros and check which have not been used. */
95446bca67bSkrw TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
955f6242408Spyr if ((opts & YPLDAP_OPT_VERBOSE) && !sym->used)
956f6242408Spyr fprintf(stderr, "warning: macro '%s' not "
957f6242408Spyr "used\n", sym->nam);
958f6242408Spyr if (!sym->persist) {
959f6242408Spyr free(sym->nam);
960f6242408Spyr free(sym->val);
961f6242408Spyr TAILQ_REMOVE(&symhead, sym, entry);
962f6242408Spyr free(sym);
963f6242408Spyr }
964f6242408Spyr }
965f6242408Spyr
966f6242408Spyr if (errors) {
967f6242408Spyr return (-1);
968f6242408Spyr }
969f6242408Spyr
970f6242408Spyr return (0);
971f6242408Spyr }
972f6242408Spyr
973f6242408Spyr int
symset(const char * nam,const char * val,int persist)974f6242408Spyr symset(const char *nam, const char *val, int persist)
975f6242408Spyr {
976f6242408Spyr struct sym *sym;
977f6242408Spyr
97854c95b7aSkrw TAILQ_FOREACH(sym, &symhead, entry) {
97954c95b7aSkrw if (strcmp(nam, sym->nam) == 0)
98054c95b7aSkrw break;
98154c95b7aSkrw }
982f6242408Spyr
983f6242408Spyr if (sym != NULL) {
984f6242408Spyr if (sym->persist == 1)
985f6242408Spyr return (0);
986f6242408Spyr else {
987f6242408Spyr free(sym->nam);
988f6242408Spyr free(sym->val);
989f6242408Spyr TAILQ_REMOVE(&symhead, sym, entry);
990f6242408Spyr free(sym);
991f6242408Spyr }
992f6242408Spyr }
993f6242408Spyr if ((sym = calloc(1, sizeof(*sym))) == NULL)
994f6242408Spyr return (-1);
995f6242408Spyr
996f6242408Spyr sym->nam = strdup(nam);
997f6242408Spyr if (sym->nam == NULL) {
998f6242408Spyr free(sym);
999f6242408Spyr return (-1);
1000f6242408Spyr }
1001f6242408Spyr sym->val = strdup(val);
1002f6242408Spyr if (sym->val == NULL) {
1003f6242408Spyr free(sym->nam);
1004f6242408Spyr free(sym);
1005f6242408Spyr return (-1);
1006f6242408Spyr }
1007f6242408Spyr sym->used = 0;
1008f6242408Spyr sym->persist = persist;
1009f6242408Spyr TAILQ_INSERT_TAIL(&symhead, sym, entry);
1010f6242408Spyr return (0);
1011f6242408Spyr }
1012f6242408Spyr
1013f6242408Spyr int
cmdline_symset(char * s)1014f6242408Spyr cmdline_symset(char *s)
1015f6242408Spyr {
1016f6242408Spyr char *sym, *val;
1017f6242408Spyr int ret;
1018f6242408Spyr
1019f6242408Spyr if ((val = strrchr(s, '=')) == NULL)
1020f6242408Spyr return (-1);
1021ed1b9eb8Smiko sym = strndup(s, val - s);
1022ed1b9eb8Smiko if (sym == NULL)
1023ed1b9eb8Smiko errx(1, "%s: strndup", __func__);
1024f6242408Spyr ret = symset(sym, val + 1, 1);
1025f6242408Spyr free(sym);
1026f6242408Spyr
1027f6242408Spyr return (ret);
1028f6242408Spyr }
1029f6242408Spyr
1030f6242408Spyr char *
symget(const char * nam)1031f6242408Spyr symget(const char *nam)
1032f6242408Spyr {
1033f6242408Spyr struct sym *sym;
1034f6242408Spyr
103554c95b7aSkrw TAILQ_FOREACH(sym, &symhead, entry) {
1036f6242408Spyr if (strcmp(nam, sym->nam) == 0) {
1037f6242408Spyr sym->used = 1;
1038f6242408Spyr return (sym->val);
1039f6242408Spyr }
104054c95b7aSkrw }
1041f6242408Spyr return (NULL);
1042f6242408Spyr }
1043