ctx.c revision 271259
1/*
2 * Copyright (c) 2000-2002, Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
19 *
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
30 * SUCH DAMAGE.
31 *
32 * $Id: ctx.c,v 1.24 2002/04/13 14:35:28 bp Exp $
33 * $FreeBSD: head/contrib/smbfs/lib/smb/ctx.c 271259 2014-09-08 11:01:57Z trasz $
34 */
35#include <sys/param.h>
36#include <sys/sysctl.h>
37#include <sys/ioctl.h>
38#include <sys/time.h>
39#include <sys/mount.h>
40#include <fcntl.h>
41#include <ctype.h>
42#include <errno.h>
43#include <stdio.h>
44#include <string.h>
45#include <stdlib.h>
46#include <pwd.h>
47#include <grp.h>
48#include <unistd.h>
49#include <sys/iconv.h>
50
51#define NB_NEEDRESOLVER
52
53#include <netsmb/smb_lib.h>
54#include <netsmb/netbios.h>
55#include <netsmb/nb_lib.h>
56#include <netsmb/smb_conn.h>
57#include <cflib.h>
58
59/*
60 * Prescan command line for [-U user] argument
61 * and fill context with defaults
62 */
63int
64smb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[],
65	int minlevel, int maxlevel, int sharetype)
66{
67	int  opt, error = 0;
68	uid_t euid;
69	const char *arg, *cp;
70	struct passwd *pwd;
71
72	bzero(ctx,sizeof(*ctx));
73	error = nb_ctx_create(&ctx->ct_nb);
74	if (error)
75		return error;
76	ctx->ct_fd = -1;
77	ctx->ct_parsedlevel = SMBL_NONE;
78	ctx->ct_minlevel = minlevel;
79	ctx->ct_maxlevel = maxlevel;
80	ctx->ct_smbtcpport = SMB_TCP_PORT;
81
82	ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE;
83	ctx->ct_ssn.ioc_timeout = 15;
84	ctx->ct_ssn.ioc_retrycount = 4;
85	ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER;
86	ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP;
87	ctx->ct_ssn.ioc_mode = SMBM_EXEC;
88	ctx->ct_ssn.ioc_rights = SMBM_DEFAULT;
89
90	ctx->ct_sh.ioc_opt = SMBVOPT_CREATE;
91	ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER;
92	ctx->ct_sh.ioc_group = SMBM_ANY_GROUP;
93	ctx->ct_sh.ioc_mode = SMBM_EXEC;
94	ctx->ct_sh.ioc_rights = SMBM_DEFAULT;
95	ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER;
96	ctx->ct_sh.ioc_group = SMBM_ANY_GROUP;
97
98	nb_ctx_setscope(ctx->ct_nb, "");
99	euid = geteuid();
100	if ((pwd = getpwuid(euid)) != NULL) {
101		smb_ctx_setuser(ctx, pwd->pw_name);
102		endpwent();
103	} else if (euid == 0)
104		smb_ctx_setuser(ctx, "root");
105	else
106		return 0;
107	if (argv == NULL)
108		return 0;
109	for (opt = 1; opt < argc; opt++) {
110		cp = argv[opt];
111		if (strncmp(cp, "//", 2) != 0)
112			continue;
113		error = smb_ctx_parseunc(ctx, cp, sharetype, (const char**)&cp);
114		if (error)
115			return error;
116		ctx->ct_uncnext = cp;
117		break;
118	}
119	while (error == 0 && (opt = cf_getopt(argc, argv, ":E:L:U:")) != -1) {
120		arg = cf_optarg;
121		switch (opt) {
122		    case 'E':
123			error = smb_ctx_setcharset(ctx, arg);
124			if (error)
125				return error;
126			break;
127		    case 'L':
128			error = nls_setlocale(arg);
129			if (error)
130				break;
131			break;
132		    case 'U':
133			error = smb_ctx_setuser(ctx, arg);
134			break;
135		}
136	}
137	cf_optind = cf_optreset = 1;
138	return error;
139}
140
141void
142smb_ctx_done(struct smb_ctx *ctx)
143{
144	if (ctx->ct_ssn.ioc_server)
145		nb_snbfree(ctx->ct_ssn.ioc_server);
146	if (ctx->ct_ssn.ioc_local)
147		nb_snbfree(ctx->ct_ssn.ioc_local);
148	if (ctx->ct_srvaddr)
149		free(ctx->ct_srvaddr);
150	if (ctx->ct_nb)
151		nb_ctx_done(ctx->ct_nb);
152}
153
154static int
155getsubstring(const char *p, u_char sep, char *dest, int maxlen, const char **next)
156{
157	int len;
158
159	maxlen--;
160	for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) {
161		if (*p == 0)
162			return EINVAL;
163		*dest = *p;
164	}
165	*dest = 0;
166	*next = *p ? p + 1 : p;
167	return 0;
168}
169
170/*
171 * Here we expect something like "[proto:]//[user@]host[:psmb[:pnb]][/share][/path]"
172 */
173int
174smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
175	const char **next)
176{
177	const char *p = unc;
178	char *p1, *psmb, *pnb;
179	char tmp[1024];
180	int error ;
181
182	ctx->ct_parsedlevel = SMBL_NONE;
183	if (*p++ != '/' || *p++ != '/') {
184		smb_error("UNC should start with '//'", 0);
185		return EINVAL;
186	}
187	p1 = tmp;
188	error = getsubstring(p, '@', p1, sizeof(tmp), &p);
189	if (!error) {
190		if (ctx->ct_maxlevel < SMBL_VC) {
191			smb_error("no user name required", 0);
192			return EINVAL;
193		}
194		error = smb_ctx_setuser(ctx, tmp);
195		if (error)
196			return error;
197		ctx->ct_parsedlevel = SMBL_VC;
198	}
199	error = getsubstring(p, '/', p1, sizeof(tmp), &p);
200	if (error) {
201		error = getsubstring(p, '\0', p1, sizeof(tmp), &p);
202		if (error) {
203			smb_error("no server name found", 0);
204			return error;
205		}
206	}
207	if (*p1 == 0) {
208		smb_error("empty server name", 0);
209		return EINVAL;
210	}
211	/*
212	 * Check for port number specification.
213	 */
214	psmb = strchr(tmp, ':');
215	if (psmb) {
216		*psmb++ = '\0';
217		pnb = strchr(psmb, ':');
218		if (pnb) {
219			*pnb++ = '\0';
220			error = smb_ctx_setnbport(ctx, atoi(pnb));
221			if (error) {
222				smb_error("Invalid NetBIOS port number", 0);
223				return error;
224			}
225		}
226		error = smb_ctx_setsmbport(ctx, atoi(psmb));
227		if (error) {
228			smb_error("Invalid SMB port number", 0);
229			return error;
230		}
231	}
232	error = smb_ctx_setserver(ctx, tmp);
233	if (error)
234		return error;
235	if (sharetype == SMB_ST_NONE) {
236		*next = p;
237		return 0;
238	}
239	if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
240		smb_error("no share name required", 0);
241		return EINVAL;
242	}
243	error = getsubstring(p, '/', p1, sizeof(tmp), &p);
244	if (error) {
245		error = getsubstring(p, '\0', p1, sizeof(tmp), &p);
246		if (error) {
247			smb_error("unexpected end of line", 0);
248			return error;
249		}
250	}
251	if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE) {
252		smb_error("empty share name", 0);
253		return EINVAL;
254	}
255	*next = p;
256	if (*p1 == 0)
257		return 0;
258	error = smb_ctx_setshare(ctx, p1, sharetype);
259	return error;
260}
261
262int
263smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
264{
265	char *cp, *servercs, *localcs;
266	int cslen = sizeof(ctx->ct_ssn.ioc_localcs);
267	int scslen, lcslen, error;
268
269	cp = strchr(arg, ':');
270	lcslen = cp ? (cp - arg) : 0;
271	if (lcslen == 0 || lcslen >= cslen) {
272		smb_error("invalid local charset specification (%s)", 0, arg);
273		return EINVAL;
274	}
275	scslen = (size_t)strlen(++cp);
276	if (scslen == 0 || scslen >= cslen) {
277		smb_error("invalid server charset specification (%s)", 0, arg);
278		return EINVAL;
279	}
280	localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen);
281	localcs[lcslen] = 0;
282	servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp);
283	error = nls_setrecode(localcs, servercs);
284	if (error == 0)
285		return 0;
286	smb_error("can't initialize iconv support (%s:%s)",
287	    error, localcs, servercs);
288	localcs[0] = 0;
289	servercs[0] = 0;
290	return error;
291}
292
293int
294smb_ctx_setserver(struct smb_ctx *ctx, const char *name)
295{
296	if (strlen(name) > SMB_MAXSRVNAMELEN) {
297		smb_error("server name '%s' too long", 0, name);
298		return ENAMETOOLONG;
299	}
300	nls_str_upper(ctx->ct_ssn.ioc_srvname, name);
301	return 0;
302}
303
304int
305smb_ctx_setnbport(struct smb_ctx *ctx, int port)
306{
307	if (port < 1 || port > 0xffff)
308		return EINVAL;
309	ctx->ct_nb->nb_nmbtcpport = port;
310	return 0;
311}
312
313int
314smb_ctx_setsmbport(struct smb_ctx *ctx, int port)
315{
316	if (port < 1 || port > 0xffff)
317		return EINVAL;
318	ctx->ct_smbtcpport = port;
319	ctx->ct_nb->nb_smbtcpport = port;
320	return 0;
321}
322
323int
324smb_ctx_setuser(struct smb_ctx *ctx, const char *name)
325{
326	if (strlen(name) > SMB_MAXUSERNAMELEN) {
327		smb_error("user name '%s' too long", 0, name);
328		return ENAMETOOLONG;
329	}
330	nls_str_upper(ctx->ct_ssn.ioc_user, name);
331	return 0;
332}
333
334int
335smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name)
336{
337	if (strlen(name) > SMB_MAXUSERNAMELEN) {
338		smb_error("workgroup name '%s' too long", 0, name);
339		return ENAMETOOLONG;
340	}
341	nls_str_upper(ctx->ct_ssn.ioc_workgroup, name);
342	return 0;
343}
344
345int
346smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd)
347{
348	if (passwd == NULL)
349		return EINVAL;
350	if (strlen(passwd) > SMB_MAXPASSWORDLEN) {
351		smb_error("password too long", 0);
352		return ENAMETOOLONG;
353	}
354	if (strncmp(passwd, "$$1", 3) == 0)
355		smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd);
356	else
357		strcpy(ctx->ct_ssn.ioc_password, passwd);
358	strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password);
359	return 0;
360}
361
362int
363smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
364{
365	if (strlen(share) > SMB_MAXSHARENAMELEN) {
366		smb_error("share name '%s' too long", 0, share);
367		return ENAMETOOLONG;
368	}
369	nls_str_upper(ctx->ct_sh.ioc_share, share);
370	if (share[0] != 0)
371		ctx->ct_parsedlevel = SMBL_SHARE;
372	ctx->ct_sh.ioc_stype = stype;
373	return 0;
374}
375
376int
377smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr)
378{
379	if (addr == NULL || addr[0] == 0)
380		return EINVAL;
381	if (ctx->ct_srvaddr)
382		free(ctx->ct_srvaddr);
383	if ((ctx->ct_srvaddr = strdup(addr)) == NULL)
384		return ENOMEM;
385	return 0;
386}
387
388static int
389smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
390{
391	struct group *gr;
392	struct passwd *pw;
393	char *cp;
394
395	cp = strchr(pair, ':');
396	if (cp) {
397		*cp++ = '\0';
398		if (*cp) {
399			gr = getgrnam(cp);
400			if (gr) {
401				*gid = gr->gr_gid;
402			} else
403				smb_error("Invalid group name %s, ignored",
404				    0, cp);
405		}
406	}
407	if (*pair) {
408		pw = getpwnam(pair);
409		if (pw) {
410			*uid = pw->pw_uid;
411		} else
412			smb_error("Invalid user name %s, ignored", 0, pair);
413	}
414	endpwent();
415	return 0;
416}
417
418int
419smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
420{
421	int error = 0;
422	char *p, *cp;
423
424	switch(opt) {
425	    case 'U':
426		break;
427	    case 'I':
428		error = smb_ctx_setsrvaddr(ctx, arg);
429		break;
430	    case 'M':
431		ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8);
432		if (*cp == '/') {
433			ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8);
434			ctx->ct_flags |= SMBCF_SRIGHTS;
435		}
436		break;
437	    case 'N':
438		ctx->ct_flags |= SMBCF_NOPWD;
439		break;
440	    case 'O':
441		p = strdup(arg);
442		cp = strchr(p, '/');
443		if (cp) {
444			*cp++ = '\0';
445			error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner,
446			    &ctx->ct_sh.ioc_group);
447		}
448		if (*p && error == 0) {
449			error = smb_parse_owner(p, &ctx->ct_ssn.ioc_owner,
450			    &ctx->ct_ssn.ioc_group);
451		}
452		free(p);
453		break;
454	    case 'P':
455/*		ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT;*/
456		break;
457	    case 'R':
458		ctx->ct_ssn.ioc_retrycount = atoi(arg);
459		break;
460	    case 'T':
461		ctx->ct_ssn.ioc_timeout = atoi(arg);
462		break;
463	    case 'W':
464		error = smb_ctx_setworkgroup(ctx, arg);
465		break;
466	}
467	return error;
468}
469
470#if 0
471static void
472smb_hexdump(const u_char *buf, int len) {
473	int ofs = 0;
474
475	while (len--) {
476		if (ofs % 16 == 0)
477			printf("\n%02X: ", ofs);
478		printf("%02x ", *buf++);
479		ofs++;
480	}
481	printf("\n");
482}
483#endif
484
485
486static int
487smb_addiconvtbl(const char *to, const char *from, const u_char *tbl)
488{
489	int error;
490
491	error = kiconv_add_xlat_table(to, from, tbl);
492	if (error && error != EEXIST) {
493		smb_error("can not setup kernel iconv table (%s:%s)", error,
494		    from, to);
495		return error;
496	}
497	return 0;
498}
499
500/*
501 * Verify context before connect operation(s),
502 * lookup specified server and try to fill all forgotten fields.
503 */
504int
505smb_ctx_resolve(struct smb_ctx *ctx)
506{
507	struct smbioc_ossn *ssn = &ctx->ct_ssn;
508	struct smbioc_oshare *sh = &ctx->ct_sh;
509	struct nb_name nn;
510	struct sockaddr *sap;
511	struct sockaddr_nb *salocal, *saserver;
512	char *cp;
513	int error = 0;
514
515	ctx->ct_flags &= ~SMBCF_RESOLVED;
516	if (ssn->ioc_srvname[0] == 0) {
517		smb_error("no server name specified", 0);
518		return EINVAL;
519	}
520	if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0) {
521		smb_error("no share name specified for %s@%s",
522		    0, ssn->ioc_user, ssn->ioc_srvname);
523		return EINVAL;
524	}
525	error = nb_ctx_resolve(ctx->ct_nb);
526	if (error)
527		return error;
528	if (ssn->ioc_localcs[0] == 0)
529		strcpy(ssn->ioc_localcs, "ISO8859-1");
530	error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
531	if (error)
532		return error;
533	error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
534	if (error)
535		return error;
536	if (ssn->ioc_servercs[0] != 0) {
537		error = kiconv_add_xlat16_cspairs
538			(ssn->ioc_servercs, ssn->ioc_localcs);
539		if (error) return error;
540	}
541	if (ctx->ct_srvaddr) {
542		error = nb_resolvehost_in(ctx->ct_srvaddr, &sap, ctx->ct_smbtcpport);
543	} else {
544		error = nbns_resolvename(ssn->ioc_srvname, ctx->ct_nb, &sap);
545	}
546	if (error) {
547		smb_error("can't get server address", error);
548		return error;
549	}
550	nn.nn_scope = ctx->ct_nb->nb_scope;
551	nn.nn_type = NBT_SERVER;
552	strcpy(nn.nn_name, ssn->ioc_srvname);
553	error = nb_sockaddr(sap, &nn, &saserver);
554	nb_snbfree(sap);
555	if (error) {
556		smb_error("can't allocate server address", error);
557		return error;
558	}
559	ssn->ioc_server = (struct sockaddr*)saserver;
560	if (ctx->ct_locname[0] == 0) {
561		error = nb_getlocalname(ctx->ct_locname);
562		if (error) {
563			smb_error("can't get local name", error);
564			return error;
565		}
566		nls_str_upper(ctx->ct_locname, ctx->ct_locname);
567	}
568	strcpy(nn.nn_name, ctx->ct_locname);
569	nn.nn_type = NBT_WKSTA;
570	nn.nn_scope = ctx->ct_nb->nb_scope;
571	error = nb_sockaddr(NULL, &nn, &salocal);
572	if (error) {
573		nb_snbfree((struct sockaddr*)saserver);
574		smb_error("can't allocate local address", error);
575		return error;
576	}
577	ssn->ioc_local = (struct sockaddr*)salocal;
578	ssn->ioc_lolen = salocal->snb_len;
579	ssn->ioc_svlen = saserver->snb_len;
580	if (ssn->ioc_password[0] == 0 && (ctx->ct_flags & SMBCF_NOPWD) == 0) {
581		cp = getpass("Password:");
582		error = smb_ctx_setpassword(ctx, cp);
583		if (error)
584			return error;
585	}
586	ctx->ct_flags |= SMBCF_RESOLVED;
587	return 0;
588}
589
590static int
591smb_ctx_gethandle(struct smb_ctx *ctx)
592{
593	int fd, i;
594	char buf[20];
595
596	fd = open("/dev/"NSMB_NAME, O_RDWR);
597	if (fd >= 0) {
598		ctx->ct_fd = fd;
599		return 0;
600	}
601	return ENOENT;
602}
603
604int
605smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags)
606{
607	struct smbioc_lookup rq;
608	int error;
609
610	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
611		smb_error("smb_ctx_lookup() data is not resolved", 0);
612		return EINVAL;
613	}
614	if (ctx->ct_fd != -1) {
615		close(ctx->ct_fd);
616		ctx->ct_fd = -1;
617	}
618	error = smb_ctx_gethandle(ctx);
619	if (error) {
620		smb_error("can't get handle to requester (no /dev/"NSMB_NAME"* device)", 0);
621		return EINVAL;
622	}
623	bzero(&rq, sizeof(rq));
624	bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof(struct smbioc_ossn));
625	bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof(struct smbioc_oshare));
626	rq.ioc_flags = flags;
627	rq.ioc_level = level;
628	if (ioctl(ctx->ct_fd, SMBIOC_LOOKUP, &rq) == -1) {
629		error = errno;
630		if (flags & SMBLK_CREATE)
631			smb_error("unable to open connection", error);
632		return error;
633	}
634	return 0;
635}
636
637int
638smb_ctx_login(struct smb_ctx *ctx)
639{
640	struct smbioc_ossn *ssn = &ctx->ct_ssn;
641	struct smbioc_oshare *sh = &ctx->ct_sh;
642	int error;
643
644	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
645		smb_error("smb_ctx_resolve() should be called first", 0);
646		return EINVAL;
647	}
648	if (ctx->ct_fd != -1) {
649		close(ctx->ct_fd);
650		ctx->ct_fd = -1;
651	}
652	error = smb_ctx_gethandle(ctx);
653	if (error) {
654		smb_error("can't get handle to requester", 0);
655		return EINVAL;
656	}
657	if (ioctl(ctx->ct_fd, SMBIOC_OPENSESSION, ssn) == -1) {
658		error = errno;
659		smb_error("can't open session to server %s", error, ssn->ioc_srvname);
660		return error;
661	}
662	if (sh->ioc_share[0] == 0)
663		return 0;
664	if (ioctl(ctx->ct_fd, SMBIOC_OPENSHARE, sh) == -1) {
665		error = errno;
666		smb_error("can't connect to share //%s/%s", error,
667		    ssn->ioc_srvname, sh->ioc_share);
668		return error;
669	}
670	return 0;
671}
672
673int
674smb_ctx_setflags(struct smb_ctx *ctx, int level, int mask, int flags)
675{
676	struct smbioc_flags fl;
677
678	if (ctx->ct_fd == -1)
679		return EINVAL;
680	fl.ioc_level = level;
681	fl.ioc_mask = mask;
682	fl.ioc_flags = flags;
683	if (ioctl(ctx->ct_fd, SMBIOC_SETFLAGS, &fl) == -1)
684		return errno;
685	return 0;
686}
687
688/*
689 * level values:
690 * 0 - default
691 * 1 - server
692 * 2 - server:user
693 * 3 - server:user:share
694 */
695static int
696smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
697{
698	char *p;
699	int error;
700
701	if (level >= 0) {
702		rc_getstringptr(smb_rc, sname, "charsets", &p);
703		if (p) {
704			error = smb_ctx_setcharset(ctx, p);
705			if (error)
706				smb_error("charset specification in the section '%s' ignored", error, sname);
707		}
708	}
709	if (level <= 1) {
710		rc_getint(smb_rc, sname, "timeout", &ctx->ct_ssn.ioc_timeout);
711		rc_getint(smb_rc, sname, "retry_count", &ctx->ct_ssn.ioc_retrycount);
712	}
713	if (level == 1) {
714		rc_getstringptr(smb_rc, sname, "addr", &p);
715		if (p) {
716			error = smb_ctx_setsrvaddr(ctx, p);
717			if (error) {
718				smb_error("invalid address specified in the section %s", 0, sname);
719				return error;
720			}
721		}
722	}
723	if (level >= 2) {
724		rc_getstringptr(smb_rc, sname, "password", &p);
725		if (p)
726			smb_ctx_setpassword(ctx, p);
727	}
728	rc_getstringptr(smb_rc, sname, "workgroup", &p);
729	if (p)
730		smb_ctx_setworkgroup(ctx, p);
731	return 0;
732}
733
734/*
735 * read rc file as follows:
736 * 1. read [default] section
737 * 2. override with [server] section
738 * 3. override with [server:user:share] section
739 * Since abcence of rcfile is not fatal, silently ignore this fact.
740 * smb_rc file should be closed by caller.
741 */
742int
743smb_ctx_readrc(struct smb_ctx *ctx)
744{
745	char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN + SMB_MAXSHARENAMELEN + 4];
746/*	char *p;*/
747
748	if (smb_open_rcfile() != 0)
749		return 0;
750
751	if (ctx->ct_ssn.ioc_user[0] == 0 || ctx->ct_ssn.ioc_srvname[0] == 0)
752		return 0;
753
754	smb_ctx_readrcsection(ctx, "default", 0);
755	nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
756	smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1);
757	nb_ctx_readrcsection(smb_rc, ctx->ct_nb, ctx->ct_ssn.ioc_srvname, 1);
758	/*
759	 * SERVER:USER parameters
760	 */
761	snprintf(sname, sizeof(sname), "%s:%s", ctx->ct_ssn.ioc_srvname,
762	    ctx->ct_ssn.ioc_user);
763	smb_ctx_readrcsection(ctx, sname, 2);
764
765	if (ctx->ct_sh.ioc_share[0] != 0) {
766		/*
767		 * SERVER:USER:SHARE parameters
768	         */
769		snprintf(sname, sizeof(sname), "%s:%s:%s", ctx->ct_ssn.ioc_srvname,
770		    ctx->ct_ssn.ioc_user, ctx->ct_sh.ioc_share);
771		smb_ctx_readrcsection(ctx, sname, 3);
772	}
773	return 0;
774}
775
776