xref: /onnv-gate/usr/src/lib/libsmbfs/smb/rcfile.c (revision 8271:792589b3384f)
16007Sthurlow /*
26007Sthurlow  * Copyright (c) 2000, Boris Popov
36007Sthurlow  * All rights reserved.
46007Sthurlow  *
56007Sthurlow  * Redistribution and use in source and binary forms, with or without
66007Sthurlow  * modification, are permitted provided that the following conditions
76007Sthurlow  * are met:
86007Sthurlow  * 1. Redistributions of source code must retain the above copyright
96007Sthurlow  *    notice, this list of conditions and the following disclaimer.
106007Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
116007Sthurlow  *    notice, this list of conditions and the following disclaimer in the
126007Sthurlow  *    documentation and/or other materials provided with the distribution.
136007Sthurlow  * 3. All advertising materials mentioning features or use of this software
146007Sthurlow  *    must display the following acknowledgement:
156007Sthurlow  *    This product includes software developed by Boris Popov.
166007Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
176007Sthurlow  *    may be used to endorse or promote products derived from this software
186007Sthurlow  *    without specific prior written permission.
196007Sthurlow  *
206007Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
216007Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
226007Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
236007Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
246007Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
256007Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
266007Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
276007Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
286007Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
296007Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
306007Sthurlow  * SUCH DAMAGE.
316007Sthurlow  *
326007Sthurlow  * $Id: rcfile.c,v 1.1.1.2 2001/07/06 22:38:43 conrad Exp $
336007Sthurlow  */
346007Sthurlow 
356007Sthurlow #include <fcntl.h>
366007Sthurlow #include <sys/types.h>
376007Sthurlow #include <sys/queue.h>
386007Sthurlow #include <sys/stat.h>
396007Sthurlow #include <ctype.h>
406007Sthurlow #include <errno.h>
416007Sthurlow #include <stdio.h>
426007Sthurlow #include <string.h>
436007Sthurlow #include <strings.h>
446007Sthurlow #include <stdlib.h>
456007Sthurlow #include <libintl.h>
466007Sthurlow #include <pwd.h>
476007Sthurlow #include <unistd.h>
486007Sthurlow #include <sys/debug.h>
496007Sthurlow 
506007Sthurlow #include <cflib.h>
516007Sthurlow #include "rcfile_priv.h"
52*8271SGordon.Ross@Sun.COM extern int smb_debug;
536007Sthurlow 
546007Sthurlow SLIST_HEAD(rcfile_head, rcfile);
556007Sthurlow static struct rcfile_head pf_head = {NULL};
566007Sthurlow 
576007Sthurlow static struct rcfile *rc_cachelookup(const char *filename);
586007Sthurlow struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname);
596007Sthurlow static struct rcsection *rc_addsect(struct rcfile *rcp, const char *sectname);
606007Sthurlow static int rc_freesect(struct rcfile *rcp, struct rcsection *rsp);
616007Sthurlow struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname);
626007Sthurlow static struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name,
636007Sthurlow     const char *value);
646007Sthurlow static void rc_key_free(struct rckey *p);
656007Sthurlow static void rc_parse(struct rcfile *rcp);
666007Sthurlow 
676007Sthurlow int insecure_nsmbrc;
686007Sthurlow 
696007Sthurlow /*
706007Sthurlow  * open rcfile and load its content, if already open - return previous handle
716007Sthurlow  */
726007Sthurlow int
736007Sthurlow rc_open(const char *filename, const char *mode, struct rcfile **rcfile)
746007Sthurlow {
756007Sthurlow 	struct rcfile *rcp;
766007Sthurlow 	FILE *f;
776007Sthurlow 	struct stat statbuf;
786007Sthurlow 
796007Sthurlow 	rcp = rc_cachelookup(filename);
806007Sthurlow 	if (rcp) {
816007Sthurlow 		*rcfile = rcp;
826007Sthurlow 		return (0);
836007Sthurlow 	}
846007Sthurlow 	f = fopen(filename, mode);
856007Sthurlow 	if (f == NULL)
866007Sthurlow 		return (errno);
876007Sthurlow 	insecure_nsmbrc = 0;
886007Sthurlow 	if (fstat(fileno(f), &statbuf) >= 0 &&
896007Sthurlow 	    (statbuf.st_mode & 077) != 0)
906007Sthurlow 		insecure_nsmbrc = 1;
916007Sthurlow 	rcp = malloc(sizeof (struct rcfile));
926007Sthurlow 	if (rcp == NULL) {
936007Sthurlow 		fclose(f);
946007Sthurlow 		return (ENOMEM);
956007Sthurlow 	}
966007Sthurlow 	bzero(rcp, sizeof (struct rcfile));
976007Sthurlow 	rcp->rf_name = strdup(filename);
986007Sthurlow 	rcp->rf_f = f;
996007Sthurlow 	SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
1006007Sthurlow 	rc_parse(rcp);
1016007Sthurlow 	*rcfile = rcp;
1026007Sthurlow 	return (0);
1036007Sthurlow }
1046007Sthurlow 
1056007Sthurlow int
1066007Sthurlow rc_merge(const char *filename, struct rcfile **rcfile)
1076007Sthurlow {
1086007Sthurlow 	struct rcfile *rcp = *rcfile;
1096007Sthurlow 	FILE *f, *t;
1106007Sthurlow 
1116007Sthurlow 	insecure_nsmbrc = 0;
1126007Sthurlow 	if (rcp == NULL) {
1136007Sthurlow 		return (rc_open(filename, "r", rcfile));
1146007Sthurlow 	}
1156007Sthurlow 	f = fopen(filename, "r");
1166007Sthurlow 	if (f == NULL)
1176007Sthurlow 		return (errno);
1186007Sthurlow 	t = rcp->rf_f;
1196007Sthurlow 	rcp->rf_f = f;
1206007Sthurlow 	rc_parse(rcp);
1216007Sthurlow 	rcp->rf_f = t;
1226007Sthurlow 	fclose(f);
1236007Sthurlow 	return (0);
1246007Sthurlow }
1256007Sthurlow 
1266007Sthurlow int
1276007Sthurlow rc_merge_pipe(const char *command, struct rcfile **rcfile)
1286007Sthurlow {
1296007Sthurlow 	struct rcfile *rcp = *rcfile;
1306007Sthurlow 	FILE *f, *t;
1316007Sthurlow 
1326007Sthurlow 	insecure_nsmbrc = 0;
1336007Sthurlow 	f = popen(command, "r");
1346007Sthurlow 	if (f == NULL)
1356007Sthurlow 		return (errno);
1366007Sthurlow 	if (rcp == NULL) {
1376007Sthurlow 		rcp = malloc(sizeof (struct rcfile));
1386007Sthurlow 		if (rcp == NULL) {
1396007Sthurlow 			fclose(f);
1406007Sthurlow 			return (ENOMEM);
1416007Sthurlow 		}
1426007Sthurlow 		*rcfile = rcp;
1436007Sthurlow 		bzero(rcp, sizeof (struct rcfile));
1446007Sthurlow 		rcp->rf_name = strdup(command);
1456007Sthurlow 		rcp->rf_f = f;
1466007Sthurlow 		SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
1476007Sthurlow 		rc_parse(rcp);
1486007Sthurlow 	} else {
1496007Sthurlow 		t = rcp->rf_f;
1506007Sthurlow 		rcp->rf_f = f;
1516007Sthurlow 		rc_parse(rcp);
1526007Sthurlow 		rcp->rf_f = t;
1536007Sthurlow 	}
1546007Sthurlow 	fclose(f);
1556007Sthurlow 	return (0);
1566007Sthurlow }
1576007Sthurlow 
1586007Sthurlow int
1596007Sthurlow rc_close(struct rcfile *rcp)
1606007Sthurlow {
1616007Sthurlow 	struct rcsection *p, *n;
1626007Sthurlow 
1636007Sthurlow 	fclose(rcp->rf_f);
1646007Sthurlow 	for (p = SLIST_FIRST(&rcp->rf_sect); p; ) {
1656007Sthurlow 		n = p;
1666007Sthurlow 		p = SLIST_NEXT(p, rs_next);
1676007Sthurlow 		rc_freesect(rcp, n);
1686007Sthurlow 	}
1696007Sthurlow 	free(rcp->rf_name);
1706007Sthurlow 	SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next);
1716007Sthurlow 	free(rcp);
1726007Sthurlow 	return (0);
1736007Sthurlow }
1746007Sthurlow 
1756007Sthurlow static struct rcfile *
1766007Sthurlow rc_cachelookup(const char *filename)
1776007Sthurlow {
1786007Sthurlow 	struct rcfile *p;
1796007Sthurlow 
1806007Sthurlow 	SLIST_FOREACH(p, &pf_head, rf_next)
1816007Sthurlow 		if (strcmp(filename, p->rf_name) == 0)
1826007Sthurlow 			return (p);
1836007Sthurlow 	return (0);
1846007Sthurlow }
1856007Sthurlow 
1866007Sthurlow /* static */ struct rcsection *
1876007Sthurlow rc_findsect(struct rcfile *rcp, const char *sectname)
1886007Sthurlow {
1896007Sthurlow 	struct rcsection *p;
1906007Sthurlow 
1916007Sthurlow 	SLIST_FOREACH(p, &rcp->rf_sect, rs_next)
1926007Sthurlow 		if (strcasecmp(p->rs_name, sectname) == 0)
1936007Sthurlow 			return (p);
1946007Sthurlow 	return (NULL);
1956007Sthurlow }
1966007Sthurlow 
1976007Sthurlow static struct rcsection *
1986007Sthurlow rc_addsect(struct rcfile *rcp, const char *sectname)
1996007Sthurlow {
2006007Sthurlow 	struct rcsection *p;
2016007Sthurlow 
2026007Sthurlow 	p = rc_findsect(rcp, sectname);
2036007Sthurlow 	if (p)
2046007Sthurlow 		return (p);
2056007Sthurlow 	p = malloc(sizeof (*p));
2066007Sthurlow 	if (!p)
2076007Sthurlow 		return (NULL);
2086007Sthurlow 	p->rs_name = strdup(sectname);
2096007Sthurlow 	SLIST_INIT(&p->rs_keys);
2106007Sthurlow 	SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next);
2116007Sthurlow 	return (p);
2126007Sthurlow }
2136007Sthurlow 
2146007Sthurlow static int
2156007Sthurlow rc_freesect(struct rcfile *rcp, struct rcsection *rsp)
2166007Sthurlow {
2176007Sthurlow 	struct rckey *p, *n;
2186007Sthurlow 
2196007Sthurlow 	SLIST_REMOVE(&rcp->rf_sect, rsp, rcsection, rs_next);
2206007Sthurlow 	for (p = SLIST_FIRST(&rsp->rs_keys); p; ) {
2216007Sthurlow 		n = p;
2226007Sthurlow 		p = SLIST_NEXT(p, rk_next);
2236007Sthurlow 		rc_key_free(n);
2246007Sthurlow 	}
2256007Sthurlow 	free(rsp->rs_name);
2266007Sthurlow 	free(rsp);
2276007Sthurlow 	return (0);
2286007Sthurlow }
2296007Sthurlow 
2306007Sthurlow /* static */ struct rckey *
2316007Sthurlow rc_sect_findkey(struct rcsection *rsp, const char *keyname)
2326007Sthurlow {
2336007Sthurlow 	struct rckey *p;
2346007Sthurlow 
2356007Sthurlow 	SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
2366007Sthurlow 		if (strcmp(p->rk_name, keyname) == 0)
2376007Sthurlow 			return (p);
2386007Sthurlow 	return (NULL);
2396007Sthurlow }
2406007Sthurlow 
2416007Sthurlow static struct rckey *
2426007Sthurlow rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value)
2436007Sthurlow {
2446007Sthurlow 	struct rckey *p;
2456007Sthurlow 
2466007Sthurlow 	p = rc_sect_findkey(rsp, name);
2476007Sthurlow 	if (!p) {
2486007Sthurlow 		p = malloc(sizeof (*p));
2496007Sthurlow 		if (!p)
2506007Sthurlow 			return (NULL);
2516007Sthurlow 		SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next);
2526007Sthurlow 		p->rk_name = strdup(name);
2536007Sthurlow 		p->rk_value = value ? strdup(value) : strdup("");
2546007Sthurlow 	}
2556007Sthurlow 	return (p);
2566007Sthurlow }
2576007Sthurlow 
2586007Sthurlow #if 0
2596007Sthurlow void
2606007Sthurlow rc_sect_delkey(struct rcsection *rsp, struct rckey *p)
2616007Sthurlow {
2626007Sthurlow 
2636007Sthurlow 	SLIST_REMOVE(&rsp->rs_keys, p, rckey, rk_next);
2646007Sthurlow 	rc_key_free(p);
2656007Sthurlow }
2666007Sthurlow #endif
2676007Sthurlow 
2686007Sthurlow static void
2696007Sthurlow rc_key_free(struct rckey *p)
2706007Sthurlow {
2716007Sthurlow 	free(p->rk_value);
2726007Sthurlow 	free(p->rk_name);
2736007Sthurlow 	free(p);
2746007Sthurlow }
2756007Sthurlow 
2766007Sthurlow enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
2776007Sthurlow 
2786007Sthurlow int home_nsmbrc = 0;
2796007Sthurlow 
2806007Sthurlow static char *minauth[] = {
2816007Sthurlow 	"kerberos",
2826007Sthurlow 	"ntlmv2",
2836007Sthurlow 	"ntlm",
2846007Sthurlow 	"lm",
2856007Sthurlow 	"none",
2866007Sthurlow 	NULL
2876007Sthurlow };
2886007Sthurlow 
2896007Sthurlow static int
2906007Sthurlow eval_minauth(char *auth)
2916007Sthurlow {
2926007Sthurlow 	int i;
2936007Sthurlow 
2946007Sthurlow 	for (i = 0; minauth[i]; i++)
2956007Sthurlow 		if (strcmp(auth, minauth[i]) == 0)
2966007Sthurlow 			break;
2976007Sthurlow 	return (i);
2986007Sthurlow }
2996007Sthurlow 
3006007Sthurlow /*
3016007Sthurlow  * Ensure that "minauth" is set to the highest level (lowest array offset)
3026007Sthurlow  */
3036007Sthurlow static void
3046007Sthurlow set_value(struct rcfile *rcp, struct rcsection *rsp, struct rckey *rkp,
3056007Sthurlow     char *ptr)
3066007Sthurlow {
3076007Sthurlow 	int now, new;
3086007Sthurlow 
3096007Sthurlow 	if (strcmp(rkp->rk_name, "minauth") == 0) {
3106007Sthurlow 		now = eval_minauth(rkp->rk_value);
3116007Sthurlow 		new = eval_minauth(ptr);
3126007Sthurlow 		if (new >= now) {
3136007Sthurlow #ifdef DEBUG
314*8271SGordon.Ross@Sun.COM 			if (smb_debug)
315*8271SGordon.Ross@Sun.COM 				printf(
316*8271SGordon.Ross@Sun.COM 				    "set_value: rejecting %s=%s from %s\n",
317*8271SGordon.Ross@Sun.COM 				    rkp->rk_name, ptr, home_nsmbrc ?
318*8271SGordon.Ross@Sun.COM 				    "user file" : "SMF");
3196007Sthurlow #endif
3206007Sthurlow 			return;
3216007Sthurlow 		}
3226007Sthurlow 	}
3236007Sthurlow #ifdef DEBUG
324*8271SGordon.Ross@Sun.COM 	if (smb_debug)
325*8271SGordon.Ross@Sun.COM 		printf("set_value: applying %s=%s from %s\n",
326*8271SGordon.Ross@Sun.COM 		    rkp->rk_name, ptr, home_nsmbrc ? "user file" : "SMF");
3276007Sthurlow #endif
3286007Sthurlow 	rkp->rk_value = strdup(ptr);
3296007Sthurlow }
3306007Sthurlow 
3316007Sthurlow static void
3326007Sthurlow rc_parse(struct rcfile *rcp)
3336007Sthurlow {
3346007Sthurlow 	FILE *f = rcp->rf_f;
3356007Sthurlow 	int state = stNewLine, c;
3366007Sthurlow 	struct rcsection *rsp = NULL;
3376007Sthurlow 	struct rckey *rkp = NULL;
3386007Sthurlow 	char buf[2048];
3396007Sthurlow 	char *next = buf, *last = &buf[sizeof (buf)-1];
3406007Sthurlow 
3416007Sthurlow 	while ((c = getc(f)) != EOF) {
3426007Sthurlow 		if (c == '\r')
3436007Sthurlow 			continue;
3446007Sthurlow 		if (state == stNewLine) {
3456007Sthurlow 			next = buf;
3466007Sthurlow 			if (isspace(c))
3476007Sthurlow 				continue;	/* skip leading junk */
3486007Sthurlow 			if (c == '[') {
3496007Sthurlow 				state = stHeader;
3506007Sthurlow 				rsp = NULL;
3516007Sthurlow 				continue;
3526007Sthurlow 			}
3536007Sthurlow 			if (c == '#' || c == ';') {
3546007Sthurlow 				state = stSkipToEOL;
3556007Sthurlow 			} else {		/* something meaningfull */
3566007Sthurlow 				state = stGetKey;
3576007Sthurlow 			}
3586007Sthurlow 		}
3596007Sthurlow 		/* ignore long lines */
3606007Sthurlow 		if (state == stSkipToEOL || next == last) {
3616007Sthurlow 			if (c == '\n') {
3626007Sthurlow 				state = stNewLine;
3636007Sthurlow 				next = buf;
3646007Sthurlow 			}
3656007Sthurlow 			continue;
3666007Sthurlow 		}
3676007Sthurlow 		if (state == stHeader) {
3686007Sthurlow 			if (c == ']') {
3696007Sthurlow 				*next = 0;
3706007Sthurlow 				next = buf;
3716007Sthurlow 				rsp = rc_addsect(rcp, buf);
3726007Sthurlow 				state = stSkipToEOL;
3736007Sthurlow 			} else
3746007Sthurlow 				*next++ = c;
3756007Sthurlow 			continue;
3766007Sthurlow 		}
3776007Sthurlow 		if (state == stGetKey) {
3786007Sthurlow 			/* side effect: 'key name=' */
3796007Sthurlow 			if (c == ' ' || c == '\t')
3806007Sthurlow 				continue;	/* become 'keyname=' */
3816007Sthurlow 			if (c == '\n') {	/* silently ignore ... */
3826007Sthurlow 				state = stNewLine;
3836007Sthurlow 				continue;
3846007Sthurlow 			}
3856007Sthurlow 			if (c != '=') {
3866007Sthurlow 				*next++ = c;
3876007Sthurlow 				continue;
3886007Sthurlow 			}
3896007Sthurlow 			*next = 0;
3906007Sthurlow 			if (rsp == NULL) {
3916007Sthurlow 				fprintf(stderr, dgettext(TEXT_DOMAIN,
3926007Sthurlow 				    "Key '%s' defined before section\n"), buf);
3936007Sthurlow 				state = stSkipToEOL;
3946007Sthurlow 				continue;
3956007Sthurlow 			}
3966007Sthurlow 			if (home_nsmbrc &&
3976007Sthurlow 			    (strcmp(buf, "nbns") == 0 ||
3986007Sthurlow 			    strcmp(buf, "nbns_enable") == 0 ||
399*8271SGordon.Ross@Sun.COM 			    strcmp(buf, "nbns_broadcast") == 0 ||
400*8271SGordon.Ross@Sun.COM 			    strcmp(buf, "signing") == 0)) {
4016007Sthurlow 				fprintf(stderr, dgettext(TEXT_DOMAIN,
4026007Sthurlow 				    "option %s may not be set "
4036007Sthurlow 				    "in user .nsmbrc file\n"), buf);
4046007Sthurlow 				next = buf;
4056007Sthurlow 				state = stNewLine;
4066007Sthurlow 				continue;
4076007Sthurlow 			}
4086007Sthurlow 			if (insecure_nsmbrc && (strcmp(buf, "password") == 0)) {
4096007Sthurlow 				fprintf(stderr, dgettext(TEXT_DOMAIN,
4106007Sthurlow 				    "Warning: .nsmbrc file not secure, "
4116007Sthurlow 				    "ignoring passwords\n"));
4126007Sthurlow 				next = buf;
4136007Sthurlow 				state = stNewLine;
4146007Sthurlow 				continue;
4156007Sthurlow 			}
4166007Sthurlow 			rkp = rc_sect_addkey(rsp, buf, NULL);
4176007Sthurlow 			next = buf;
4186007Sthurlow 			state = stGetValue;
4196007Sthurlow 			continue;
4206007Sthurlow 		}
4216007Sthurlow 		/* only stGetValue left */
4226007Sthurlow 		if (state != stGetValue) {
4236007Sthurlow 			fprintf(stderr, dgettext(TEXT_DOMAIN,
4246007Sthurlow 			    "Well, I can't parse file '%s'\n"), rcp->rf_name);
4256007Sthurlow 			state = stSkipToEOL;
4266007Sthurlow 		}
4276007Sthurlow 		if (c != '\n') {
4286007Sthurlow 			*next++ = c;
4296007Sthurlow 			continue;
4306007Sthurlow 		}
4316007Sthurlow 		*next = 0;
4326007Sthurlow 		set_value(rcp, rsp, rkp, buf);
4336007Sthurlow 		state = stNewLine;
4346007Sthurlow 		rkp = NULL;
4356007Sthurlow 	} 	/* while */
4366007Sthurlow 	if (c == EOF && state == stGetValue) {
4376007Sthurlow 		*next = 0;
4386007Sthurlow 		set_value(rcp, rsp, rkp, buf);
4396007Sthurlow 	}
4406007Sthurlow }
4416007Sthurlow 
4426007Sthurlow int
4436007Sthurlow rc_getstringptr(struct rcfile *rcp, const char *section, const char *key,
4446007Sthurlow 	char **dest)
4456007Sthurlow {
4466007Sthurlow 	struct rcsection *rsp;
4476007Sthurlow 	struct rckey *rkp;
4486007Sthurlow 
4496007Sthurlow 	*dest = NULL;
4506007Sthurlow 	rsp = rc_findsect(rcp, section);
4516007Sthurlow 	if (!rsp)
4526007Sthurlow 		return (ENOENT);
4536007Sthurlow 	rkp = rc_sect_findkey(rsp, key);
4546007Sthurlow 	if (!rkp)
4556007Sthurlow 		return (ENOENT);
4566007Sthurlow 	*dest = rkp->rk_value;
4576007Sthurlow 	return (0);
4586007Sthurlow }
4596007Sthurlow 
4606007Sthurlow int
4616007Sthurlow rc_getstring(struct rcfile *rcp, const char *section, const char *key,
4626007Sthurlow 	size_t maxlen, char *dest)
4636007Sthurlow {
4646007Sthurlow 	char *value;
4656007Sthurlow 	int error;
4666007Sthurlow 
4676007Sthurlow 	error = rc_getstringptr(rcp, section, key, &value);
4686007Sthurlow 	if (error)
4696007Sthurlow 		return (error);
4706007Sthurlow 	if (strlen(value) >= maxlen) {
4716007Sthurlow 		fprintf(stdout, dgettext(TEXT_DOMAIN,
4726007Sthurlow 		    "line too long for key '%s' in section '%s', max = %d\n"),
4736007Sthurlow 		    key, section, maxlen);
4746007Sthurlow 		return (EINVAL);
4756007Sthurlow 	}
4766007Sthurlow 	strcpy(dest, value);
4776007Sthurlow 	return (0);
4786007Sthurlow }
4796007Sthurlow 
4806007Sthurlow int
4816007Sthurlow rc_getint(struct rcfile *rcp, const char *section, const char *key, int *value)
4826007Sthurlow {
4836007Sthurlow 	struct rcsection *rsp;
4846007Sthurlow 	struct rckey *rkp;
4856007Sthurlow 
4866007Sthurlow 	rsp = rc_findsect(rcp, section);
4876007Sthurlow 	if (!rsp)
4886007Sthurlow 		return (ENOENT);
4896007Sthurlow 	rkp = rc_sect_findkey(rsp, key);
4906007Sthurlow 	if (!rkp)
4916007Sthurlow 		return (ENOENT);
4926007Sthurlow 	errno = 0;
4936007Sthurlow 	*value = strtol(rkp->rk_value, NULL, 0);
4946007Sthurlow 	if (errno) {
4956007Sthurlow 		fprintf(stdout, dgettext(TEXT_DOMAIN,
4966007Sthurlow 		    "invalid int value '%s' for key '%s' in section '%s'\n"),
4976007Sthurlow 		    rkp->rk_value, key, section);
4986007Sthurlow 		return (errno);
4996007Sthurlow 	}
5006007Sthurlow 	return (0);
5016007Sthurlow }
5026007Sthurlow 
5036007Sthurlow /*
5046007Sthurlow  * 1,yes,true
5056007Sthurlow  * 0,no,false
5066007Sthurlow  */
5076007Sthurlow int
5086007Sthurlow rc_getbool(struct rcfile *rcp, const char *section, const char *key, int *value)
5096007Sthurlow {
5106007Sthurlow 	struct rcsection *rsp;
5116007Sthurlow 	struct rckey *rkp;
5126007Sthurlow 	char *p;
5136007Sthurlow 
5146007Sthurlow 	rsp = rc_findsect(rcp, section);
5156007Sthurlow 	if (!rsp)
5166007Sthurlow 		return (ENOENT);
5176007Sthurlow 	rkp = rc_sect_findkey(rsp, key);
5186007Sthurlow 	if (!rkp)
5196007Sthurlow 		return (ENOENT);
5206007Sthurlow 	p = rkp->rk_value;
5216007Sthurlow 	while (*p && isspace(*p)) p++;
5226007Sthurlow 	if (*p == '0' ||
5236007Sthurlow 	    strcasecmp(p, "no") == 0 ||
5246007Sthurlow 	    strcasecmp(p, "false") == 0) {
5256007Sthurlow 		*value = 0;
5266007Sthurlow 		return (0);
5276007Sthurlow 	}
5286007Sthurlow 	if (*p == '1' ||
5296007Sthurlow 	    strcasecmp(p, "yes") == 0 ||
5306007Sthurlow 	    strcasecmp(p, "true") == 0) {
5316007Sthurlow 		*value = 1;
5326007Sthurlow 		return (0);
5336007Sthurlow 	}
5346007Sthurlow 	fprintf(stderr, dgettext(TEXT_DOMAIN,
5356007Sthurlow 	    "invalid boolean value '%s' for key '%s' in section '%s' \n"),
5366007Sthurlow 	    p, key, section);
5376007Sthurlow 	return (EINVAL);
5386007Sthurlow }
5396007Sthurlow 
5406007Sthurlow /*
5416007Sthurlow  * Unified command line/rc file parser
5426007Sthurlow  */
5436007Sthurlow int
5446007Sthurlow opt_args_parse(struct rcfile *rcp, struct opt_args *ap, const char *sect,
5456007Sthurlow 	opt_callback_t *callback)
5466007Sthurlow {
5476007Sthurlow 	int len, error;
5486007Sthurlow 
5496007Sthurlow 	for (; ap->opt; ap++) {
5506007Sthurlow 		switch (ap->type) {
5516007Sthurlow 		case OPTARG_STR:
5526007Sthurlow 			if (rc_getstringptr(rcp, sect, ap->name, &ap->str) != 0)
5536007Sthurlow 				break;
5546007Sthurlow 			len = strlen(ap->str);
5556007Sthurlow 			if (len > ap->ival) {
5566007Sthurlow 				fprintf(stdout, dgettext(TEXT_DOMAIN,
5576007Sthurlow 			"rc: argument for option '%c' (%s) too long\n"),
5586007Sthurlow 				    ap->opt, ap->name);
5596007Sthurlow 				return (EINVAL);
5606007Sthurlow 			}
5616007Sthurlow 			callback(ap);
5626007Sthurlow 			break;
5636007Sthurlow 		case OPTARG_BOOL:
5646007Sthurlow 			error = rc_getbool(rcp, sect, ap->name, &ap->ival);
5656007Sthurlow 			if (error == ENOENT)
5666007Sthurlow 				break;
5676007Sthurlow 			if (error)
5686007Sthurlow 				return (EINVAL);
5696007Sthurlow 			callback(ap);
5706007Sthurlow 			break;
5716007Sthurlow 		case OPTARG_INT:
5726007Sthurlow 			if (rc_getint(rcp, sect, ap->name, &ap->ival) != 0)
5736007Sthurlow 				break;
5746007Sthurlow 			if (((ap->flag & OPTFL_HAVEMIN) &&
5756007Sthurlow 			    ap->ival < ap->min) ||
5766007Sthurlow 			    ((ap->flag & OPTFL_HAVEMAX) &&
5776007Sthurlow 			    ap->ival > ap->max)) {
5786007Sthurlow 				fprintf(stdout, dgettext(TEXT_DOMAIN,
5796007Sthurlow 				    "rc: argument for option '%c' (%s) "
5806007Sthurlow 				    "should be in [%d-%d] range\n"),
5816007Sthurlow 				    ap->opt, ap->name, ap->min, ap->max);
5826007Sthurlow 				return (EINVAL);
5836007Sthurlow 			}
5846007Sthurlow 			callback(ap);
5856007Sthurlow 			break;
5866007Sthurlow 		default:
5876007Sthurlow 			break;
5886007Sthurlow 		}
5896007Sthurlow 	}
5906007Sthurlow 	return (0);
5916007Sthurlow }
5926007Sthurlow 
5936007Sthurlow int
5946007Sthurlow opt_args_parseopt(struct opt_args *ap, int opt, char *arg,
5956007Sthurlow 	opt_callback_t *callback)
5966007Sthurlow {
5976007Sthurlow 	int len;
5986007Sthurlow 
5996007Sthurlow 	for (; ap->opt; ap++) {
6006007Sthurlow 		if (ap->opt != opt)
6016007Sthurlow 			continue;
6026007Sthurlow 		switch (ap->type) {
6036007Sthurlow 		case OPTARG_STR:
6046007Sthurlow 			ap->str = arg;
6056007Sthurlow 			if (arg) {
6066007Sthurlow 				len = strlen(ap->str);
6076007Sthurlow 				if (len > ap->ival) {
6086007Sthurlow 					fprintf(stdout, dgettext(TEXT_DOMAIN,
6096007Sthurlow 			"opt: Argument for option '%c' (%s) too long\n"),
6106007Sthurlow 					    ap->opt, ap->name);
6116007Sthurlow 					return (EINVAL);
6126007Sthurlow 				}
6136007Sthurlow 				callback(ap);
6146007Sthurlow 			}
6156007Sthurlow 			break;
6166007Sthurlow 		case OPTARG_BOOL:
6176007Sthurlow 			ap->ival = 0;
6186007Sthurlow 			callback(ap);
6196007Sthurlow 			break;
6206007Sthurlow 		case OPTARG_INT:
6216007Sthurlow 			errno = 0;
6226007Sthurlow 			ap->ival = strtol(arg, NULL, 0);
6236007Sthurlow 			if (errno) {
6246007Sthurlow 				fprintf(stdout, dgettext(TEXT_DOMAIN,
6256007Sthurlow 				    "opt: Invalid integer value for "
6266007Sthurlow 				    "option '%c' (%s).\n"),
6276007Sthurlow 				    ap->opt, ap->name);
6286007Sthurlow 				return (EINVAL);
6296007Sthurlow 			}
6306007Sthurlow 			if (((ap->flag & OPTFL_HAVEMIN) &&
6316007Sthurlow 			    (ap->ival < ap->min)) ||
6326007Sthurlow 			    ((ap->flag & OPTFL_HAVEMAX) &&
6336007Sthurlow 			    (ap->ival > ap->max))) {
6346007Sthurlow 				fprintf(stdout, dgettext(TEXT_DOMAIN,
6356007Sthurlow 				    "opt: Argument for option '%c' (%s) "
6366007Sthurlow 				    "should be in [%d-%d] range\n"),
6376007Sthurlow 				    ap->opt, ap->name, ap->min, ap->max);
6386007Sthurlow 				return (EINVAL);
6396007Sthurlow 			}
6406007Sthurlow 			callback(ap);
6416007Sthurlow 			break;
6426007Sthurlow 		default:
6436007Sthurlow 			break;
6446007Sthurlow 		}
6456007Sthurlow 		break;
6466007Sthurlow 	}
6476007Sthurlow 	return (0);
6486007Sthurlow }
649