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