14bff34e3Sthurlow /* 24bff34e3Sthurlow * Copyright (c) 2000, Boris Popov 34bff34e3Sthurlow * All rights reserved. 44bff34e3Sthurlow * 54bff34e3Sthurlow * Redistribution and use in source and binary forms, with or without 64bff34e3Sthurlow * modification, are permitted provided that the following conditions 74bff34e3Sthurlow * are met: 84bff34e3Sthurlow * 1. Redistributions of source code must retain the above copyright 94bff34e3Sthurlow * notice, this list of conditions and the following disclaimer. 104bff34e3Sthurlow * 2. Redistributions in binary form must reproduce the above copyright 114bff34e3Sthurlow * notice, this list of conditions and the following disclaimer in the 124bff34e3Sthurlow * documentation and/or other materials provided with the distribution. 134bff34e3Sthurlow * 3. All advertising materials mentioning features or use of this software 144bff34e3Sthurlow * must display the following acknowledgement: 154bff34e3Sthurlow * This product includes software developed by Boris Popov. 164bff34e3Sthurlow * 4. Neither the name of the author nor the names of any co-contributors 174bff34e3Sthurlow * may be used to endorse or promote products derived from this software 184bff34e3Sthurlow * without specific prior written permission. 194bff34e3Sthurlow * 204bff34e3Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 214bff34e3Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224bff34e3Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234bff34e3Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 244bff34e3Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254bff34e3Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264bff34e3Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274bff34e3Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284bff34e3Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294bff34e3Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304bff34e3Sthurlow * SUCH DAMAGE. 314bff34e3Sthurlow * 324bff34e3Sthurlow * $Id: rcfile.c,v 1.1.1.2 2001/07/06 22:38:43 conrad Exp $ 334bff34e3Sthurlow */ 344bff34e3Sthurlow 354bff34e3Sthurlow #include <fcntl.h> 364bff34e3Sthurlow #include <sys/types.h> 374bff34e3Sthurlow #include <sys/queue.h> 384bff34e3Sthurlow #include <sys/stat.h> 394bff34e3Sthurlow #include <ctype.h> 404bff34e3Sthurlow #include <errno.h> 414bff34e3Sthurlow #include <stdio.h> 424bff34e3Sthurlow #include <string.h> 434bff34e3Sthurlow #include <strings.h> 444bff34e3Sthurlow #include <stdlib.h> 454bff34e3Sthurlow #include <libintl.h> 464bff34e3Sthurlow #include <pwd.h> 474bff34e3Sthurlow #include <unistd.h> 484bff34e3Sthurlow #include <sys/debug.h> 494bff34e3Sthurlow 504bff34e3Sthurlow #include <cflib.h> 514bff34e3Sthurlow #include "rcfile_priv.h" 52*9c9af259SGordon Ross extern int smb_debug; 534bff34e3Sthurlow 544bff34e3Sthurlow SLIST_HEAD(rcfile_head, rcfile); 554bff34e3Sthurlow static struct rcfile_head pf_head = {NULL}; 564bff34e3Sthurlow 574bff34e3Sthurlow static struct rcfile *rc_cachelookup(const char *filename); 584bff34e3Sthurlow struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname); 594bff34e3Sthurlow static struct rcsection *rc_addsect(struct rcfile *rcp, const char *sectname); 604bff34e3Sthurlow static int rc_freesect(struct rcfile *rcp, struct rcsection *rsp); 614bff34e3Sthurlow struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname); 624bff34e3Sthurlow static struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name, 634bff34e3Sthurlow const char *value); 644bff34e3Sthurlow static void rc_key_free(struct rckey *p); 654bff34e3Sthurlow static void rc_parse(struct rcfile *rcp); 664bff34e3Sthurlow 674bff34e3Sthurlow int insecure_nsmbrc; 684bff34e3Sthurlow 694bff34e3Sthurlow /* 704bff34e3Sthurlow * open rcfile and load its content, if already open - return previous handle 714bff34e3Sthurlow */ 724bff34e3Sthurlow int 734bff34e3Sthurlow rc_open(const char *filename, const char *mode, struct rcfile **rcfile) 744bff34e3Sthurlow { 754bff34e3Sthurlow struct rcfile *rcp; 764bff34e3Sthurlow FILE *f; 774bff34e3Sthurlow struct stat statbuf; 784bff34e3Sthurlow 794bff34e3Sthurlow rcp = rc_cachelookup(filename); 804bff34e3Sthurlow if (rcp) { 814bff34e3Sthurlow *rcfile = rcp; 824bff34e3Sthurlow return (0); 834bff34e3Sthurlow } 844bff34e3Sthurlow f = fopen(filename, mode); 854bff34e3Sthurlow if (f == NULL) 864bff34e3Sthurlow return (errno); 874bff34e3Sthurlow insecure_nsmbrc = 0; 884bff34e3Sthurlow if (fstat(fileno(f), &statbuf) >= 0 && 894bff34e3Sthurlow (statbuf.st_mode & 077) != 0) 904bff34e3Sthurlow insecure_nsmbrc = 1; 914bff34e3Sthurlow rcp = malloc(sizeof (struct rcfile)); 924bff34e3Sthurlow if (rcp == NULL) { 934bff34e3Sthurlow fclose(f); 944bff34e3Sthurlow return (ENOMEM); 954bff34e3Sthurlow } 964bff34e3Sthurlow bzero(rcp, sizeof (struct rcfile)); 974bff34e3Sthurlow rcp->rf_name = strdup(filename); 984bff34e3Sthurlow rcp->rf_f = f; 994bff34e3Sthurlow SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); 1004bff34e3Sthurlow rc_parse(rcp); 1014bff34e3Sthurlow *rcfile = rcp; 1024bff34e3Sthurlow return (0); 1034bff34e3Sthurlow } 1044bff34e3Sthurlow 1054bff34e3Sthurlow int 1064bff34e3Sthurlow rc_merge(const char *filename, struct rcfile **rcfile) 1074bff34e3Sthurlow { 1084bff34e3Sthurlow struct rcfile *rcp = *rcfile; 1094bff34e3Sthurlow FILE *f, *t; 1104bff34e3Sthurlow 1114bff34e3Sthurlow insecure_nsmbrc = 0; 1124bff34e3Sthurlow if (rcp == NULL) { 1134bff34e3Sthurlow return (rc_open(filename, "r", rcfile)); 1144bff34e3Sthurlow } 1154bff34e3Sthurlow f = fopen(filename, "r"); 1164bff34e3Sthurlow if (f == NULL) 1174bff34e3Sthurlow return (errno); 1184bff34e3Sthurlow t = rcp->rf_f; 1194bff34e3Sthurlow rcp->rf_f = f; 1204bff34e3Sthurlow rc_parse(rcp); 1214bff34e3Sthurlow rcp->rf_f = t; 1224bff34e3Sthurlow fclose(f); 1234bff34e3Sthurlow return (0); 1244bff34e3Sthurlow } 1254bff34e3Sthurlow 1264bff34e3Sthurlow int 1274bff34e3Sthurlow rc_merge_pipe(const char *command, struct rcfile **rcfile) 1284bff34e3Sthurlow { 1294bff34e3Sthurlow struct rcfile *rcp = *rcfile; 1304bff34e3Sthurlow FILE *f, *t; 1314bff34e3Sthurlow 1324bff34e3Sthurlow insecure_nsmbrc = 0; 1334bff34e3Sthurlow f = popen(command, "r"); 1344bff34e3Sthurlow if (f == NULL) 1354bff34e3Sthurlow return (errno); 1364bff34e3Sthurlow if (rcp == NULL) { 1374bff34e3Sthurlow rcp = malloc(sizeof (struct rcfile)); 1384bff34e3Sthurlow if (rcp == NULL) { 1394bff34e3Sthurlow fclose(f); 1404bff34e3Sthurlow return (ENOMEM); 1414bff34e3Sthurlow } 1424bff34e3Sthurlow *rcfile = rcp; 1434bff34e3Sthurlow bzero(rcp, sizeof (struct rcfile)); 1444bff34e3Sthurlow rcp->rf_name = strdup(command); 1454bff34e3Sthurlow rcp->rf_f = f; 1464bff34e3Sthurlow SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); 1474bff34e3Sthurlow rc_parse(rcp); 1484bff34e3Sthurlow } else { 1494bff34e3Sthurlow t = rcp->rf_f; 1504bff34e3Sthurlow rcp->rf_f = f; 1514bff34e3Sthurlow rc_parse(rcp); 1524bff34e3Sthurlow rcp->rf_f = t; 1534bff34e3Sthurlow } 1544bff34e3Sthurlow fclose(f); 1554bff34e3Sthurlow return (0); 1564bff34e3Sthurlow } 1574bff34e3Sthurlow 1584bff34e3Sthurlow int 1594bff34e3Sthurlow rc_close(struct rcfile *rcp) 1604bff34e3Sthurlow { 1614bff34e3Sthurlow struct rcsection *p, *n; 1624bff34e3Sthurlow 1634bff34e3Sthurlow fclose(rcp->rf_f); 1644bff34e3Sthurlow for (p = SLIST_FIRST(&rcp->rf_sect); p; ) { 1654bff34e3Sthurlow n = p; 1664bff34e3Sthurlow p = SLIST_NEXT(p, rs_next); 1674bff34e3Sthurlow rc_freesect(rcp, n); 1684bff34e3Sthurlow } 1694bff34e3Sthurlow free(rcp->rf_name); 1704bff34e3Sthurlow SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next); 1714bff34e3Sthurlow free(rcp); 1724bff34e3Sthurlow return (0); 1734bff34e3Sthurlow } 1744bff34e3Sthurlow 1754bff34e3Sthurlow static struct rcfile * 1764bff34e3Sthurlow rc_cachelookup(const char *filename) 1774bff34e3Sthurlow { 1784bff34e3Sthurlow struct rcfile *p; 1794bff34e3Sthurlow 1804bff34e3Sthurlow SLIST_FOREACH(p, &pf_head, rf_next) 1814bff34e3Sthurlow if (strcmp(filename, p->rf_name) == 0) 1824bff34e3Sthurlow return (p); 1834bff34e3Sthurlow return (0); 1844bff34e3Sthurlow } 1854bff34e3Sthurlow 1864bff34e3Sthurlow /* static */ struct rcsection * 1874bff34e3Sthurlow rc_findsect(struct rcfile *rcp, const char *sectname) 1884bff34e3Sthurlow { 1894bff34e3Sthurlow struct rcsection *p; 1904bff34e3Sthurlow 1914bff34e3Sthurlow SLIST_FOREACH(p, &rcp->rf_sect, rs_next) 1924bff34e3Sthurlow if (strcasecmp(p->rs_name, sectname) == 0) 1934bff34e3Sthurlow return (p); 1944bff34e3Sthurlow return (NULL); 1954bff34e3Sthurlow } 1964bff34e3Sthurlow 1974bff34e3Sthurlow static struct rcsection * 1984bff34e3Sthurlow rc_addsect(struct rcfile *rcp, const char *sectname) 1994bff34e3Sthurlow { 2004bff34e3Sthurlow struct rcsection *p; 2014bff34e3Sthurlow 2024bff34e3Sthurlow p = rc_findsect(rcp, sectname); 2034bff34e3Sthurlow if (p) 2044bff34e3Sthurlow return (p); 2054bff34e3Sthurlow p = malloc(sizeof (*p)); 2064bff34e3Sthurlow if (!p) 2074bff34e3Sthurlow return (NULL); 2084bff34e3Sthurlow p->rs_name = strdup(sectname); 2094bff34e3Sthurlow SLIST_INIT(&p->rs_keys); 2104bff34e3Sthurlow SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next); 2114bff34e3Sthurlow return (p); 2124bff34e3Sthurlow } 2134bff34e3Sthurlow 2144bff34e3Sthurlow static int 2154bff34e3Sthurlow rc_freesect(struct rcfile *rcp, struct rcsection *rsp) 2164bff34e3Sthurlow { 2174bff34e3Sthurlow struct rckey *p, *n; 2184bff34e3Sthurlow 2194bff34e3Sthurlow SLIST_REMOVE(&rcp->rf_sect, rsp, rcsection, rs_next); 2204bff34e3Sthurlow for (p = SLIST_FIRST(&rsp->rs_keys); p; ) { 2214bff34e3Sthurlow n = p; 2224bff34e3Sthurlow p = SLIST_NEXT(p, rk_next); 2234bff34e3Sthurlow rc_key_free(n); 2244bff34e3Sthurlow } 2254bff34e3Sthurlow free(rsp->rs_name); 2264bff34e3Sthurlow free(rsp); 2274bff34e3Sthurlow return (0); 2284bff34e3Sthurlow } 2294bff34e3Sthurlow 2304bff34e3Sthurlow /* static */ struct rckey * 2314bff34e3Sthurlow rc_sect_findkey(struct rcsection *rsp, const char *keyname) 2324bff34e3Sthurlow { 2334bff34e3Sthurlow struct rckey *p; 2344bff34e3Sthurlow 2354bff34e3Sthurlow SLIST_FOREACH(p, &rsp->rs_keys, rk_next) 2364bff34e3Sthurlow if (strcmp(p->rk_name, keyname) == 0) 2374bff34e3Sthurlow return (p); 2384bff34e3Sthurlow return (NULL); 2394bff34e3Sthurlow } 2404bff34e3Sthurlow 2414bff34e3Sthurlow static struct rckey * 2424bff34e3Sthurlow rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value) 2434bff34e3Sthurlow { 2444bff34e3Sthurlow struct rckey *p; 2454bff34e3Sthurlow 2464bff34e3Sthurlow p = rc_sect_findkey(rsp, name); 2474bff34e3Sthurlow if (!p) { 2484bff34e3Sthurlow p = malloc(sizeof (*p)); 2494bff34e3Sthurlow if (!p) 2504bff34e3Sthurlow return (NULL); 2514bff34e3Sthurlow SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next); 2524bff34e3Sthurlow p->rk_name = strdup(name); 2534bff34e3Sthurlow p->rk_value = value ? strdup(value) : strdup(""); 2544bff34e3Sthurlow } 2554bff34e3Sthurlow return (p); 2564bff34e3Sthurlow } 2574bff34e3Sthurlow 2584bff34e3Sthurlow #if 0 2594bff34e3Sthurlow void 2604bff34e3Sthurlow rc_sect_delkey(struct rcsection *rsp, struct rckey *p) 2614bff34e3Sthurlow { 2624bff34e3Sthurlow 2634bff34e3Sthurlow SLIST_REMOVE(&rsp->rs_keys, p, rckey, rk_next); 2644bff34e3Sthurlow rc_key_free(p); 2654bff34e3Sthurlow } 2664bff34e3Sthurlow #endif 2674bff34e3Sthurlow 2684bff34e3Sthurlow static void 2694bff34e3Sthurlow rc_key_free(struct rckey *p) 2704bff34e3Sthurlow { 2714bff34e3Sthurlow free(p->rk_value); 2724bff34e3Sthurlow free(p->rk_name); 2734bff34e3Sthurlow free(p); 2744bff34e3Sthurlow } 2754bff34e3Sthurlow 2764bff34e3Sthurlow enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; 2774bff34e3Sthurlow 2784bff34e3Sthurlow int home_nsmbrc = 0; 2794bff34e3Sthurlow 2804bff34e3Sthurlow static char *minauth[] = { 2814bff34e3Sthurlow "kerberos", 2824bff34e3Sthurlow "ntlmv2", 2834bff34e3Sthurlow "ntlm", 2844bff34e3Sthurlow "lm", 2854bff34e3Sthurlow "none", 2864bff34e3Sthurlow NULL 2874bff34e3Sthurlow }; 2884bff34e3Sthurlow 2894bff34e3Sthurlow static int 2904bff34e3Sthurlow eval_minauth(char *auth) 2914bff34e3Sthurlow { 2924bff34e3Sthurlow int i; 2934bff34e3Sthurlow 2944bff34e3Sthurlow for (i = 0; minauth[i]; i++) 2954bff34e3Sthurlow if (strcmp(auth, minauth[i]) == 0) 2964bff34e3Sthurlow break; 2974bff34e3Sthurlow return (i); 2984bff34e3Sthurlow } 2994bff34e3Sthurlow 3004bff34e3Sthurlow /* 3014bff34e3Sthurlow * Ensure that "minauth" is set to the highest level (lowest array offset) 3024bff34e3Sthurlow */ 3034bff34e3Sthurlow static void 3044bff34e3Sthurlow set_value(struct rcfile *rcp, struct rcsection *rsp, struct rckey *rkp, 3054bff34e3Sthurlow char *ptr) 3064bff34e3Sthurlow { 3074bff34e3Sthurlow int now, new; 3084bff34e3Sthurlow 3094bff34e3Sthurlow if (strcmp(rkp->rk_name, "minauth") == 0) { 3104bff34e3Sthurlow now = eval_minauth(rkp->rk_value); 3114bff34e3Sthurlow new = eval_minauth(ptr); 3124bff34e3Sthurlow if (new >= now) { 3134bff34e3Sthurlow #ifdef DEBUG 314*9c9af259SGordon Ross if (smb_debug) 315*9c9af259SGordon Ross printf( 316*9c9af259SGordon Ross "set_value: rejecting %s=%s from %s\n", 317*9c9af259SGordon Ross rkp->rk_name, ptr, home_nsmbrc ? 318*9c9af259SGordon Ross "user file" : "SMF"); 3194bff34e3Sthurlow #endif 3204bff34e3Sthurlow return; 3214bff34e3Sthurlow } 3224bff34e3Sthurlow } 3234bff34e3Sthurlow #ifdef DEBUG 324*9c9af259SGordon Ross if (smb_debug) 3254bff34e3Sthurlow printf("set_value: applying %s=%s from %s\n", 3264bff34e3Sthurlow rkp->rk_name, ptr, home_nsmbrc ? "user file" : "SMF"); 3274bff34e3Sthurlow #endif 3284bff34e3Sthurlow rkp->rk_value = strdup(ptr); 3294bff34e3Sthurlow } 3304bff34e3Sthurlow 3314bff34e3Sthurlow static void 3324bff34e3Sthurlow rc_parse(struct rcfile *rcp) 3334bff34e3Sthurlow { 3344bff34e3Sthurlow FILE *f = rcp->rf_f; 3354bff34e3Sthurlow int state = stNewLine, c; 3364bff34e3Sthurlow struct rcsection *rsp = NULL; 3374bff34e3Sthurlow struct rckey *rkp = NULL; 3384bff34e3Sthurlow char buf[2048]; 3394bff34e3Sthurlow char *next = buf, *last = &buf[sizeof (buf)-1]; 3404bff34e3Sthurlow 3414bff34e3Sthurlow while ((c = getc(f)) != EOF) { 3424bff34e3Sthurlow if (c == '\r') 3434bff34e3Sthurlow continue; 3444bff34e3Sthurlow if (state == stNewLine) { 3454bff34e3Sthurlow next = buf; 3464bff34e3Sthurlow if (isspace(c)) 3474bff34e3Sthurlow continue; /* skip leading junk */ 3484bff34e3Sthurlow if (c == '[') { 3494bff34e3Sthurlow state = stHeader; 3504bff34e3Sthurlow rsp = NULL; 3514bff34e3Sthurlow continue; 3524bff34e3Sthurlow } 3534bff34e3Sthurlow if (c == '#' || c == ';') { 3544bff34e3Sthurlow state = stSkipToEOL; 3554bff34e3Sthurlow } else { /* something meaningfull */ 3564bff34e3Sthurlow state = stGetKey; 3574bff34e3Sthurlow } 3584bff34e3Sthurlow } 3594bff34e3Sthurlow /* ignore long lines */ 3604bff34e3Sthurlow if (state == stSkipToEOL || next == last) { 3614bff34e3Sthurlow if (c == '\n') { 3624bff34e3Sthurlow state = stNewLine; 3634bff34e3Sthurlow next = buf; 3644bff34e3Sthurlow } 3654bff34e3Sthurlow continue; 3664bff34e3Sthurlow } 3674bff34e3Sthurlow if (state == stHeader) { 3684bff34e3Sthurlow if (c == ']') { 3694bff34e3Sthurlow *next = 0; 3704bff34e3Sthurlow next = buf; 3714bff34e3Sthurlow rsp = rc_addsect(rcp, buf); 3724bff34e3Sthurlow state = stSkipToEOL; 3734bff34e3Sthurlow } else 3744bff34e3Sthurlow *next++ = c; 3754bff34e3Sthurlow continue; 3764bff34e3Sthurlow } 3774bff34e3Sthurlow if (state == stGetKey) { 3784bff34e3Sthurlow /* side effect: 'key name=' */ 3794bff34e3Sthurlow if (c == ' ' || c == '\t') 3804bff34e3Sthurlow continue; /* become 'keyname=' */ 3814bff34e3Sthurlow if (c == '\n') { /* silently ignore ... */ 3824bff34e3Sthurlow state = stNewLine; 3834bff34e3Sthurlow continue; 3844bff34e3Sthurlow } 3854bff34e3Sthurlow if (c != '=') { 3864bff34e3Sthurlow *next++ = c; 3874bff34e3Sthurlow continue; 3884bff34e3Sthurlow } 3894bff34e3Sthurlow *next = 0; 3904bff34e3Sthurlow if (rsp == NULL) { 3914bff34e3Sthurlow fprintf(stderr, dgettext(TEXT_DOMAIN, 3924bff34e3Sthurlow "Key '%s' defined before section\n"), buf); 3934bff34e3Sthurlow state = stSkipToEOL; 3944bff34e3Sthurlow continue; 3954bff34e3Sthurlow } 3964bff34e3Sthurlow if (home_nsmbrc && 3974bff34e3Sthurlow (strcmp(buf, "nbns") == 0 || 3984bff34e3Sthurlow strcmp(buf, "nbns_enable") == 0 || 399*9c9af259SGordon Ross strcmp(buf, "nbns_broadcast") == 0 || 400*9c9af259SGordon Ross strcmp(buf, "signing") == 0)) { 4014bff34e3Sthurlow fprintf(stderr, dgettext(TEXT_DOMAIN, 4024bff34e3Sthurlow "option %s may not be set " 4034bff34e3Sthurlow "in user .nsmbrc file\n"), buf); 4044bff34e3Sthurlow next = buf; 4054bff34e3Sthurlow state = stNewLine; 4064bff34e3Sthurlow continue; 4074bff34e3Sthurlow } 4084bff34e3Sthurlow if (insecure_nsmbrc && (strcmp(buf, "password") == 0)) { 4094bff34e3Sthurlow fprintf(stderr, dgettext(TEXT_DOMAIN, 4104bff34e3Sthurlow "Warning: .nsmbrc file not secure, " 4114bff34e3Sthurlow "ignoring passwords\n")); 4124bff34e3Sthurlow next = buf; 4134bff34e3Sthurlow state = stNewLine; 4144bff34e3Sthurlow continue; 4154bff34e3Sthurlow } 4164bff34e3Sthurlow rkp = rc_sect_addkey(rsp, buf, NULL); 4174bff34e3Sthurlow next = buf; 4184bff34e3Sthurlow state = stGetValue; 4194bff34e3Sthurlow continue; 4204bff34e3Sthurlow } 4214bff34e3Sthurlow /* only stGetValue left */ 4224bff34e3Sthurlow if (state != stGetValue) { 4234bff34e3Sthurlow fprintf(stderr, dgettext(TEXT_DOMAIN, 4244bff34e3Sthurlow "Well, I can't parse file '%s'\n"), rcp->rf_name); 4254bff34e3Sthurlow state = stSkipToEOL; 4264bff34e3Sthurlow } 4274bff34e3Sthurlow if (c != '\n') { 4284bff34e3Sthurlow *next++ = c; 4294bff34e3Sthurlow continue; 4304bff34e3Sthurlow } 4314bff34e3Sthurlow *next = 0; 4324bff34e3Sthurlow set_value(rcp, rsp, rkp, buf); 4334bff34e3Sthurlow state = stNewLine; 4344bff34e3Sthurlow rkp = NULL; 4354bff34e3Sthurlow } /* while */ 4364bff34e3Sthurlow if (c == EOF && state == stGetValue) { 4374bff34e3Sthurlow *next = 0; 4384bff34e3Sthurlow set_value(rcp, rsp, rkp, buf); 4394bff34e3Sthurlow } 4404bff34e3Sthurlow } 4414bff34e3Sthurlow 4424bff34e3Sthurlow int 4434bff34e3Sthurlow rc_getstringptr(struct rcfile *rcp, const char *section, const char *key, 4444bff34e3Sthurlow char **dest) 4454bff34e3Sthurlow { 4464bff34e3Sthurlow struct rcsection *rsp; 4474bff34e3Sthurlow struct rckey *rkp; 4484bff34e3Sthurlow 4494bff34e3Sthurlow *dest = NULL; 4504bff34e3Sthurlow rsp = rc_findsect(rcp, section); 4514bff34e3Sthurlow if (!rsp) 4524bff34e3Sthurlow return (ENOENT); 4534bff34e3Sthurlow rkp = rc_sect_findkey(rsp, key); 4544bff34e3Sthurlow if (!rkp) 4554bff34e3Sthurlow return (ENOENT); 4564bff34e3Sthurlow *dest = rkp->rk_value; 4574bff34e3Sthurlow return (0); 4584bff34e3Sthurlow } 4594bff34e3Sthurlow 4604bff34e3Sthurlow int 4614bff34e3Sthurlow rc_getstring(struct rcfile *rcp, const char *section, const char *key, 4624bff34e3Sthurlow size_t maxlen, char *dest) 4634bff34e3Sthurlow { 4644bff34e3Sthurlow char *value; 4654bff34e3Sthurlow int error; 4664bff34e3Sthurlow 4674bff34e3Sthurlow error = rc_getstringptr(rcp, section, key, &value); 4684bff34e3Sthurlow if (error) 4694bff34e3Sthurlow return (error); 4704bff34e3Sthurlow if (strlen(value) >= maxlen) { 4714bff34e3Sthurlow fprintf(stdout, dgettext(TEXT_DOMAIN, 4724bff34e3Sthurlow "line too long for key '%s' in section '%s', max = %d\n"), 4734bff34e3Sthurlow key, section, maxlen); 4744bff34e3Sthurlow return (EINVAL); 4754bff34e3Sthurlow } 4764bff34e3Sthurlow strcpy(dest, value); 4774bff34e3Sthurlow return (0); 4784bff34e3Sthurlow } 4794bff34e3Sthurlow 4804bff34e3Sthurlow int 4814bff34e3Sthurlow rc_getint(struct rcfile *rcp, const char *section, const char *key, int *value) 4824bff34e3Sthurlow { 4834bff34e3Sthurlow struct rcsection *rsp; 4844bff34e3Sthurlow struct rckey *rkp; 4854bff34e3Sthurlow 4864bff34e3Sthurlow rsp = rc_findsect(rcp, section); 4874bff34e3Sthurlow if (!rsp) 4884bff34e3Sthurlow return (ENOENT); 4894bff34e3Sthurlow rkp = rc_sect_findkey(rsp, key); 4904bff34e3Sthurlow if (!rkp) 4914bff34e3Sthurlow return (ENOENT); 4924bff34e3Sthurlow errno = 0; 4934bff34e3Sthurlow *value = strtol(rkp->rk_value, NULL, 0); 4944bff34e3Sthurlow if (errno) { 4954bff34e3Sthurlow fprintf(stdout, dgettext(TEXT_DOMAIN, 4964bff34e3Sthurlow "invalid int value '%s' for key '%s' in section '%s'\n"), 4974bff34e3Sthurlow rkp->rk_value, key, section); 4984bff34e3Sthurlow return (errno); 4994bff34e3Sthurlow } 5004bff34e3Sthurlow return (0); 5014bff34e3Sthurlow } 5024bff34e3Sthurlow 5034bff34e3Sthurlow /* 5044bff34e3Sthurlow * 1,yes,true 5054bff34e3Sthurlow * 0,no,false 5064bff34e3Sthurlow */ 5074bff34e3Sthurlow int 5084bff34e3Sthurlow rc_getbool(struct rcfile *rcp, const char *section, const char *key, int *value) 5094bff34e3Sthurlow { 5104bff34e3Sthurlow struct rcsection *rsp; 5114bff34e3Sthurlow struct rckey *rkp; 5124bff34e3Sthurlow char *p; 5134bff34e3Sthurlow 5144bff34e3Sthurlow rsp = rc_findsect(rcp, section); 5154bff34e3Sthurlow if (!rsp) 5164bff34e3Sthurlow return (ENOENT); 5174bff34e3Sthurlow rkp = rc_sect_findkey(rsp, key); 5184bff34e3Sthurlow if (!rkp) 5194bff34e3Sthurlow return (ENOENT); 5204bff34e3Sthurlow p = rkp->rk_value; 5214bff34e3Sthurlow while (*p && isspace(*p)) p++; 5224bff34e3Sthurlow if (*p == '0' || 5234bff34e3Sthurlow strcasecmp(p, "no") == 0 || 5244bff34e3Sthurlow strcasecmp(p, "false") == 0) { 5254bff34e3Sthurlow *value = 0; 5264bff34e3Sthurlow return (0); 5274bff34e3Sthurlow } 5284bff34e3Sthurlow if (*p == '1' || 5294bff34e3Sthurlow strcasecmp(p, "yes") == 0 || 5304bff34e3Sthurlow strcasecmp(p, "true") == 0) { 5314bff34e3Sthurlow *value = 1; 5324bff34e3Sthurlow return (0); 5334bff34e3Sthurlow } 5344bff34e3Sthurlow fprintf(stderr, dgettext(TEXT_DOMAIN, 5354bff34e3Sthurlow "invalid boolean value '%s' for key '%s' in section '%s' \n"), 5364bff34e3Sthurlow p, key, section); 5374bff34e3Sthurlow return (EINVAL); 5384bff34e3Sthurlow } 5394bff34e3Sthurlow 5404bff34e3Sthurlow /* 5414bff34e3Sthurlow * Unified command line/rc file parser 5424bff34e3Sthurlow */ 5434bff34e3Sthurlow int 5444bff34e3Sthurlow opt_args_parse(struct rcfile *rcp, struct opt_args *ap, const char *sect, 5454bff34e3Sthurlow opt_callback_t *callback) 5464bff34e3Sthurlow { 5474bff34e3Sthurlow int len, error; 5484bff34e3Sthurlow 5494bff34e3Sthurlow for (; ap->opt; ap++) { 5504bff34e3Sthurlow switch (ap->type) { 5514bff34e3Sthurlow case OPTARG_STR: 5524bff34e3Sthurlow if (rc_getstringptr(rcp, sect, ap->name, &ap->str) != 0) 5534bff34e3Sthurlow break; 5544bff34e3Sthurlow len = strlen(ap->str); 5554bff34e3Sthurlow if (len > ap->ival) { 5564bff34e3Sthurlow fprintf(stdout, dgettext(TEXT_DOMAIN, 5574bff34e3Sthurlow "rc: argument for option '%c' (%s) too long\n"), 5584bff34e3Sthurlow ap->opt, ap->name); 5594bff34e3Sthurlow return (EINVAL); 5604bff34e3Sthurlow } 5614bff34e3Sthurlow callback(ap); 5624bff34e3Sthurlow break; 5634bff34e3Sthurlow case OPTARG_BOOL: 5644bff34e3Sthurlow error = rc_getbool(rcp, sect, ap->name, &ap->ival); 5654bff34e3Sthurlow if (error == ENOENT) 5664bff34e3Sthurlow break; 5674bff34e3Sthurlow if (error) 5684bff34e3Sthurlow return (EINVAL); 5694bff34e3Sthurlow callback(ap); 5704bff34e3Sthurlow break; 5714bff34e3Sthurlow case OPTARG_INT: 5724bff34e3Sthurlow if (rc_getint(rcp, sect, ap->name, &ap->ival) != 0) 5734bff34e3Sthurlow break; 5744bff34e3Sthurlow if (((ap->flag & OPTFL_HAVEMIN) && 5754bff34e3Sthurlow ap->ival < ap->min) || 5764bff34e3Sthurlow ((ap->flag & OPTFL_HAVEMAX) && 5774bff34e3Sthurlow ap->ival > ap->max)) { 5784bff34e3Sthurlow fprintf(stdout, dgettext(TEXT_DOMAIN, 5794bff34e3Sthurlow "rc: argument for option '%c' (%s) " 5804bff34e3Sthurlow "should be in [%d-%d] range\n"), 5814bff34e3Sthurlow ap->opt, ap->name, ap->min, ap->max); 5824bff34e3Sthurlow return (EINVAL); 5834bff34e3Sthurlow } 5844bff34e3Sthurlow callback(ap); 5854bff34e3Sthurlow break; 5864bff34e3Sthurlow default: 5874bff34e3Sthurlow break; 5884bff34e3Sthurlow } 5894bff34e3Sthurlow } 5904bff34e3Sthurlow return (0); 5914bff34e3Sthurlow } 5924bff34e3Sthurlow 5934bff34e3Sthurlow int 5944bff34e3Sthurlow opt_args_parseopt(struct opt_args *ap, int opt, char *arg, 5954bff34e3Sthurlow opt_callback_t *callback) 5964bff34e3Sthurlow { 5974bff34e3Sthurlow int len; 5984bff34e3Sthurlow 5994bff34e3Sthurlow for (; ap->opt; ap++) { 6004bff34e3Sthurlow if (ap->opt != opt) 6014bff34e3Sthurlow continue; 6024bff34e3Sthurlow switch (ap->type) { 6034bff34e3Sthurlow case OPTARG_STR: 6044bff34e3Sthurlow ap->str = arg; 6054bff34e3Sthurlow if (arg) { 6064bff34e3Sthurlow len = strlen(ap->str); 6074bff34e3Sthurlow if (len > ap->ival) { 6084bff34e3Sthurlow fprintf(stdout, dgettext(TEXT_DOMAIN, 6094bff34e3Sthurlow "opt: Argument for option '%c' (%s) too long\n"), 6104bff34e3Sthurlow ap->opt, ap->name); 6114bff34e3Sthurlow return (EINVAL); 6124bff34e3Sthurlow } 6134bff34e3Sthurlow callback(ap); 6144bff34e3Sthurlow } 6154bff34e3Sthurlow break; 6164bff34e3Sthurlow case OPTARG_BOOL: 6174bff34e3Sthurlow ap->ival = 0; 6184bff34e3Sthurlow callback(ap); 6194bff34e3Sthurlow break; 6204bff34e3Sthurlow case OPTARG_INT: 6214bff34e3Sthurlow errno = 0; 6224bff34e3Sthurlow ap->ival = strtol(arg, NULL, 0); 6234bff34e3Sthurlow if (errno) { 6244bff34e3Sthurlow fprintf(stdout, dgettext(TEXT_DOMAIN, 6254bff34e3Sthurlow "opt: Invalid integer value for " 6264bff34e3Sthurlow "option '%c' (%s).\n"), 6274bff34e3Sthurlow ap->opt, ap->name); 6284bff34e3Sthurlow return (EINVAL); 6294bff34e3Sthurlow } 6304bff34e3Sthurlow if (((ap->flag & OPTFL_HAVEMIN) && 6314bff34e3Sthurlow (ap->ival < ap->min)) || 6324bff34e3Sthurlow ((ap->flag & OPTFL_HAVEMAX) && 6334bff34e3Sthurlow (ap->ival > ap->max))) { 6344bff34e3Sthurlow fprintf(stdout, dgettext(TEXT_DOMAIN, 6354bff34e3Sthurlow "opt: Argument for option '%c' (%s) " 6364bff34e3Sthurlow "should be in [%d-%d] range\n"), 6374bff34e3Sthurlow ap->opt, ap->name, ap->min, ap->max); 6384bff34e3Sthurlow return (EINVAL); 6394bff34e3Sthurlow } 6404bff34e3Sthurlow callback(ap); 6414bff34e3Sthurlow break; 6424bff34e3Sthurlow default: 6434bff34e3Sthurlow break; 6444bff34e3Sthurlow } 6454bff34e3Sthurlow break; 6464bff34e3Sthurlow } 6474bff34e3Sthurlow return (0); 6484bff34e3Sthurlow } 649