xref: /titanic_54/usr/src/lib/libsmbfs/smb/rcfile.c (revision 4bff34e37def8a90f9194d81bc345c52ba20086a)
1*4bff34e3Sthurlow /*
2*4bff34e3Sthurlow  * Copyright (c) 2000, Boris Popov
3*4bff34e3Sthurlow  * All rights reserved.
4*4bff34e3Sthurlow  *
5*4bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
6*4bff34e3Sthurlow  * modification, are permitted provided that the following conditions
7*4bff34e3Sthurlow  * are met:
8*4bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
9*4bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
10*4bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
11*4bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
12*4bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
13*4bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
14*4bff34e3Sthurlow  *    must display the following acknowledgement:
15*4bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
16*4bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
17*4bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
18*4bff34e3Sthurlow  *    without specific prior written permission.
19*4bff34e3Sthurlow  *
20*4bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21*4bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*4bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*4bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24*4bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25*4bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26*4bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*4bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28*4bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29*4bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30*4bff34e3Sthurlow  * SUCH DAMAGE.
31*4bff34e3Sthurlow  *
32*4bff34e3Sthurlow  * $Id: rcfile.c,v 1.1.1.2 2001/07/06 22:38:43 conrad Exp $
33*4bff34e3Sthurlow  */
34*4bff34e3Sthurlow 
35*4bff34e3Sthurlow #pragma ident	"%Z%%M%	%I%	%E% SMI"
36*4bff34e3Sthurlow 
37*4bff34e3Sthurlow #include <fcntl.h>
38*4bff34e3Sthurlow #include <sys/types.h>
39*4bff34e3Sthurlow #include <sys/queue.h>
40*4bff34e3Sthurlow #include <sys/stat.h>
41*4bff34e3Sthurlow #include <ctype.h>
42*4bff34e3Sthurlow #include <errno.h>
43*4bff34e3Sthurlow #include <stdio.h>
44*4bff34e3Sthurlow #include <string.h>
45*4bff34e3Sthurlow #include <strings.h>
46*4bff34e3Sthurlow #include <stdlib.h>
47*4bff34e3Sthurlow #include <libintl.h>
48*4bff34e3Sthurlow #include <pwd.h>
49*4bff34e3Sthurlow #include <unistd.h>
50*4bff34e3Sthurlow #include <sys/debug.h>
51*4bff34e3Sthurlow 
52*4bff34e3Sthurlow #include <cflib.h>
53*4bff34e3Sthurlow #include "rcfile_priv.h"
54*4bff34e3Sthurlow 
55*4bff34e3Sthurlow SLIST_HEAD(rcfile_head, rcfile);
56*4bff34e3Sthurlow static struct rcfile_head pf_head = {NULL};
57*4bff34e3Sthurlow 
58*4bff34e3Sthurlow static struct rcfile *rc_cachelookup(const char *filename);
59*4bff34e3Sthurlow struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname);
60*4bff34e3Sthurlow static struct rcsection *rc_addsect(struct rcfile *rcp, const char *sectname);
61*4bff34e3Sthurlow static int rc_freesect(struct rcfile *rcp, struct rcsection *rsp);
62*4bff34e3Sthurlow struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname);
63*4bff34e3Sthurlow static struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name,
64*4bff34e3Sthurlow     const char *value);
65*4bff34e3Sthurlow static void rc_key_free(struct rckey *p);
66*4bff34e3Sthurlow static void rc_parse(struct rcfile *rcp);
67*4bff34e3Sthurlow 
68*4bff34e3Sthurlow int insecure_nsmbrc;
69*4bff34e3Sthurlow 
70*4bff34e3Sthurlow /*
71*4bff34e3Sthurlow  * open rcfile and load its content, if already open - return previous handle
72*4bff34e3Sthurlow  */
73*4bff34e3Sthurlow int
74*4bff34e3Sthurlow rc_open(const char *filename, const char *mode, struct rcfile **rcfile)
75*4bff34e3Sthurlow {
76*4bff34e3Sthurlow 	struct rcfile *rcp;
77*4bff34e3Sthurlow 	FILE *f;
78*4bff34e3Sthurlow 	struct stat statbuf;
79*4bff34e3Sthurlow 
80*4bff34e3Sthurlow 	rcp = rc_cachelookup(filename);
81*4bff34e3Sthurlow 	if (rcp) {
82*4bff34e3Sthurlow 		*rcfile = rcp;
83*4bff34e3Sthurlow 		return (0);
84*4bff34e3Sthurlow 	}
85*4bff34e3Sthurlow 	f = fopen(filename, mode);
86*4bff34e3Sthurlow 	if (f == NULL)
87*4bff34e3Sthurlow 		return (errno);
88*4bff34e3Sthurlow 	insecure_nsmbrc = 0;
89*4bff34e3Sthurlow 	if (fstat(fileno(f), &statbuf) >= 0 &&
90*4bff34e3Sthurlow 	    (statbuf.st_mode & 077) != 0)
91*4bff34e3Sthurlow 		insecure_nsmbrc = 1;
92*4bff34e3Sthurlow 	rcp = malloc(sizeof (struct rcfile));
93*4bff34e3Sthurlow 	if (rcp == NULL) {
94*4bff34e3Sthurlow 		fclose(f);
95*4bff34e3Sthurlow 		return (ENOMEM);
96*4bff34e3Sthurlow 	}
97*4bff34e3Sthurlow 	bzero(rcp, sizeof (struct rcfile));
98*4bff34e3Sthurlow 	rcp->rf_name = strdup(filename);
99*4bff34e3Sthurlow 	rcp->rf_f = f;
100*4bff34e3Sthurlow 	SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
101*4bff34e3Sthurlow 	rc_parse(rcp);
102*4bff34e3Sthurlow 	*rcfile = rcp;
103*4bff34e3Sthurlow 	return (0);
104*4bff34e3Sthurlow }
105*4bff34e3Sthurlow 
106*4bff34e3Sthurlow int
107*4bff34e3Sthurlow rc_merge(const char *filename, struct rcfile **rcfile)
108*4bff34e3Sthurlow {
109*4bff34e3Sthurlow 	struct rcfile *rcp = *rcfile;
110*4bff34e3Sthurlow 	FILE *f, *t;
111*4bff34e3Sthurlow 
112*4bff34e3Sthurlow 	insecure_nsmbrc = 0;
113*4bff34e3Sthurlow 	if (rcp == NULL) {
114*4bff34e3Sthurlow 		return (rc_open(filename, "r", rcfile));
115*4bff34e3Sthurlow 	}
116*4bff34e3Sthurlow 	f = fopen(filename, "r");
117*4bff34e3Sthurlow 	if (f == NULL)
118*4bff34e3Sthurlow 		return (errno);
119*4bff34e3Sthurlow 	t = rcp->rf_f;
120*4bff34e3Sthurlow 	rcp->rf_f = f;
121*4bff34e3Sthurlow 	rc_parse(rcp);
122*4bff34e3Sthurlow 	rcp->rf_f = t;
123*4bff34e3Sthurlow 	fclose(f);
124*4bff34e3Sthurlow 	return (0);
125*4bff34e3Sthurlow }
126*4bff34e3Sthurlow 
127*4bff34e3Sthurlow int
128*4bff34e3Sthurlow rc_merge_pipe(const char *command, struct rcfile **rcfile)
129*4bff34e3Sthurlow {
130*4bff34e3Sthurlow 	struct rcfile *rcp = *rcfile;
131*4bff34e3Sthurlow 	FILE *f, *t;
132*4bff34e3Sthurlow 
133*4bff34e3Sthurlow 	insecure_nsmbrc = 0;
134*4bff34e3Sthurlow 	f = popen(command, "r");
135*4bff34e3Sthurlow 	if (f == NULL)
136*4bff34e3Sthurlow 		return (errno);
137*4bff34e3Sthurlow 	if (rcp == NULL) {
138*4bff34e3Sthurlow 		rcp = malloc(sizeof (struct rcfile));
139*4bff34e3Sthurlow 		if (rcp == NULL) {
140*4bff34e3Sthurlow 			fclose(f);
141*4bff34e3Sthurlow 			return (ENOMEM);
142*4bff34e3Sthurlow 		}
143*4bff34e3Sthurlow 		*rcfile = rcp;
144*4bff34e3Sthurlow 		bzero(rcp, sizeof (struct rcfile));
145*4bff34e3Sthurlow 		rcp->rf_name = strdup(command);
146*4bff34e3Sthurlow 		rcp->rf_f = f;
147*4bff34e3Sthurlow 		SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
148*4bff34e3Sthurlow 		rc_parse(rcp);
149*4bff34e3Sthurlow 	} else {
150*4bff34e3Sthurlow 		t = rcp->rf_f;
151*4bff34e3Sthurlow 		rcp->rf_f = f;
152*4bff34e3Sthurlow 		rc_parse(rcp);
153*4bff34e3Sthurlow 		rcp->rf_f = t;
154*4bff34e3Sthurlow 	}
155*4bff34e3Sthurlow 	fclose(f);
156*4bff34e3Sthurlow 	return (0);
157*4bff34e3Sthurlow }
158*4bff34e3Sthurlow 
159*4bff34e3Sthurlow int
160*4bff34e3Sthurlow rc_close(struct rcfile *rcp)
161*4bff34e3Sthurlow {
162*4bff34e3Sthurlow 	struct rcsection *p, *n;
163*4bff34e3Sthurlow 
164*4bff34e3Sthurlow 	fclose(rcp->rf_f);
165*4bff34e3Sthurlow 	for (p = SLIST_FIRST(&rcp->rf_sect); p; ) {
166*4bff34e3Sthurlow 		n = p;
167*4bff34e3Sthurlow 		p = SLIST_NEXT(p, rs_next);
168*4bff34e3Sthurlow 		rc_freesect(rcp, n);
169*4bff34e3Sthurlow 	}
170*4bff34e3Sthurlow 	free(rcp->rf_name);
171*4bff34e3Sthurlow 	SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next);
172*4bff34e3Sthurlow 	free(rcp);
173*4bff34e3Sthurlow 	return (0);
174*4bff34e3Sthurlow }
175*4bff34e3Sthurlow 
176*4bff34e3Sthurlow static struct rcfile *
177*4bff34e3Sthurlow rc_cachelookup(const char *filename)
178*4bff34e3Sthurlow {
179*4bff34e3Sthurlow 	struct rcfile *p;
180*4bff34e3Sthurlow 
181*4bff34e3Sthurlow 	SLIST_FOREACH(p, &pf_head, rf_next)
182*4bff34e3Sthurlow 		if (strcmp(filename, p->rf_name) == 0)
183*4bff34e3Sthurlow 			return (p);
184*4bff34e3Sthurlow 	return (0);
185*4bff34e3Sthurlow }
186*4bff34e3Sthurlow 
187*4bff34e3Sthurlow /* static */ struct rcsection *
188*4bff34e3Sthurlow rc_findsect(struct rcfile *rcp, const char *sectname)
189*4bff34e3Sthurlow {
190*4bff34e3Sthurlow 	struct rcsection *p;
191*4bff34e3Sthurlow 
192*4bff34e3Sthurlow 	SLIST_FOREACH(p, &rcp->rf_sect, rs_next)
193*4bff34e3Sthurlow 		if (strcasecmp(p->rs_name, sectname) == 0)
194*4bff34e3Sthurlow 			return (p);
195*4bff34e3Sthurlow 	return (NULL);
196*4bff34e3Sthurlow }
197*4bff34e3Sthurlow 
198*4bff34e3Sthurlow static struct rcsection *
199*4bff34e3Sthurlow rc_addsect(struct rcfile *rcp, const char *sectname)
200*4bff34e3Sthurlow {
201*4bff34e3Sthurlow 	struct rcsection *p;
202*4bff34e3Sthurlow 
203*4bff34e3Sthurlow 	p = rc_findsect(rcp, sectname);
204*4bff34e3Sthurlow 	if (p)
205*4bff34e3Sthurlow 		return (p);
206*4bff34e3Sthurlow 	p = malloc(sizeof (*p));
207*4bff34e3Sthurlow 	if (!p)
208*4bff34e3Sthurlow 		return (NULL);
209*4bff34e3Sthurlow 	p->rs_name = strdup(sectname);
210*4bff34e3Sthurlow 	SLIST_INIT(&p->rs_keys);
211*4bff34e3Sthurlow 	SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next);
212*4bff34e3Sthurlow 	return (p);
213*4bff34e3Sthurlow }
214*4bff34e3Sthurlow 
215*4bff34e3Sthurlow static int
216*4bff34e3Sthurlow rc_freesect(struct rcfile *rcp, struct rcsection *rsp)
217*4bff34e3Sthurlow {
218*4bff34e3Sthurlow 	struct rckey *p, *n;
219*4bff34e3Sthurlow 
220*4bff34e3Sthurlow 	SLIST_REMOVE(&rcp->rf_sect, rsp, rcsection, rs_next);
221*4bff34e3Sthurlow 	for (p = SLIST_FIRST(&rsp->rs_keys); p; ) {
222*4bff34e3Sthurlow 		n = p;
223*4bff34e3Sthurlow 		p = SLIST_NEXT(p, rk_next);
224*4bff34e3Sthurlow 		rc_key_free(n);
225*4bff34e3Sthurlow 	}
226*4bff34e3Sthurlow 	free(rsp->rs_name);
227*4bff34e3Sthurlow 	free(rsp);
228*4bff34e3Sthurlow 	return (0);
229*4bff34e3Sthurlow }
230*4bff34e3Sthurlow 
231*4bff34e3Sthurlow /* static */ struct rckey *
232*4bff34e3Sthurlow rc_sect_findkey(struct rcsection *rsp, const char *keyname)
233*4bff34e3Sthurlow {
234*4bff34e3Sthurlow 	struct rckey *p;
235*4bff34e3Sthurlow 
236*4bff34e3Sthurlow 	SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
237*4bff34e3Sthurlow 		if (strcmp(p->rk_name, keyname) == 0)
238*4bff34e3Sthurlow 			return (p);
239*4bff34e3Sthurlow 	return (NULL);
240*4bff34e3Sthurlow }
241*4bff34e3Sthurlow 
242*4bff34e3Sthurlow static struct rckey *
243*4bff34e3Sthurlow rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value)
244*4bff34e3Sthurlow {
245*4bff34e3Sthurlow 	struct rckey *p;
246*4bff34e3Sthurlow 
247*4bff34e3Sthurlow 	p = rc_sect_findkey(rsp, name);
248*4bff34e3Sthurlow 	if (!p) {
249*4bff34e3Sthurlow 		p = malloc(sizeof (*p));
250*4bff34e3Sthurlow 		if (!p)
251*4bff34e3Sthurlow 			return (NULL);
252*4bff34e3Sthurlow 		SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next);
253*4bff34e3Sthurlow 		p->rk_name = strdup(name);
254*4bff34e3Sthurlow 		p->rk_value = value ? strdup(value) : strdup("");
255*4bff34e3Sthurlow 	}
256*4bff34e3Sthurlow 	return (p);
257*4bff34e3Sthurlow }
258*4bff34e3Sthurlow 
259*4bff34e3Sthurlow #if 0
260*4bff34e3Sthurlow void
261*4bff34e3Sthurlow rc_sect_delkey(struct rcsection *rsp, struct rckey *p)
262*4bff34e3Sthurlow {
263*4bff34e3Sthurlow 
264*4bff34e3Sthurlow 	SLIST_REMOVE(&rsp->rs_keys, p, rckey, rk_next);
265*4bff34e3Sthurlow 	rc_key_free(p);
266*4bff34e3Sthurlow }
267*4bff34e3Sthurlow #endif
268*4bff34e3Sthurlow 
269*4bff34e3Sthurlow static void
270*4bff34e3Sthurlow rc_key_free(struct rckey *p)
271*4bff34e3Sthurlow {
272*4bff34e3Sthurlow 	free(p->rk_value);
273*4bff34e3Sthurlow 	free(p->rk_name);
274*4bff34e3Sthurlow 	free(p);
275*4bff34e3Sthurlow }
276*4bff34e3Sthurlow 
277*4bff34e3Sthurlow enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
278*4bff34e3Sthurlow 
279*4bff34e3Sthurlow int home_nsmbrc = 0;
280*4bff34e3Sthurlow 
281*4bff34e3Sthurlow static char *minauth[] = {
282*4bff34e3Sthurlow 	"kerberos",
283*4bff34e3Sthurlow 	"ntlmv2",
284*4bff34e3Sthurlow 	"ntlm",
285*4bff34e3Sthurlow 	"lm",
286*4bff34e3Sthurlow 	"none",
287*4bff34e3Sthurlow 	NULL
288*4bff34e3Sthurlow };
289*4bff34e3Sthurlow 
290*4bff34e3Sthurlow static int
291*4bff34e3Sthurlow eval_minauth(char *auth)
292*4bff34e3Sthurlow {
293*4bff34e3Sthurlow 	int i;
294*4bff34e3Sthurlow 
295*4bff34e3Sthurlow 	for (i = 0; minauth[i]; i++)
296*4bff34e3Sthurlow 		if (strcmp(auth, minauth[i]) == 0)
297*4bff34e3Sthurlow 			break;
298*4bff34e3Sthurlow 	return (i);
299*4bff34e3Sthurlow }
300*4bff34e3Sthurlow 
301*4bff34e3Sthurlow /*
302*4bff34e3Sthurlow  * Ensure that "minauth" is set to the highest level (lowest array offset)
303*4bff34e3Sthurlow  */
304*4bff34e3Sthurlow static void
305*4bff34e3Sthurlow set_value(struct rcfile *rcp, struct rcsection *rsp, struct rckey *rkp,
306*4bff34e3Sthurlow     char *ptr)
307*4bff34e3Sthurlow {
308*4bff34e3Sthurlow 	int now, new;
309*4bff34e3Sthurlow 
310*4bff34e3Sthurlow 	if (strcmp(rkp->rk_name, "minauth") == 0) {
311*4bff34e3Sthurlow 		now = eval_minauth(rkp->rk_value);
312*4bff34e3Sthurlow 		new = eval_minauth(ptr);
313*4bff34e3Sthurlow 		if (new >= now) {
314*4bff34e3Sthurlow #ifdef DEBUG
315*4bff34e3Sthurlow 		printf("set_value: rejecting %s=%s from %s\n",
316*4bff34e3Sthurlow 		    rkp->rk_name, ptr, home_nsmbrc ? "user file" : "SMF");
317*4bff34e3Sthurlow #endif
318*4bff34e3Sthurlow 			return;
319*4bff34e3Sthurlow 		}
320*4bff34e3Sthurlow 	}
321*4bff34e3Sthurlow #ifdef DEBUG
322*4bff34e3Sthurlow 	printf("set_value: applying %s=%s from %s\n",
323*4bff34e3Sthurlow 	    rkp->rk_name, ptr, home_nsmbrc ? "user file" : "SMF");
324*4bff34e3Sthurlow #endif
325*4bff34e3Sthurlow 	rkp->rk_value = strdup(ptr);
326*4bff34e3Sthurlow }
327*4bff34e3Sthurlow 
328*4bff34e3Sthurlow static void
329*4bff34e3Sthurlow rc_parse(struct rcfile *rcp)
330*4bff34e3Sthurlow {
331*4bff34e3Sthurlow 	FILE *f = rcp->rf_f;
332*4bff34e3Sthurlow 	int state = stNewLine, c;
333*4bff34e3Sthurlow 	struct rcsection *rsp = NULL;
334*4bff34e3Sthurlow 	struct rckey *rkp = NULL;
335*4bff34e3Sthurlow 	char buf[2048];
336*4bff34e3Sthurlow 	char *next = buf, *last = &buf[sizeof (buf)-1];
337*4bff34e3Sthurlow 
338*4bff34e3Sthurlow 	while ((c = getc(f)) != EOF) {
339*4bff34e3Sthurlow 		if (c == '\r')
340*4bff34e3Sthurlow 			continue;
341*4bff34e3Sthurlow 		if (state == stNewLine) {
342*4bff34e3Sthurlow 			next = buf;
343*4bff34e3Sthurlow 			if (isspace(c))
344*4bff34e3Sthurlow 				continue;	/* skip leading junk */
345*4bff34e3Sthurlow 			if (c == '[') {
346*4bff34e3Sthurlow 				state = stHeader;
347*4bff34e3Sthurlow 				rsp = NULL;
348*4bff34e3Sthurlow 				continue;
349*4bff34e3Sthurlow 			}
350*4bff34e3Sthurlow 			if (c == '#' || c == ';') {
351*4bff34e3Sthurlow 				state = stSkipToEOL;
352*4bff34e3Sthurlow 			} else {		/* something meaningfull */
353*4bff34e3Sthurlow 				state = stGetKey;
354*4bff34e3Sthurlow 			}
355*4bff34e3Sthurlow 		}
356*4bff34e3Sthurlow 		/* ignore long lines */
357*4bff34e3Sthurlow 		if (state == stSkipToEOL || next == last) {
358*4bff34e3Sthurlow 			if (c == '\n') {
359*4bff34e3Sthurlow 				state = stNewLine;
360*4bff34e3Sthurlow 				next = buf;
361*4bff34e3Sthurlow 			}
362*4bff34e3Sthurlow 			continue;
363*4bff34e3Sthurlow 		}
364*4bff34e3Sthurlow 		if (state == stHeader) {
365*4bff34e3Sthurlow 			if (c == ']') {
366*4bff34e3Sthurlow 				*next = 0;
367*4bff34e3Sthurlow 				next = buf;
368*4bff34e3Sthurlow 				rsp = rc_addsect(rcp, buf);
369*4bff34e3Sthurlow 				state = stSkipToEOL;
370*4bff34e3Sthurlow 			} else
371*4bff34e3Sthurlow 				*next++ = c;
372*4bff34e3Sthurlow 			continue;
373*4bff34e3Sthurlow 		}
374*4bff34e3Sthurlow 		if (state == stGetKey) {
375*4bff34e3Sthurlow 			/* side effect: 'key name=' */
376*4bff34e3Sthurlow 			if (c == ' ' || c == '\t')
377*4bff34e3Sthurlow 				continue;	/* become 'keyname=' */
378*4bff34e3Sthurlow 			if (c == '\n') {	/* silently ignore ... */
379*4bff34e3Sthurlow 				state = stNewLine;
380*4bff34e3Sthurlow 				continue;
381*4bff34e3Sthurlow 			}
382*4bff34e3Sthurlow 			if (c != '=') {
383*4bff34e3Sthurlow 				*next++ = c;
384*4bff34e3Sthurlow 				continue;
385*4bff34e3Sthurlow 			}
386*4bff34e3Sthurlow 			*next = 0;
387*4bff34e3Sthurlow 			if (rsp == NULL) {
388*4bff34e3Sthurlow 				fprintf(stderr, dgettext(TEXT_DOMAIN,
389*4bff34e3Sthurlow 				    "Key '%s' defined before section\n"), buf);
390*4bff34e3Sthurlow 				state = stSkipToEOL;
391*4bff34e3Sthurlow 				continue;
392*4bff34e3Sthurlow 			}
393*4bff34e3Sthurlow 			if (home_nsmbrc &&
394*4bff34e3Sthurlow 			    (strcmp(buf, "nbns") == 0 ||
395*4bff34e3Sthurlow 			    strcmp(buf, "nbns_enable") == 0 ||
396*4bff34e3Sthurlow 			    strcmp(buf, "nbns_broadcast") == 0)) {
397*4bff34e3Sthurlow 				fprintf(stderr, dgettext(TEXT_DOMAIN,
398*4bff34e3Sthurlow 				    "option %s may not be set "
399*4bff34e3Sthurlow 				    "in user .nsmbrc file\n"), buf);
400*4bff34e3Sthurlow 				next = buf;
401*4bff34e3Sthurlow 				state = stNewLine;
402*4bff34e3Sthurlow 				continue;
403*4bff34e3Sthurlow 			}
404*4bff34e3Sthurlow 			if (insecure_nsmbrc && (strcmp(buf, "password") == 0)) {
405*4bff34e3Sthurlow 				fprintf(stderr, dgettext(TEXT_DOMAIN,
406*4bff34e3Sthurlow 				    "Warning: .nsmbrc file not secure, "
407*4bff34e3Sthurlow 				    "ignoring passwords\n"));
408*4bff34e3Sthurlow 				next = buf;
409*4bff34e3Sthurlow 				state = stNewLine;
410*4bff34e3Sthurlow 				continue;
411*4bff34e3Sthurlow 			}
412*4bff34e3Sthurlow 			rkp = rc_sect_addkey(rsp, buf, NULL);
413*4bff34e3Sthurlow 			next = buf;
414*4bff34e3Sthurlow 			state = stGetValue;
415*4bff34e3Sthurlow 			continue;
416*4bff34e3Sthurlow 		}
417*4bff34e3Sthurlow 		/* only stGetValue left */
418*4bff34e3Sthurlow 		if (state != stGetValue) {
419*4bff34e3Sthurlow 			fprintf(stderr, dgettext(TEXT_DOMAIN,
420*4bff34e3Sthurlow 			    "Well, I can't parse file '%s'\n"), rcp->rf_name);
421*4bff34e3Sthurlow 			state = stSkipToEOL;
422*4bff34e3Sthurlow 		}
423*4bff34e3Sthurlow 		if (c != '\n') {
424*4bff34e3Sthurlow 			*next++ = c;
425*4bff34e3Sthurlow 			continue;
426*4bff34e3Sthurlow 		}
427*4bff34e3Sthurlow 		*next = 0;
428*4bff34e3Sthurlow 		set_value(rcp, rsp, rkp, buf);
429*4bff34e3Sthurlow 		state = stNewLine;
430*4bff34e3Sthurlow 		rkp = NULL;
431*4bff34e3Sthurlow 	} 	/* while */
432*4bff34e3Sthurlow 	if (c == EOF && state == stGetValue) {
433*4bff34e3Sthurlow 		*next = 0;
434*4bff34e3Sthurlow 		set_value(rcp, rsp, rkp, buf);
435*4bff34e3Sthurlow 	}
436*4bff34e3Sthurlow }
437*4bff34e3Sthurlow 
438*4bff34e3Sthurlow int
439*4bff34e3Sthurlow rc_getstringptr(struct rcfile *rcp, const char *section, const char *key,
440*4bff34e3Sthurlow 	char **dest)
441*4bff34e3Sthurlow {
442*4bff34e3Sthurlow 	struct rcsection *rsp;
443*4bff34e3Sthurlow 	struct rckey *rkp;
444*4bff34e3Sthurlow 
445*4bff34e3Sthurlow 	*dest = NULL;
446*4bff34e3Sthurlow 	rsp = rc_findsect(rcp, section);
447*4bff34e3Sthurlow 	if (!rsp)
448*4bff34e3Sthurlow 		return (ENOENT);
449*4bff34e3Sthurlow 	rkp = rc_sect_findkey(rsp, key);
450*4bff34e3Sthurlow 	if (!rkp)
451*4bff34e3Sthurlow 		return (ENOENT);
452*4bff34e3Sthurlow 	*dest = rkp->rk_value;
453*4bff34e3Sthurlow 	return (0);
454*4bff34e3Sthurlow }
455*4bff34e3Sthurlow 
456*4bff34e3Sthurlow int
457*4bff34e3Sthurlow rc_getstring(struct rcfile *rcp, const char *section, const char *key,
458*4bff34e3Sthurlow 	size_t maxlen, char *dest)
459*4bff34e3Sthurlow {
460*4bff34e3Sthurlow 	char *value;
461*4bff34e3Sthurlow 	int error;
462*4bff34e3Sthurlow 
463*4bff34e3Sthurlow 	error = rc_getstringptr(rcp, section, key, &value);
464*4bff34e3Sthurlow 	if (error)
465*4bff34e3Sthurlow 		return (error);
466*4bff34e3Sthurlow 	if (strlen(value) >= maxlen) {
467*4bff34e3Sthurlow 		fprintf(stdout, dgettext(TEXT_DOMAIN,
468*4bff34e3Sthurlow 		    "line too long for key '%s' in section '%s', max = %d\n"),
469*4bff34e3Sthurlow 		    key, section, maxlen);
470*4bff34e3Sthurlow 		return (EINVAL);
471*4bff34e3Sthurlow 	}
472*4bff34e3Sthurlow 	strcpy(dest, value);
473*4bff34e3Sthurlow 	return (0);
474*4bff34e3Sthurlow }
475*4bff34e3Sthurlow 
476*4bff34e3Sthurlow int
477*4bff34e3Sthurlow rc_getint(struct rcfile *rcp, const char *section, const char *key, int *value)
478*4bff34e3Sthurlow {
479*4bff34e3Sthurlow 	struct rcsection *rsp;
480*4bff34e3Sthurlow 	struct rckey *rkp;
481*4bff34e3Sthurlow 
482*4bff34e3Sthurlow 	rsp = rc_findsect(rcp, section);
483*4bff34e3Sthurlow 	if (!rsp)
484*4bff34e3Sthurlow 		return (ENOENT);
485*4bff34e3Sthurlow 	rkp = rc_sect_findkey(rsp, key);
486*4bff34e3Sthurlow 	if (!rkp)
487*4bff34e3Sthurlow 		return (ENOENT);
488*4bff34e3Sthurlow 	errno = 0;
489*4bff34e3Sthurlow 	*value = strtol(rkp->rk_value, NULL, 0);
490*4bff34e3Sthurlow 	if (errno) {
491*4bff34e3Sthurlow 		fprintf(stdout, dgettext(TEXT_DOMAIN,
492*4bff34e3Sthurlow 		    "invalid int value '%s' for key '%s' in section '%s'\n"),
493*4bff34e3Sthurlow 		    rkp->rk_value, key, section);
494*4bff34e3Sthurlow 		return (errno);
495*4bff34e3Sthurlow 	}
496*4bff34e3Sthurlow 	return (0);
497*4bff34e3Sthurlow }
498*4bff34e3Sthurlow 
499*4bff34e3Sthurlow /*
500*4bff34e3Sthurlow  * 1,yes,true
501*4bff34e3Sthurlow  * 0,no,false
502*4bff34e3Sthurlow  */
503*4bff34e3Sthurlow int
504*4bff34e3Sthurlow rc_getbool(struct rcfile *rcp, const char *section, const char *key, int *value)
505*4bff34e3Sthurlow {
506*4bff34e3Sthurlow 	struct rcsection *rsp;
507*4bff34e3Sthurlow 	struct rckey *rkp;
508*4bff34e3Sthurlow 	char *p;
509*4bff34e3Sthurlow 
510*4bff34e3Sthurlow 	rsp = rc_findsect(rcp, section);
511*4bff34e3Sthurlow 	if (!rsp)
512*4bff34e3Sthurlow 		return (ENOENT);
513*4bff34e3Sthurlow 	rkp = rc_sect_findkey(rsp, key);
514*4bff34e3Sthurlow 	if (!rkp)
515*4bff34e3Sthurlow 		return (ENOENT);
516*4bff34e3Sthurlow 	p = rkp->rk_value;
517*4bff34e3Sthurlow 	while (*p && isspace(*p)) p++;
518*4bff34e3Sthurlow 	if (*p == '0' ||
519*4bff34e3Sthurlow 	    strcasecmp(p, "no") == 0 ||
520*4bff34e3Sthurlow 	    strcasecmp(p, "false") == 0) {
521*4bff34e3Sthurlow 		*value = 0;
522*4bff34e3Sthurlow 		return (0);
523*4bff34e3Sthurlow 	}
524*4bff34e3Sthurlow 	if (*p == '1' ||
525*4bff34e3Sthurlow 	    strcasecmp(p, "yes") == 0 ||
526*4bff34e3Sthurlow 	    strcasecmp(p, "true") == 0) {
527*4bff34e3Sthurlow 		*value = 1;
528*4bff34e3Sthurlow 		return (0);
529*4bff34e3Sthurlow 	}
530*4bff34e3Sthurlow 	fprintf(stderr, dgettext(TEXT_DOMAIN,
531*4bff34e3Sthurlow 	    "invalid boolean value '%s' for key '%s' in section '%s' \n"),
532*4bff34e3Sthurlow 	    p, key, section);
533*4bff34e3Sthurlow 	return (EINVAL);
534*4bff34e3Sthurlow }
535*4bff34e3Sthurlow 
536*4bff34e3Sthurlow /*
537*4bff34e3Sthurlow  * Unified command line/rc file parser
538*4bff34e3Sthurlow  */
539*4bff34e3Sthurlow int
540*4bff34e3Sthurlow opt_args_parse(struct rcfile *rcp, struct opt_args *ap, const char *sect,
541*4bff34e3Sthurlow 	opt_callback_t *callback)
542*4bff34e3Sthurlow {
543*4bff34e3Sthurlow 	int len, error;
544*4bff34e3Sthurlow 
545*4bff34e3Sthurlow 	for (; ap->opt; ap++) {
546*4bff34e3Sthurlow 		switch (ap->type) {
547*4bff34e3Sthurlow 		case OPTARG_STR:
548*4bff34e3Sthurlow 			if (rc_getstringptr(rcp, sect, ap->name, &ap->str) != 0)
549*4bff34e3Sthurlow 				break;
550*4bff34e3Sthurlow 			len = strlen(ap->str);
551*4bff34e3Sthurlow 			if (len > ap->ival) {
552*4bff34e3Sthurlow 				fprintf(stdout, dgettext(TEXT_DOMAIN,
553*4bff34e3Sthurlow 			"rc: argument for option '%c' (%s) too long\n"),
554*4bff34e3Sthurlow 				    ap->opt, ap->name);
555*4bff34e3Sthurlow 				return (EINVAL);
556*4bff34e3Sthurlow 			}
557*4bff34e3Sthurlow 			callback(ap);
558*4bff34e3Sthurlow 			break;
559*4bff34e3Sthurlow 		case OPTARG_BOOL:
560*4bff34e3Sthurlow 			error = rc_getbool(rcp, sect, ap->name, &ap->ival);
561*4bff34e3Sthurlow 			if (error == ENOENT)
562*4bff34e3Sthurlow 				break;
563*4bff34e3Sthurlow 			if (error)
564*4bff34e3Sthurlow 				return (EINVAL);
565*4bff34e3Sthurlow 			callback(ap);
566*4bff34e3Sthurlow 			break;
567*4bff34e3Sthurlow 		case OPTARG_INT:
568*4bff34e3Sthurlow 			if (rc_getint(rcp, sect, ap->name, &ap->ival) != 0)
569*4bff34e3Sthurlow 				break;
570*4bff34e3Sthurlow 			if (((ap->flag & OPTFL_HAVEMIN) &&
571*4bff34e3Sthurlow 			    ap->ival < ap->min) ||
572*4bff34e3Sthurlow 			    ((ap->flag & OPTFL_HAVEMAX) &&
573*4bff34e3Sthurlow 			    ap->ival > ap->max)) {
574*4bff34e3Sthurlow 				fprintf(stdout, dgettext(TEXT_DOMAIN,
575*4bff34e3Sthurlow 				    "rc: argument for option '%c' (%s) "
576*4bff34e3Sthurlow 				    "should be in [%d-%d] range\n"),
577*4bff34e3Sthurlow 				    ap->opt, ap->name, ap->min, ap->max);
578*4bff34e3Sthurlow 				return (EINVAL);
579*4bff34e3Sthurlow 			}
580*4bff34e3Sthurlow 			callback(ap);
581*4bff34e3Sthurlow 			break;
582*4bff34e3Sthurlow 		default:
583*4bff34e3Sthurlow 			break;
584*4bff34e3Sthurlow 		}
585*4bff34e3Sthurlow 	}
586*4bff34e3Sthurlow 	return (0);
587*4bff34e3Sthurlow }
588*4bff34e3Sthurlow 
589*4bff34e3Sthurlow int
590*4bff34e3Sthurlow opt_args_parseopt(struct opt_args *ap, int opt, char *arg,
591*4bff34e3Sthurlow 	opt_callback_t *callback)
592*4bff34e3Sthurlow {
593*4bff34e3Sthurlow 	int len;
594*4bff34e3Sthurlow 
595*4bff34e3Sthurlow 	for (; ap->opt; ap++) {
596*4bff34e3Sthurlow 		if (ap->opt != opt)
597*4bff34e3Sthurlow 			continue;
598*4bff34e3Sthurlow 		switch (ap->type) {
599*4bff34e3Sthurlow 		case OPTARG_STR:
600*4bff34e3Sthurlow 			ap->str = arg;
601*4bff34e3Sthurlow 			if (arg) {
602*4bff34e3Sthurlow 				len = strlen(ap->str);
603*4bff34e3Sthurlow 				if (len > ap->ival) {
604*4bff34e3Sthurlow 					fprintf(stdout, dgettext(TEXT_DOMAIN,
605*4bff34e3Sthurlow 			"opt: Argument for option '%c' (%s) too long\n"),
606*4bff34e3Sthurlow 					    ap->opt, ap->name);
607*4bff34e3Sthurlow 					return (EINVAL);
608*4bff34e3Sthurlow 				}
609*4bff34e3Sthurlow 				callback(ap);
610*4bff34e3Sthurlow 			}
611*4bff34e3Sthurlow 			break;
612*4bff34e3Sthurlow 		case OPTARG_BOOL:
613*4bff34e3Sthurlow 			ap->ival = 0;
614*4bff34e3Sthurlow 			callback(ap);
615*4bff34e3Sthurlow 			break;
616*4bff34e3Sthurlow 		case OPTARG_INT:
617*4bff34e3Sthurlow 			errno = 0;
618*4bff34e3Sthurlow 			ap->ival = strtol(arg, NULL, 0);
619*4bff34e3Sthurlow 			if (errno) {
620*4bff34e3Sthurlow 				fprintf(stdout, dgettext(TEXT_DOMAIN,
621*4bff34e3Sthurlow 				    "opt: Invalid integer value for "
622*4bff34e3Sthurlow 				    "option '%c' (%s).\n"),
623*4bff34e3Sthurlow 				    ap->opt, ap->name);
624*4bff34e3Sthurlow 				return (EINVAL);
625*4bff34e3Sthurlow 			}
626*4bff34e3Sthurlow 			if (((ap->flag & OPTFL_HAVEMIN) &&
627*4bff34e3Sthurlow 			    (ap->ival < ap->min)) ||
628*4bff34e3Sthurlow 			    ((ap->flag & OPTFL_HAVEMAX) &&
629*4bff34e3Sthurlow 			    (ap->ival > ap->max))) {
630*4bff34e3Sthurlow 				fprintf(stdout, dgettext(TEXT_DOMAIN,
631*4bff34e3Sthurlow 				    "opt: Argument for option '%c' (%s) "
632*4bff34e3Sthurlow 				    "should be in [%d-%d] range\n"),
633*4bff34e3Sthurlow 				    ap->opt, ap->name, ap->min, ap->max);
634*4bff34e3Sthurlow 				return (EINVAL);
635*4bff34e3Sthurlow 			}
636*4bff34e3Sthurlow 			callback(ap);
637*4bff34e3Sthurlow 			break;
638*4bff34e3Sthurlow 		default:
639*4bff34e3Sthurlow 			break;
640*4bff34e3Sthurlow 		}
641*4bff34e3Sthurlow 		break;
642*4bff34e3Sthurlow 	}
643*4bff34e3Sthurlow 	return (0);
644*4bff34e3Sthurlow }
645