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