2 * Copyright (c) 2000, Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $Id: rcfile.c,v 1.1.1.2 2001/07/06 22:38:43 conrad Exp $
36 #include <sys/types.h>
37 #include <sys/queue.h>
52 #include "rcfile_priv.h"
56 #if 0 /* before SMF */
57 #define SMB_CFG_FILE "/etc/nsmb.conf"
58 #define OLD_SMB_CFG_FILE "/usr/local/etc/nsmb.conf"
60 #define SMBFS_SHARECTL_CMD "/usr/sbin/sharectl get smbfs"
64 static struct rcfile
*rc_cachelookup(const char *filename
);
65 static struct rcsection
*rc_findsect(struct rcfile
*rcp
, const char *sectname
);
66 static struct rcsection
*rc_addsect(struct rcfile
*rcp
, const char *sectname
);
67 static int rc_freesect(struct rcfile
*rcp
, struct rcsection
*rsp
);
68 static struct rckey
*rc_sect_findkey(struct rcsection
*rsp
, const char *key
);
69 static struct rckey
*rc_sect_addkey(struct rcsection
*rsp
, const char *name
,
71 static void rc_key_free(struct rckey
*p
);
72 static void rc_parse(struct rcfile
*rcp
);
74 /* lock for the variables below */
75 mutex_t rcfile_mutex
= DEFAULTMUTEX
;
77 SLIST_HEAD(rcfile_head
, rcfile
);
78 static struct rcfile_head pf_head
= {NULL
};
79 struct rcfile
*smb_rc
;
84 * open rcfile and load its content, if already open - return previous handle
87 rc_open(const char *filename
, const char *mode
, struct rcfile
**rcfile
)
93 assert(MUTEX_HELD(&rcfile_mutex
));
95 rcp
= rc_cachelookup(filename
);
100 f
= fopen(filename
, mode
);
104 if (fstat(fileno(f
), &statbuf
) >= 0 &&
105 (statbuf
.st_mode
& 077) != 0)
107 rcp
= malloc(sizeof (struct rcfile
));
112 bzero(rcp
, sizeof (struct rcfile
));
113 rcp
->rf_name
= strdup(filename
);
115 SLIST_INSERT_HEAD(&pf_head
, rcp
, rf_next
);
122 rc_merge(const char *filename
, struct rcfile
**rcfile
)
125 struct rcfile
*rcp
= *rcfile
;
128 assert(MUTEX_HELD(&rcfile_mutex
));
132 return (rc_open(filename
, "r", rcfile
));
134 f
= fopen(filename
, "r");
138 if (fstat(fileno(f
), &statbuf
) >= 0 &&
139 (statbuf
.st_mode
& 077) != 0)
150 * Like rc_open, but does popen of command:
154 rc_popen_cmd(const char *command
, struct rcfile
**rcfile
)
159 assert(MUTEX_HELD(&rcfile_mutex
));
161 f
= popen(command
, "r");
166 rcp
= malloc(sizeof (struct rcfile
));
171 bzero(rcp
, sizeof (struct rcfile
));
172 rcp
->rf_name
= strdup(command
);
174 SLIST_INSERT_HEAD(&pf_head
, rcp
, rf_next
);
177 /* fclose(f) in rc_close */
182 rc_close(struct rcfile
*rcp
)
184 struct rcsection
*p
, *n
;
186 mutex_lock(&rcfile_mutex
);
189 for (p
= SLIST_FIRST(&rcp
->rf_sect
); p
; ) {
191 p
= SLIST_NEXT(p
, rs_next
);
195 SLIST_REMOVE(&pf_head
, rcp
, rcfile
, rf_next
);
198 mutex_unlock(&rcfile_mutex
);
202 static struct rcfile
*
203 rc_cachelookup(const char *filename
)
207 assert(MUTEX_HELD(&rcfile_mutex
));
209 SLIST_FOREACH(p
, &pf_head
, rf_next
)
210 if (strcmp(filename
, p
->rf_name
) == 0)
215 static struct rcsection
*
216 rc_findsect(struct rcfile
*rcp
, const char *sectname
)
220 assert(MUTEX_HELD(&rcfile_mutex
));
222 SLIST_FOREACH(p
, &rcp
->rf_sect
, rs_next
)
223 if (strcasecmp(p
->rs_name
, sectname
) == 0)
228 static struct rcsection
*
229 rc_addsect(struct rcfile
*rcp
, const char *sectname
)
233 assert(MUTEX_HELD(&rcfile_mutex
));
235 p
= rc_findsect(rcp
, sectname
);
238 p
= malloc(sizeof (*p
));
241 p
->rs_name
= strdup(sectname
);
242 SLIST_INIT(&p
->rs_keys
);
243 SLIST_INSERT_HEAD(&rcp
->rf_sect
, p
, rs_next
);
248 rc_freesect(struct rcfile
*rcp
, struct rcsection
*rsp
)
252 assert(MUTEX_HELD(&rcfile_mutex
));
254 SLIST_REMOVE(&rcp
->rf_sect
, rsp
, rcsection
, rs_next
);
255 for (p
= SLIST_FIRST(&rsp
->rs_keys
); p
; ) {
257 p
= SLIST_NEXT(p
, rk_next
);
265 static struct rckey
*
266 rc_sect_findkey(struct rcsection
*rsp
, const char *keyname
)
270 assert(MUTEX_HELD(&rcfile_mutex
));
272 SLIST_FOREACH(p
, &rsp
->rs_keys
, rk_next
)
273 if (strcmp(p
->rk_name
, keyname
) == 0)
278 static struct rckey
*
279 rc_sect_addkey(struct rcsection
*rsp
, const char *name
, const char *value
)
283 assert(MUTEX_HELD(&rcfile_mutex
));
285 p
= rc_sect_findkey(rsp
, name
);
287 p
= malloc(sizeof (*p
));
290 SLIST_INSERT_HEAD(&rsp
->rs_keys
, p
, rk_next
);
291 p
->rk_name
= strdup(name
);
292 p
->rk_value
= value
? strdup(value
) : strdup("");
299 rc_sect_delkey(struct rcsection
*rsp
, struct rckey
*p
)
302 SLIST_REMOVE(&rsp
->rs_keys
, p
, rckey
, rk_next
);
308 rc_key_free(struct rckey
*p
)
316 static char *minauth_values
[] = {
326 eval_minauth(char *auth
)
330 for (i
= 0; minauth_values
[i
]; i
++)
331 if (strcmp(auth
, minauth_values
[i
]) == 0)
337 * Ensure that "minauth" is set to the highest level
341 set_value(struct rcfile
*rcp
, struct rcsection
*rsp
, struct rckey
*rkp
,
349 from
= (home_nsmbrc
) ?
353 if (strcmp(rkp
->rk_name
, "minauth") == 0) {
354 now
= eval_minauth(rkp
->rk_value
);
355 new = eval_minauth(ptr
);
360 "set_value: rejecting %s=%s"
371 "set_value: applying %s=%s in %s from %s\n",
372 rkp
->rk_name
, ptr
, rsp
->rs_name
, from
);
374 rkp
->rk_value
= strdup(ptr
);
378 /* states in rc_parse */
379 enum { stNewLine
, stHeader
, stSkipToEOL
, stGetKey
, stGetValue
};
382 rc_parse(struct rcfile
*rcp
)
385 int state
= stNewLine
, c
;
386 struct rcsection
*rsp
= NULL
;
387 struct rckey
*rkp
= NULL
;
389 char *next
= buf
, *last
= &buf
[sizeof (buf
)-1];
391 assert(MUTEX_HELD(&rcfile_mutex
));
393 while ((c
= getc(f
)) != EOF
) {
396 if (state
== stNewLine
) {
399 continue; /* skip leading junk */
405 if (c
== '#' || c
== ';') {
407 } else { /* something meaningfull */
411 /* ignore long lines */
412 if (state
== stSkipToEOL
|| next
== last
) {
419 if (state
== stHeader
) {
423 rsp
= rc_addsect(rcp
, buf
);
429 if (state
== stGetKey
) {
430 /* side effect: 'key name=' */
431 if (c
== ' ' || c
== '\t')
432 continue; /* become 'keyname=' */
433 if (c
== '\n') { /* silently ignore ... */
443 fprintf(stderr
, dgettext(TEXT_DOMAIN
,
444 "Key '%s' defined before section\n"), buf
);
448 if (home_nsmbrc
!= 0 && (
449 strcmp(buf
, "nbns") == 0 ||
450 strcmp(buf
, "nbns_enable") == 0 ||
451 strcmp(buf
, "nbns_broadcast") == 0 ||
452 strcmp(buf
, "signing") == 0)) {
453 fprintf(stderr
, dgettext(TEXT_DOMAIN
,
454 "option %s may not be set "
455 "in user .nsmbrc file\n"), buf
);
460 if (insecure_nsmbrc
!= 0 &&
461 strcmp(buf
, "password") == 0) {
462 fprintf(stderr
, dgettext(TEXT_DOMAIN
,
463 "Warning: .nsmbrc file not secure, "
464 "ignoring passwords\n"));
469 rkp
= rc_sect_addkey(rsp
, buf
, NULL
);
474 /* only stGetValue left */
475 if (state
!= stGetValue
) {
476 fprintf(stderr
, dgettext(TEXT_DOMAIN
,
477 "Well, I can't parse file '%s'\n"), rcp
->rf_name
);
485 set_value(rcp
, rsp
, rkp
, buf
);
489 if (c
== EOF
&& state
== stGetValue
) {
491 set_value(rcp
, rsp
, rkp
, buf
);
496 rc_getstringptr(struct rcfile
*rcp
, const char *section
, const char *key
,
499 struct rcsection
*rsp
;
503 mutex_lock(&rcfile_mutex
);
506 rsp
= rc_findsect(rcp
, section
);
511 rkp
= rc_sect_findkey(rsp
, key
);
516 *dest
= rkp
->rk_value
;
520 mutex_unlock(&rcfile_mutex
);
525 rc_getstring(struct rcfile
*rcp
, const char *section
, const char *key
,
526 size_t maxlen
, char *dest
)
531 error
= rc_getstringptr(rcp
, section
, key
, &value
);
534 if (strlen(value
) >= maxlen
) {
535 fprintf(stderr
, dgettext(TEXT_DOMAIN
,
536 "line too long for key '%s' in section '%s', max = %d\n"),
537 key
, section
, maxlen
);
545 rc_getint(struct rcfile
*rcp
, const char *section
, const char *key
, int *value
)
547 struct rcsection
*rsp
;
551 mutex_lock(&rcfile_mutex
);
553 rsp
= rc_findsect(rcp
, section
);
558 rkp
= rc_sect_findkey(rsp
, key
);
564 *value
= strtol(rkp
->rk_value
, NULL
, 0);
565 if ((err
= errno
) != 0) {
566 fprintf(stderr
, dgettext(TEXT_DOMAIN
,
567 "invalid int value '%s' for key '%s' in section '%s'\n"),
568 rkp
->rk_value
, key
, section
);
572 mutex_unlock(&rcfile_mutex
);
581 rc_getbool(struct rcfile
*rcp
, const char *section
, const char *key
, int *value
)
583 struct rcsection
*rsp
;
588 mutex_lock(&rcfile_mutex
);
590 rsp
= rc_findsect(rcp
, section
);
595 rkp
= rc_sect_findkey(rsp
, key
);
601 while (*p
&& isspace(*p
)) p
++;
603 strcasecmp(p
, "no") == 0 ||
604 strcasecmp(p
, "false") == 0) {
610 strcasecmp(p
, "yes") == 0 ||
611 strcasecmp(p
, "true") == 0) {
616 fprintf(stderr
, dgettext(TEXT_DOMAIN
,
617 "invalid boolean value '%s' for key '%s' in section '%s' \n"),
622 mutex_unlock(&rcfile_mutex
);
628 dump_props(char *where
)
630 struct rcsection
*rsp
= NULL
;
631 struct rckey
*rkp
= NULL
;
633 fprintf(stderr
, "Settings %s\n", where
);
634 SLIST_FOREACH(rsp
, &smb_rc
->rf_sect
, rs_next
) {
635 fprintf(stderr
, "section=%s\n", rsp
->rs_name
);
638 SLIST_FOREACH(rkp
, &rsp
->rs_keys
, rk_next
) {
639 fprintf(stderr
, " key=%s, value=%s\n",
640 rkp
->rk_name
, rkp
->rk_value
);
648 * first parse "sharectl get smbfs, then $HOME/.nsmbrc
649 * This is called by library consumers (commands)
652 smb_open_rcfile(char *home
)
657 mutex_lock(&rcfile_mutex
);
660 #if 0 /* before SMF */
662 error
= rc_open(fn
, &smb_rc
);
664 fn
= SMBFS_SHARECTL_CMD
;
665 error
= rc_popen_cmd(fn
, &smb_rc
);
667 if (error
!= 0 && error
!= ENOENT
) {
668 /* Error from fopen. strerror is OK. */
669 fprintf(stderr
, dgettext(TEXT_DOMAIN
,
670 "Can't open %s: %s\n"), fn
, strerror(errno
));
678 len
= strlen(home
) + 20;
680 snprintf(fn
, len
, "%s/.nsmbrc", home
);
682 error
= rc_merge(fn
, &smb_rc
);
683 if (error
!= 0 && error
!= ENOENT
) {
684 fprintf(stderr
, dgettext(TEXT_DOMAIN
,
685 "Can't open %s: %s\n"), fn
, strerror(errno
));
695 /* Mostly ignore error returns above. */
701 mutex_unlock(&rcfile_mutex
);
707 * This is called by library consumers (commands)
710 smb_close_rcfile(void)
714 if ((rcp
= smb_rc
) != NULL
) {