ctx.c revision 118079
1219131Srwatson/*
2219131Srwatson * Copyright (c) 2000-2002, Boris Popov
3219131Srwatson * All rights reserved.
4219131Srwatson *
5219131Srwatson * Redistribution and use in source and binary forms, with or without
6219131Srwatson * modification, are permitted provided that the following conditions
7219131Srwatson * are met:
8219131Srwatson * 1. Redistributions of source code must retain the above copyright
9219131Srwatson *    notice, this list of conditions and the following disclaimer.
10219131Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11219131Srwatson *    notice, this list of conditions and the following disclaimer in the
12219131Srwatson *    documentation and/or other materials provided with the distribution.
13219131Srwatson * 3. All advertising materials mentioning features or use of this software
14219131Srwatson *    must display the following acknowledgement:
15219131Srwatson *    This product includes software developed by Boris Popov.
16219131Srwatson * 4. Neither the name of the author nor the names of any co-contributors
17219131Srwatson *    may be used to endorse or promote products derived from this software
18219131Srwatson *    without specific prior written permission.
19219131Srwatson *
20219131Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21219131Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22219131Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23219131Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24219131Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25219131Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26219131Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27219131Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28219131Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29219131Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30219131Srwatson * SUCH DAMAGE.
31219131Srwatson *
32219131Srwatson * $Id: ctx.c,v 1.24 2002/04/13 14:35:28 bp Exp $
33219131Srwatson * $FreeBSD: head/contrib/smbfs/lib/smb/ctx.c 118079 2003-07-27 11:41:38Z tjr $
34219131Srwatson */
35219131Srwatson#include <sys/param.h>
36219131Srwatson#include <sys/sysctl.h>
37219131Srwatson#include <sys/ioctl.h>
38219131Srwatson#include <sys/time.h>
39219131Srwatson#include <sys/mount.h>
40219131Srwatson#include <fcntl.h>
41219131Srwatson#include <ctype.h>
42219131Srwatson#include <errno.h>
43219131Srwatson#include <stdio.h>
44219131Srwatson#include <string.h>
45219131Srwatson#include <stdlib.h>
46219131Srwatson#include <pwd.h>
47219131Srwatson#include <grp.h>
48219131Srwatson#include <unistd.h>
49219131Srwatson#include <sys/iconv.h>
50219131Srwatson
51219131Srwatson#define NB_NEEDRESOLVER
52219131Srwatson
53219131Srwatson#include <netsmb/smb_lib.h>
54219131Srwatson#include <netsmb/netbios.h>
55219131Srwatson#include <netsmb/nb_lib.h>
56219131Srwatson#include <netsmb/smb_conn.h>
57219131Srwatson#include <cflib.h>
58219131Srwatson
59219131Srwatson/*
60219131Srwatson * Prescan command line for [-U user] argument
61219131Srwatson * and fill context with defaults
62219131Srwatson */
63219131Srwatsonint
64219131Srwatsonsmb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[],
65219131Srwatson	int minlevel, int maxlevel, int sharetype)
66219131Srwatson{
67219131Srwatson	int  opt, error = 0;
68219131Srwatson	uid_t euid;
69219131Srwatson	const char *arg, *cp;
70219131Srwatson	struct passwd *pwd;
71219131Srwatson
72219131Srwatson	bzero(ctx,sizeof(*ctx));
73219131Srwatson	error = nb_ctx_create(&ctx->ct_nb);
74219131Srwatson	if (error)
75219131Srwatson		return error;
76219131Srwatson	ctx->ct_fd = -1;
77219131Srwatson	ctx->ct_parsedlevel = SMBL_NONE;
78219131Srwatson	ctx->ct_minlevel = minlevel;
79250154Sjilles	ctx->ct_maxlevel = maxlevel;
80219131Srwatson
81219131Srwatson	ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE;
82219131Srwatson	ctx->ct_ssn.ioc_timeout = 15;
83219131Srwatson	ctx->ct_ssn.ioc_retrycount = 4;
84219131Srwatson	ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER;
85219131Srwatson	ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP;
86219131Srwatson	ctx->ct_ssn.ioc_mode = SMBM_EXEC;
87219131Srwatson	ctx->ct_ssn.ioc_rights = SMBM_DEFAULT;
88219131Srwatson
89219131Srwatson	ctx->ct_sh.ioc_opt = SMBVOPT_CREATE;
90219131Srwatson	ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER;
91219131Srwatson	ctx->ct_sh.ioc_group = SMBM_ANY_GROUP;
92219131Srwatson	ctx->ct_sh.ioc_mode = SMBM_EXEC;
93219131Srwatson	ctx->ct_sh.ioc_rights = SMBM_DEFAULT;
94219131Srwatson	ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER;
95219131Srwatson	ctx->ct_sh.ioc_group = SMBM_ANY_GROUP;
96219131Srwatson
97219131Srwatson	nb_ctx_setscope(ctx->ct_nb, "");
98219131Srwatson	euid = geteuid();
99219131Srwatson	if ((pwd = getpwuid(euid)) != NULL) {
100219131Srwatson		smb_ctx_setuser(ctx, pwd->pw_name);
101219131Srwatson		endpwent();
102247667Spjd	} else if (euid == 0)
103219131Srwatson		smb_ctx_setuser(ctx, "root");
104247667Spjd	else
105219131Srwatson		return 0;
106219131Srwatson	if (argv == NULL)
107219131Srwatson		return 0;
108219131Srwatson	for (opt = 1; opt < argc; opt++) {
109219131Srwatson		cp = argv[opt];
110247602Spjd		if (strncmp(cp, "//", 2) != 0)
111247602Spjd			continue;
112219131Srwatson		error = smb_ctx_parseunc(ctx, cp, sharetype, (const char**)&cp);
113247602Spjd		if (error)
114247602Spjd			return error;
115255219Spjd		ctx->ct_uncnext = cp;
116247602Spjd		break;
117219131Srwatson	}
118219131Srwatson	while (error == 0 && (opt = cf_getopt(argc, argv, ":E:L:U:")) != -1) {
119219131Srwatson		arg = cf_optarg;
120219131Srwatson		switch (opt) {
121255374Spjd		    case 'E':
122219131Srwatson			error = smb_ctx_setcharset(ctx, arg);
123219131Srwatson			if (error)
124219131Srwatson				return error;
125219131Srwatson			break;
126219131Srwatson		    case 'L':
127219131Srwatson			error = nls_setlocale(optarg);
128219131Srwatson			if (error)
129219131Srwatson				break;
130219131Srwatson			break;
131247667Spjd		    case 'U':
132219131Srwatson			error = smb_ctx_setuser(ctx, arg);
133247667Spjd			break;
134219131Srwatson		}
135219131Srwatson	}
136319819Sallanjude	cf_optind = cf_optreset = 1;
137219131Srwatson	return error;
138219131Srwatson}
139319819Sallanjude
140219131Srwatsonvoid
141319819Sallanjudesmb_ctx_done(struct smb_ctx *ctx)
142219131Srwatson{
143219131Srwatson	if (ctx->ct_ssn.ioc_server)
144219131Srwatson		nb_snbfree(ctx->ct_ssn.ioc_server);
145219131Srwatson	if (ctx->ct_ssn.ioc_local)
146219131Srwatson		nb_snbfree(ctx->ct_ssn.ioc_local);
147219131Srwatson	if (ctx->ct_srvaddr)
148219131Srwatson		free(ctx->ct_srvaddr);
149219131Srwatson	if (ctx->ct_nb)
150219131Srwatson		nb_ctx_done(ctx->ct_nb);
151219131Srwatson}
152219131Srwatson
153219131Srwatsonstatic int
154219131Srwatsongetsubstring(const char *p, u_char sep, char *dest, int maxlen, const char **next)
155219131Srwatson{
156219131Srwatson	int len;
157219131Srwatson
158219131Srwatson	maxlen--;
159219131Srwatson	for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) {
160219131Srwatson		if (*p == 0)
161219131Srwatson			return EINVAL;
162219131Srwatson		*dest = *p;
163219131Srwatson	}
164219131Srwatson	*dest = 0;
165219131Srwatson	*next = *p ? p + 1 : p;
166219131Srwatson	return 0;
167219131Srwatson}
168219131Srwatson
169219131Srwatson/*
170219131Srwatson * Here we expect something like "[proto:]//[user@]host[/share][/path]"
171219131Srwatson */
172219131Srwatsonint
173219131Srwatsonsmb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
174219131Srwatson	const char **next)
175219131Srwatson{
176219131Srwatson	const char *p = unc;
177219131Srwatson	char *p1;
178219131Srwatson	char tmp[1024];
179219131Srwatson	int error ;
180219131Srwatson
181219131Srwatson	ctx->ct_parsedlevel = SMBL_NONE;
182219131Srwatson	if (*p++ != '/' || *p++ != '/') {
183219131Srwatson		smb_error("UNC should start with '//'", 0);
184219131Srwatson		return EINVAL;
185219131Srwatson	}
186219131Srwatson	p1 = tmp;
187219131Srwatson	error = getsubstring(p, '@', p1, sizeof(tmp), &p);
188219131Srwatson	if (!error) {
189219131Srwatson		if (ctx->ct_maxlevel < SMBL_VC) {
190219131Srwatson			smb_error("no user name required", 0);
191219131Srwatson			return EINVAL;
192219131Srwatson		}
193219131Srwatson		if (*p1 == 0) {
194219131Srwatson			smb_error("empty user name", 0);
195219131Srwatson			return EINVAL;
196219131Srwatson		}
197224852Srwatson		error = smb_ctx_setuser(ctx, tmp);
198219131Srwatson		if (error)
199219131Srwatson			return error;
200219131Srwatson		ctx->ct_parsedlevel = SMBL_VC;
201219131Srwatson	}
202219131Srwatson	error = getsubstring(p, '/', p1, sizeof(tmp), &p);
203219131Srwatson	if (error) {
204219131Srwatson		error = getsubstring(p, '\0', p1, sizeof(tmp), &p);
205219131Srwatson		if (error) {
206219131Srwatson			smb_error("no server name found", 0);
207219131Srwatson			return error;
208219131Srwatson		}
209219131Srwatson	}
210219131Srwatson	if (*p1 == 0) {
211219131Srwatson		smb_error("empty server name", 0);
212219131Srwatson		return EINVAL;
213219131Srwatson	}
214219131Srwatson	error = smb_ctx_setserver(ctx, tmp);
215219131Srwatson	if (error)
216219131Srwatson		return error;
217219131Srwatson	if (sharetype == SMB_ST_NONE) {
218219131Srwatson		*next = p;
219219131Srwatson		return 0;
220277610Sjilles	}
221219131Srwatson	if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
222277610Sjilles		smb_error("no share name required", 0);
223219131Srwatson		return EINVAL;
224219131Srwatson	}
225219131Srwatson	error = getsubstring(p, '/', p1, sizeof(tmp), &p);
226219131Srwatson	if (error) {
227219131Srwatson		error = getsubstring(p, '\0', p1, sizeof(tmp), &p);
228219131Srwatson		if (error) {
229219131Srwatson			smb_error("unexpected end of line", 0);
230219131Srwatson			return error;
231219131Srwatson		}
232219131Srwatson	}
233219131Srwatson	if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE) {
234219131Srwatson		smb_error("empty share name", 0);
235219131Srwatson		return EINVAL;
236219131Srwatson	}
237219131Srwatson	*next = p;
238219131Srwatson	if (*p1 == 0)
239219131Srwatson		return 0;
240219131Srwatson	error = smb_ctx_setshare(ctx, p1, sharetype);
241247602Spjd	return error;
242219131Srwatson}
243219131Srwatson
244219131Srwatsonint
245219131Srwatsonsmb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
246219131Srwatson{
247219131Srwatson	char *cp, *servercs, *localcs;
248219131Srwatson	int cslen = sizeof(ctx->ct_ssn.ioc_localcs);
249219131Srwatson	int scslen, lcslen, error;
250305514Semaste
251219131Srwatson	cp = strchr(arg, ':');
252219131Srwatson	lcslen = cp ? (cp - arg) : 0;
253219131Srwatson	if (lcslen == 0 || lcslen >= cslen) {
254219131Srwatson		smb_error("invalid local charset specification (%s)", 0, arg);
255219131Srwatson		return EINVAL;
256219131Srwatson	}
257219131Srwatson	scslen = (size_t)strlen(++cp);
258219131Srwatson	if (scslen == 0 || scslen >= cslen) {
259219131Srwatson		smb_error("invalid server charset specification (%s)", 0, arg);
260219131Srwatson		return EINVAL;
261219131Srwatson	}
262219131Srwatson	localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen);
263219131Srwatson	localcs[lcslen] = 0;
264219131Srwatson	servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp);
265219131Srwatson	error = nls_setrecode(localcs, servercs);
266219131Srwatson	if (error == 0)
267219131Srwatson		return 0;
268219131Srwatson	smb_error("can't initialize iconv support (%s:%s)",
269219131Srwatson	    error, localcs, servercs);
270219131Srwatson	localcs[0] = 0;
271219131Srwatson	servercs[0] = 0;
272219131Srwatson	return error;
273219131Srwatson}
274219131Srwatson
275219131Srwatsonint
276219131Srwatsonsmb_ctx_setserver(struct smb_ctx *ctx, const char *name)
277219131Srwatson{
278219131Srwatson	if (strlen(name) > SMB_MAXSRVNAMELEN) {
279219131Srwatson		smb_error("server name '%s' too long", 0, name);
280219131Srwatson		return ENAMETOOLONG;
281219131Srwatson	}
282219131Srwatson	nls_str_upper(ctx->ct_ssn.ioc_srvname, name);
283219131Srwatson	return 0;
284219131Srwatson}
285219131Srwatson
286219131Srwatsonint
287219131Srwatsonsmb_ctx_setuser(struct smb_ctx *ctx, const char *name)
288219131Srwatson{
289219131Srwatson	if (strlen(name) > SMB_MAXUSERNAMELEN) {
290219131Srwatson		smb_error("user name '%s' too long", 0, name);
291219131Srwatson		return ENAMETOOLONG;
292219131Srwatson	}
293219131Srwatson	nls_str_upper(ctx->ct_ssn.ioc_user, name);
294219131Srwatson	return 0;
295219131Srwatson}
296219131Srwatson
297219131Srwatsonint
298219131Srwatsonsmb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name)
299219131Srwatson{
300219131Srwatson	if (strlen(name) > SMB_MAXUSERNAMELEN) {
301219131Srwatson		smb_error("workgroup name '%s' too long", 0, name);
302219131Srwatson		return ENAMETOOLONG;
303219131Srwatson	}
304219131Srwatson	nls_str_upper(ctx->ct_ssn.ioc_workgroup, name);
305219131Srwatson	return 0;
306219131Srwatson}
307219131Srwatson
308219131Srwatsonint
309219131Srwatsonsmb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd)
310219131Srwatson{
311219131Srwatson	if (passwd == NULL)
312219131Srwatson		return EINVAL;
313219131Srwatson	if (strlen(passwd) > SMB_MAXPASSWORDLEN) {
314219131Srwatson		smb_error("password too long", 0);
315219131Srwatson		return ENAMETOOLONG;
316219131Srwatson	}
317219131Srwatson	if (strncmp(passwd, "$$1", 3) == 0)
318219131Srwatson		smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd);
319219131Srwatson	else
320247602Spjd		strcpy(ctx->ct_ssn.ioc_password, passwd);
321247602Spjd	strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password);
322219131Srwatson	return 0;
323247602Spjd}
324219131Srwatson
325219131Srwatsonint
326219131Srwatsonsmb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
327219131Srwatson{
328219131Srwatson	if (strlen(share) > SMB_MAXSHARENAMELEN) {
329219131Srwatson		smb_error("share name '%s' too long", 0, share);
330219131Srwatson		return ENAMETOOLONG;
331219131Srwatson	}
332219131Srwatson	nls_str_upper(ctx->ct_sh.ioc_share, share);
333219131Srwatson	if (share[0] != 0)
334219131Srwatson		ctx->ct_parsedlevel = SMBL_SHARE;
335219131Srwatson	ctx->ct_sh.ioc_stype = stype;
336219131Srwatson	return 0;
337243610Spjd}
338243610Spjd
339243610Spjdint
340243610Spjdsmb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr)
341243610Spjd{
342219131Srwatson	if (addr == NULL || addr[0] == 0)
343219131Srwatson		return EINVAL;
344321322Skib	if (ctx->ct_srvaddr)
345321322Skib		free(ctx->ct_srvaddr);
346219131Srwatson	if ((ctx->ct_srvaddr = strdup(addr)) == NULL)
347219131Srwatson		return ENOMEM;
348219131Srwatson	return 0;
349219131Srwatson}
350219131Srwatson
351219131Srwatsonstatic int
352219131Srwatsonsmb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
353219131Srwatson{
354219131Srwatson	struct group *gr;
355219131Srwatson	struct passwd *pw;
356219131Srwatson	char *cp;
357219131Srwatson
358219131Srwatson	cp = strchr(pair, ':');
359219131Srwatson	if (cp) {
360219131Srwatson		*cp++ = '\0';
361219131Srwatson		if (*cp) {
362219131Srwatson			gr = getgrnam(cp);
363219131Srwatson			if (gr) {
364219131Srwatson				*gid = gr->gr_gid;
365219131Srwatson			} else
366219131Srwatson				smb_error("Invalid group name %s, ignored",
367219131Srwatson				    0, cp);
368219131Srwatson		}
369219131Srwatson	}
370219131Srwatson	if (*pair) {
371219131Srwatson		pw = getpwnam(pair);
372219131Srwatson		if (pw) {
373219131Srwatson			*uid = pw->pw_uid;
374219131Srwatson		} else
375219131Srwatson			smb_error("Invalid user name %s, ignored", 0, pair);
376219131Srwatson	}
377219131Srwatson	endpwent();
378219131Srwatson	return 0;
379219131Srwatson}
380219131Srwatson
381219131Srwatsonint
382219131Srwatsonsmb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
383219131Srwatson{
384219131Srwatson	int error = 0;
385219131Srwatson	char *p, *cp;
386219131Srwatson
387219131Srwatson	switch(opt) {
388219131Srwatson	    case 'U':
389219131Srwatson		break;
390219131Srwatson	    case 'I':
391219131Srwatson		error = smb_ctx_setsrvaddr(ctx, arg);
392219131Srwatson		break;
393219131Srwatson	    case 'M':
394219131Srwatson		ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8);
395219131Srwatson		if (*cp == '/') {
396219131Srwatson			ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8);
397219131Srwatson			ctx->ct_flags |= SMBCF_SRIGHTS;
398219131Srwatson		}
399219131Srwatson		break;
400219131Srwatson	    case 'N':
401219131Srwatson		ctx->ct_flags |= SMBCF_NOPWD;
402219131Srwatson		break;
403219131Srwatson	    case 'O':
404219131Srwatson		p = strdup(arg);
405219131Srwatson		cp = strchr(p, '/');
406219131Srwatson		if (cp) {
407219131Srwatson			*cp++ = '\0';
408219131Srwatson			error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner,
409219131Srwatson			    &ctx->ct_sh.ioc_group);
410219131Srwatson		}
411219131Srwatson		if (*p && error == 0) {
412219131Srwatson			error = smb_parse_owner(p, &ctx->ct_ssn.ioc_owner,
413219131Srwatson			    &ctx->ct_ssn.ioc_group);
414219131Srwatson		}
415219131Srwatson		free(p);
416219131Srwatson		break;
417219131Srwatson	    case 'P':
418219131Srwatson/*		ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT;*/
419219131Srwatson		break;
420219131Srwatson	    case 'R':
421219131Srwatson		ctx->ct_ssn.ioc_retrycount = atoi(arg);
422219131Srwatson		break;
423219131Srwatson	    case 'T':
424219131Srwatson		ctx->ct_ssn.ioc_timeout = atoi(arg);
425219131Srwatson		break;
426219131Srwatson	    case 'W':
427219131Srwatson		error = smb_ctx_setworkgroup(ctx, arg);
428219131Srwatson		break;
429219131Srwatson	}
430219131Srwatson	return error;
431219131Srwatson}
432219131Srwatson
433219131Srwatson#if 0
434219131Srwatsonstatic void
435219131Srwatsonsmb_hexdump(const u_char *buf, int len) {
436219131Srwatson	int ofs = 0;
437219131Srwatson
438219131Srwatson	while (len--) {
439219131Srwatson		if (ofs % 16 == 0)
440224812Sjonathan			printf("\n%02X: ", ofs);
441219131Srwatson		printf("%02x ", *buf++);
442248599Spjd		ofs++;
443224812Sjonathan	}
444224812Sjonathan	printf("\n");
445236361Spjd}
446248359Spjd#endif
447224812Sjonathan
448236361Spjd
449224812Sjonathanstatic int
450224812Sjonathansmb_addiconvtbl(const char *to, const char *from, const u_char *tbl)
451224812Sjonathan{
452224812Sjonathan	int error;
453236361Spjd
454224812Sjonathan	error = kiconv_add_xlat_table(to, from, tbl);
455236361Spjd	if (error && error != EEXIST) {
456236361Spjd		smb_error("can not setup kernel iconv table (%s:%s)", error,
457277610Sjilles		    from, to);
458219131Srwatson		return error;
459219131Srwatson	}
460224812Sjonathan	return 0;
461224812Sjonathan}
462224812Sjonathan
463224812Sjonathan/*
464219131Srwatson * Verify context before connect operation(s),
465224812Sjonathan * lookup specified server and try to fill all forgotten fields.
466219131Srwatson */
467219131Srwatsonint
468219131Srwatsonsmb_ctx_resolve(struct smb_ctx *ctx)
469219131Srwatson{
470219131Srwatson	struct smbioc_ossn *ssn = &ctx->ct_ssn;
471219131Srwatson	struct smbioc_oshare *sh = &ctx->ct_sh;
472219131Srwatson	struct nb_name nn;
473219131Srwatson	struct sockaddr *sap;
474219131Srwatson	struct sockaddr_nb *salocal, *saserver;
475219131Srwatson	char *cp;
476219131Srwatson	u_char cstbl[256];
477219131Srwatson	u_int i;
478219131Srwatson	int error = 0;
479219131Srwatson
480219131Srwatson	ctx->ct_flags &= ~SMBCF_RESOLVED;
481224987Sjonathan	if (ssn->ioc_srvname[0] == 0) {
482219131Srwatson		smb_error("no server name specified", 0);
483219131Srwatson		return EINVAL;
484219131Srwatson	}
485219131Srwatson	if (ssn->ioc_user[0] == 0) {
486219131Srwatson		smb_error("no user name specified for server %s",
487250159Sjilles		    0, ssn->ioc_srvname);
488219131Srwatson		return EINVAL;
489219131Srwatson	}
490219131Srwatson	if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0) {
491219131Srwatson		smb_error("no share name specified for %s@%s",
492219131Srwatson		    0, ssn->ioc_user, ssn->ioc_srvname);
493219131Srwatson		return EINVAL;
494219131Srwatson	}
495219131Srwatson	error = nb_ctx_resolve(ctx->ct_nb);
496219131Srwatson	if (error)
497219131Srwatson		return error;
498331679Semaste	if (ssn->ioc_localcs[0] == 0)
499219131Srwatson		strcpy(ssn->ioc_localcs, "default");	/* XXX: locale name ? */
500219131Srwatson	error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
501219131Srwatson	if (error)
502219131Srwatson		return error;
503219131Srwatson	error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
504219131Srwatson	if (error)
505219131Srwatson		return error;
506219131Srwatson	if (ssn->ioc_servercs[0] != 0) {
507219131Srwatson		for(i = 0; i < sizeof(cstbl); i++)
508219131Srwatson			cstbl[i] = i;
509219131Srwatson		nls_mem_toext(cstbl, cstbl, sizeof(cstbl));
510219131Srwatson		error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs, cstbl);
511219131Srwatson		if (error)
512219131Srwatson			return error;
513219131Srwatson		for(i = 0; i < sizeof(cstbl); i++)
514219131Srwatson			cstbl[i] = i;
515219131Srwatson		nls_mem_toloc(cstbl, cstbl, sizeof(cstbl));
516219131Srwatson		error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs, cstbl);
517219131Srwatson		if (error)
518219131Srwatson			return error;
519219131Srwatson	}
520219131Srwatson	if (ctx->ct_srvaddr) {
521219131Srwatson		error = nb_resolvehost_in(ctx->ct_srvaddr, &sap);
522219131Srwatson	} else {
523219131Srwatson		error = nbns_resolvename(ssn->ioc_srvname, ctx->ct_nb, &sap);
524219131Srwatson	}
525219131Srwatson	if (error) {
526219131Srwatson		smb_error("can't get server address", error);
527219131Srwatson		return error;
528219131Srwatson	}
529219131Srwatson	nn.nn_scope = ctx->ct_nb->nb_scope;
530219131Srwatson	nn.nn_type = NBT_SERVER;
531219131Srwatson	strcpy(nn.nn_name, ssn->ioc_srvname);
532219131Srwatson	error = nb_sockaddr(sap, &nn, &saserver);
533219131Srwatson	nb_snbfree(sap);
534219131Srwatson	if (error) {
535219131Srwatson		smb_error("can't allocate server address", error);
536219131Srwatson		return error;
537219131Srwatson	}
538219131Srwatson	ssn->ioc_server = (struct sockaddr*)saserver;
539219131Srwatson	if (ctx->ct_locname[0] == 0) {
540219131Srwatson		error = nb_getlocalname(ctx->ct_locname);
541219131Srwatson		if (error) {
542219131Srwatson			smb_error("can't get local name", error);
543219131Srwatson			return error;
544219131Srwatson		}
545219131Srwatson		nls_str_upper(ctx->ct_locname, ctx->ct_locname);
546219131Srwatson	}
547219131Srwatson	strcpy(nn.nn_name, ctx->ct_locname);
548219131Srwatson	nn.nn_type = NBT_WKSTA;
549219131Srwatson	nn.nn_scope = ctx->ct_nb->nb_scope;
550219131Srwatson	error = nb_sockaddr(NULL, &nn, &salocal);
551257736Spjd	if (error) {
552219131Srwatson		nb_snbfree((struct sockaddr*)saserver);
553219131Srwatson		smb_error("can't allocate local address", error);
554219131Srwatson		return error;
555219131Srwatson	}
556219131Srwatson	ssn->ioc_local = (struct sockaddr*)salocal;
557219131Srwatson	ssn->ioc_lolen = salocal->snb_len;
558321322Skib	ssn->ioc_svlen = saserver->snb_len;
559321322Skib	if (ssn->ioc_password[0] == 0 && (ctx->ct_flags & SMBCF_NOPWD) == 0) {
560219131Srwatson		cp = getpass("Password:");
561219131Srwatson		error = smb_ctx_setpassword(ctx, cp);
562219131Srwatson		if (error)
563219131Srwatson			return error;
564219131Srwatson	}
565219131Srwatson	ctx->ct_flags |= SMBCF_RESOLVED;
566219131Srwatson	return 0;
567259436Spjd}
568219131Srwatson
569219131Srwatsonstatic int
570219131Srwatsonsmb_ctx_gethandle(struct smb_ctx *ctx)
571259436Spjd{
572219131Srwatson	int fd, i;
573219131Srwatson	char buf[20];
574219131Srwatson
575219131Srwatson	/*
576219131Srwatson	 * First, try to open as cloned device
577219131Srwatson	 */
578219131Srwatson	fd = open("/dev/"NSMB_NAME, O_RDWR);
579219131Srwatson	if (fd >= 0) {
580219131Srwatson		ctx->ct_fd = fd;
581219131Srwatson		return 0;
582219131Srwatson	}
583219131Srwatson	/*
584219131Srwatson	 * well, no clone capabilities available - we have to scan
585219131Srwatson	 * all devices in order to get free one
586219131Srwatson	 */
587219131Srwatson	 for (i = 0; i < 1024; i++) {
588219131Srwatson	         snprintf(buf, sizeof(buf), "/dev/%s%d", NSMB_NAME, i);
589219131Srwatson		 fd = open(buf, O_RDWR);
590219131Srwatson		 if (fd >= 0) {
591219131Srwatson			ctx->ct_fd = fd;
592219131Srwatson			return 0;
593219131Srwatson		 }
594219131Srwatson	 }
595219131Srwatson	 /*
596219131Srwatson	  * This is a compatibility with old /dev/net/nsmb device
597219131Srwatson	  */
598219131Srwatson	 for (i = 0; i < 1024; i++) {
599219131Srwatson	         snprintf(buf, sizeof(buf), "/dev/net/%s%d", NSMB_NAME, i);
600219131Srwatson		 fd = open(buf, O_RDWR);
601219131Srwatson		 if (fd >= 0) {
602219131Srwatson			ctx->ct_fd = fd;
603219131Srwatson			return 0;
604219131Srwatson		 }
605219131Srwatson		 if (errno == ENOENT)
606219131Srwatson		         return ENOENT;
607219131Srwatson	 }
608219131Srwatson	 return ENOENT;
609219131Srwatson}
610219131Srwatson
611219131Srwatsonint
612219131Srwatsonsmb_ctx_lookup(struct smb_ctx *ctx, int level, int flags)
613219131Srwatson{
614219131Srwatson	struct smbioc_lookup rq;
615219131Srwatson	int error;
616219131Srwatson
617219131Srwatson	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
618219131Srwatson		smb_error("smb_ctx_lookup() data is not resolved", 0);
619219131Srwatson		return EINVAL;
620219131Srwatson	}
621219131Srwatson	if (ctx->ct_fd != -1) {
622219131Srwatson		close(ctx->ct_fd);
623219131Srwatson		ctx->ct_fd = -1;
624219131Srwatson	}
625219131Srwatson	error = smb_ctx_gethandle(ctx);
626219131Srwatson	if (error) {
627219131Srwatson		smb_error("can't get handle to requester (no /dev/"NSMB_NAME"* device)", 0);
628219131Srwatson		return EINVAL;
629219131Srwatson	}
630219131Srwatson	bzero(&rq, sizeof(rq));
631219131Srwatson	bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof(struct smbioc_ossn));
632219131Srwatson	bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof(struct smbioc_oshare));
633219131Srwatson	rq.ioc_flags = flags;
634219131Srwatson	rq.ioc_level = level;
635219131Srwatson	if (ioctl(ctx->ct_fd, SMBIOC_LOOKUP, &rq) == -1) {
636219131Srwatson		error = errno;
637219131Srwatson		if (flags & SMBLK_CREATE)
638219131Srwatson			smb_error("unable to open connection", error);
639219131Srwatson		return error;
640219131Srwatson	}
641219131Srwatson	return 0;
642219131Srwatson}
643219131Srwatson
644219131Srwatsonint
645219131Srwatsonsmb_ctx_login(struct smb_ctx *ctx)
646219131Srwatson{
647219131Srwatson	struct smbioc_ossn *ssn = &ctx->ct_ssn;
648219131Srwatson	struct smbioc_oshare *sh = &ctx->ct_sh;
649219131Srwatson	int error;
650224812Sjonathan
651219131Srwatson	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
652224812Sjonathan		smb_error("smb_ctx_resolve() should be called first", 0);
653219131Srwatson		return EINVAL;
654219131Srwatson	}
655219131Srwatson	if (ctx->ct_fd != -1) {
656219131Srwatson		close(ctx->ct_fd);
657219131Srwatson		ctx->ct_fd = -1;
658219131Srwatson	}
659219131Srwatson	error = smb_ctx_gethandle(ctx);
660219131Srwatson	if (error) {
661219131Srwatson		smb_error("can't get handle to requester", 0);
662219131Srwatson		return EINVAL;
663219131Srwatson	}
664219131Srwatson	if (ioctl(ctx->ct_fd, SMBIOC_OPENSESSION, ssn) == -1) {
665219131Srwatson		error = errno;
666219131Srwatson		smb_error("can't open session to server %s", error, ssn->ioc_srvname);
667219131Srwatson		return error;
668219131Srwatson	}
669219131Srwatson	if (sh->ioc_share[0] == 0)
670219131Srwatson		return 0;
671219131Srwatson	if (ioctl(ctx->ct_fd, SMBIOC_OPENSHARE, sh) == -1) {
672219131Srwatson		error = errno;
673219131Srwatson		smb_error("can't connect to share //%s/%s", error,
674219131Srwatson		    ssn->ioc_srvname, sh->ioc_share);
675261220Scsjp		return error;
676219131Srwatson	}
677219131Srwatson	return 0;
678219131Srwatson}
679219131Srwatson
680219131Srwatsonint
681219131Srwatsonsmb_ctx_setflags(struct smb_ctx *ctx, int level, int mask, int flags)
682219131Srwatson{
683219131Srwatson	struct smbioc_flags fl;
684219131Srwatson
685219131Srwatson	if (ctx->ct_fd == -1)
686219131Srwatson		return EINVAL;
687219131Srwatson	fl.ioc_level = level;
688219131Srwatson	fl.ioc_mask = mask;
689219131Srwatson	fl.ioc_flags = flags;
690219131Srwatson	if (ioctl(ctx->ct_fd, SMBIOC_SETFLAGS, &fl) == -1)
691219131Srwatson		return errno;
692219131Srwatson	return 0;
693219131Srwatson}
694219131Srwatson
695219131Srwatson/*
696219131Srwatson * level values:
697219131Srwatson * 0 - default
698219131Srwatson * 1 - server
699219131Srwatson * 2 - server:user
700219131Srwatson * 3 - server:user:share
701219131Srwatson */
702219131Srwatsonstatic int
703219131Srwatsonsmb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
704219131Srwatson{
705219131Srwatson	char *p;
706219131Srwatson	int error;
707219131Srwatson
708219131Srwatson	if (level >= 0) {
709219131Srwatson		rc_getstringptr(smb_rc, sname, "charsets", &p);
710219131Srwatson		if (p) {
711219131Srwatson			error = smb_ctx_setcharset(ctx, p);
712219131Srwatson			if (error)
713219131Srwatson				smb_error("charset specification in the section '%s' ignored", error, sname);
714219131Srwatson		}
715219131Srwatson	}
716219131Srwatson	if (level <= 1) {
717219131Srwatson		rc_getint(smb_rc, sname, "timeout", &ctx->ct_ssn.ioc_timeout);
718219131Srwatson		rc_getint(smb_rc, sname, "retry_count", &ctx->ct_ssn.ioc_retrycount);
719219131Srwatson	}
720219131Srwatson	if (level == 1) {
721219131Srwatson		rc_getstringptr(smb_rc, sname, "addr", &p);
722219131Srwatson		if (p) {
723219131Srwatson			error = smb_ctx_setsrvaddr(ctx, p);
724219131Srwatson			if (error) {
725219131Srwatson				smb_error("invalid address specified in the section %s", 0, sname);
726219131Srwatson				return error;
727219131Srwatson			}
728219131Srwatson		}
729219131Srwatson	}
730219131Srwatson	if (level >= 2) {
731219131Srwatson		rc_getstringptr(smb_rc, sname, "password", &p);
732219131Srwatson		if (p)
733219131Srwatson			smb_ctx_setpassword(ctx, p);
734219131Srwatson	}
735219131Srwatson	rc_getstringptr(smb_rc, sname, "workgroup", &p);
736219131Srwatson	if (p)
737219131Srwatson		smb_ctx_setworkgroup(ctx, p);
738219131Srwatson	return 0;
739219131Srwatson}
740219131Srwatson
741219131Srwatson/*
742219131Srwatson * read rc file as follows:
743219131Srwatson * 1. read [default] section
744219131Srwatson * 2. override with [server] section
745219131Srwatson * 3. override with [server:user:share] section
746219131Srwatson * Since abcence of rcfile is not fatal, silently ignore this fact.
747219131Srwatson * smb_rc file should be closed by caller.
748219131Srwatson */
749219131Srwatsonint
750219131Srwatsonsmb_ctx_readrc(struct smb_ctx *ctx)
751219131Srwatson{
752219131Srwatson	char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN + SMB_MAXSHARENAMELEN + 4];
753219131Srwatson/*	char *p;*/
754219131Srwatson
755	if (smb_open_rcfile() != 0)
756		return 0;
757
758	if (ctx->ct_ssn.ioc_user[0] == 0 || ctx->ct_ssn.ioc_srvname[0] == 0)
759		return 0;
760
761	smb_ctx_readrcsection(ctx, "default", 0);
762	nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
763	smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1);
764	nb_ctx_readrcsection(smb_rc, ctx->ct_nb, ctx->ct_ssn.ioc_srvname, 1);
765	/*
766	 * SERVER:USER parameters
767	 */
768	snprintf(sname, sizeof(sname), "%s:%s", ctx->ct_ssn.ioc_srvname,
769	    ctx->ct_ssn.ioc_user);
770	smb_ctx_readrcsection(ctx, sname, 2);
771
772	if (ctx->ct_sh.ioc_share[0] != 0) {
773		/*
774		 * SERVER:USER:SHARE parameters
775	         */
776		snprintf(sname, sizeof(sname), "%s:%s:%s", ctx->ct_ssn.ioc_srvname,
777		    ctx->ct_ssn.ioc_user, ctx->ct_sh.ioc_share);
778		smb_ctx_readrcsection(ctx, sname, 3);
779	}
780	return 0;
781}
782
783