2 * Copyright (c) 2000-2002, Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $Id: ctx.c,v 1.24 2002/04/13 14:35:28 bp Exp $
35 #include <sys/param.h>
36 #include <sys/sysctl.h>
37 #include <sys/ioctl.h>
39 #include <sys/mount.h>
49 #include <sys/iconv.h>
51 #define NB_NEEDRESOLVER
53 #include <netsmb/smb_lib.h>
54 #include <netsmb/netbios.h>
55 #include <netsmb/nb_lib.h>
56 #include <netsmb/smb_conn.h>
60 * Prescan command line for [-U user] argument
61 * and fill context with defaults
64 smb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[],
65 int minlevel, int maxlevel, int sharetype)
72 bzero(ctx,sizeof(*ctx));
73 error = nb_ctx_create(&ctx->ct_nb);
77 ctx->ct_parsedlevel = SMBL_NONE;
78 ctx->ct_minlevel = minlevel;
79 ctx->ct_maxlevel = maxlevel;
80 ctx->ct_smbtcpport = SMB_TCP_PORT;
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;
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;
98 nb_ctx_setscope(ctx->ct_nb, "");
100 if ((pwd = getpwuid(euid)) != NULL) {
101 smb_ctx_setuser(ctx, pwd->pw_name);
103 } else if (euid == 0)
104 smb_ctx_setuser(ctx, "root");
109 for (opt = 1; opt < argc; opt++) {
111 if (strncmp(cp, "//", 2) != 0)
113 error = smb_ctx_parseunc(ctx, cp, sharetype, (const char**)&cp);
116 ctx->ct_uncnext = cp;
119 while (error == 0 && (opt = cf_getopt(argc, argv, ":E:L:U:")) != -1) {
123 error = smb_ctx_setcharset(ctx, arg);
128 error = nls_setlocale(arg);
133 error = smb_ctx_setuser(ctx, arg);
137 cf_optind = cf_optreset = 1;
142 smb_ctx_done(struct smb_ctx *ctx)
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);
149 free(ctx->ct_srvaddr);
151 nb_ctx_done(ctx->ct_nb);
155 getsubstring(const char *p, u_char sep, char *dest, int maxlen, const char **next)
160 for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) {
166 *next = *p ? p + 1 : p;
171 * Here we expect something like "[proto:]//[user@]host[:psmb[:pnb]][/share][/path]"
174 smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
178 char *p1, *psmb, *pnb;
182 ctx->ct_parsedlevel = SMBL_NONE;
183 if (*p++ != '/' || *p++ != '/') {
184 smb_error("UNC should start with '//'", 0);
188 error = getsubstring(p, '@', p1, sizeof(tmp), &p);
190 if (ctx->ct_maxlevel < SMBL_VC) {
191 smb_error("no user name required", 0);
195 smb_error("empty user name", 0);
198 error = smb_ctx_setuser(ctx, tmp);
201 ctx->ct_parsedlevel = SMBL_VC;
203 error = getsubstring(p, '/', p1, sizeof(tmp), &p);
205 error = getsubstring(p, '\0', p1, sizeof(tmp), &p);
207 smb_error("no server name found", 0);
212 smb_error("empty server name", 0);
216 * Check for port number specification.
218 psmb = strchr(tmp, ':');
221 pnb = strchr(psmb, ':');
224 error = smb_ctx_setnbport(ctx, atoi(pnb));
226 smb_error("Invalid NetBIOS port number", 0);
230 error = smb_ctx_setsmbport(ctx, atoi(psmb));
232 smb_error("Invalid SMB port number", 0);
236 error = smb_ctx_setserver(ctx, tmp);
239 if (sharetype == SMB_ST_NONE) {
243 if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
244 smb_error("no share name required", 0);
247 error = getsubstring(p, '/', p1, sizeof(tmp), &p);
249 error = getsubstring(p, '\0', p1, sizeof(tmp), &p);
251 smb_error("unexpected end of line", 0);
255 if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE) {
256 smb_error("empty share name", 0);
262 error = smb_ctx_setshare(ctx, p1, sharetype);
267 smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
269 char *cp, *servercs, *localcs;
270 int cslen = sizeof(ctx->ct_ssn.ioc_localcs);
271 int scslen, lcslen, error;
273 cp = strchr(arg, ':');
274 lcslen = cp ? (cp - arg) : 0;
275 if (lcslen == 0 || lcslen >= cslen) {
276 smb_error("invalid local charset specification (%s)", 0, arg);
279 scslen = (size_t)strlen(++cp);
280 if (scslen == 0 || scslen >= cslen) {
281 smb_error("invalid server charset specification (%s)", 0, arg);
284 localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen);
286 servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp);
287 error = nls_setrecode(localcs, servercs);
290 smb_error("can't initialize iconv support (%s:%s)",
291 error, localcs, servercs);
298 smb_ctx_setserver(struct smb_ctx *ctx, const char *name)
300 if (strlen(name) > SMB_MAXSRVNAMELEN) {
301 smb_error("server name '%s' too long", 0, name);
304 nls_str_upper(ctx->ct_ssn.ioc_srvname, name);
309 smb_ctx_setnbport(struct smb_ctx *ctx, int port)
311 if (port < 1 || port > 0xffff)
313 ctx->ct_nb->nb_nmbtcpport = port;
318 smb_ctx_setsmbport(struct smb_ctx *ctx, int port)
320 if (port < 1 || port > 0xffff)
322 ctx->ct_smbtcpport = port;
323 ctx->ct_nb->nb_smbtcpport = port;
328 smb_ctx_setuser(struct smb_ctx *ctx, const char *name)
330 if (strlen(name) > SMB_MAXUSERNAMELEN) {
331 smb_error("user name '%s' too long", 0, name);
334 nls_str_upper(ctx->ct_ssn.ioc_user, name);
339 smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name)
341 if (strlen(name) > SMB_MAXUSERNAMELEN) {
342 smb_error("workgroup name '%s' too long", 0, name);
345 nls_str_upper(ctx->ct_ssn.ioc_workgroup, name);
350 smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd)
354 if (strlen(passwd) > SMB_MAXPASSWORDLEN) {
355 smb_error("password too long", 0);
358 if (strncmp(passwd, "$$1", 3) == 0)
359 smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd);
361 strcpy(ctx->ct_ssn.ioc_password, passwd);
362 strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password);
367 smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
369 if (strlen(share) > SMB_MAXSHARENAMELEN) {
370 smb_error("share name '%s' too long", 0, share);
373 nls_str_upper(ctx->ct_sh.ioc_share, share);
375 ctx->ct_parsedlevel = SMBL_SHARE;
376 ctx->ct_sh.ioc_stype = stype;
381 smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr)
383 if (addr == NULL || addr[0] == 0)
386 free(ctx->ct_srvaddr);
387 if ((ctx->ct_srvaddr = strdup(addr)) == NULL)
393 smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
399 cp = strchr(pair, ':');
407 smb_error("Invalid group name %s, ignored",
416 smb_error("Invalid user name %s, ignored", 0, pair);
423 smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
432 error = smb_ctx_setsrvaddr(ctx, arg);
435 ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8);
437 ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8);
438 ctx->ct_flags |= SMBCF_SRIGHTS;
442 ctx->ct_flags |= SMBCF_NOPWD;
449 error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner,
450 &ctx->ct_sh.ioc_group);
452 if (*p && error == 0) {
453 error = smb_parse_owner(p, &ctx->ct_ssn.ioc_owner,
454 &ctx->ct_ssn.ioc_group);
459 /* ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT;*/
462 ctx->ct_ssn.ioc_retrycount = atoi(arg);
465 ctx->ct_ssn.ioc_timeout = atoi(arg);
468 error = smb_ctx_setworkgroup(ctx, arg);
476 smb_hexdump(const u_char *buf, int len) {
481 printf("\n%02X: ", ofs);
482 printf("%02x ", *buf++);
491 smb_addiconvtbl(const char *to, const char *from, const u_char *tbl)
495 error = kiconv_add_xlat_table(to, from, tbl);
496 if (error && error != EEXIST) {
497 smb_error("can not setup kernel iconv table (%s:%s)", error,
505 * Verify context before connect operation(s),
506 * lookup specified server and try to fill all forgotten fields.
509 smb_ctx_resolve(struct smb_ctx *ctx)
511 struct smbioc_ossn *ssn = &ctx->ct_ssn;
512 struct smbioc_oshare *sh = &ctx->ct_sh;
514 struct sockaddr *sap;
515 struct sockaddr_nb *salocal, *saserver;
519 ctx->ct_flags &= ~SMBCF_RESOLVED;
520 if (ssn->ioc_srvname[0] == 0) {
521 smb_error("no server name specified", 0);
524 if (ssn->ioc_user[0] == 0) {
525 smb_error("no user name specified for server %s",
526 0, ssn->ioc_srvname);
529 if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0) {
530 smb_error("no share name specified for %s@%s",
531 0, ssn->ioc_user, ssn->ioc_srvname);
534 error = nb_ctx_resolve(ctx->ct_nb);
537 if (ssn->ioc_localcs[0] == 0)
538 strcpy(ssn->ioc_localcs, "ISO8859-1");
539 error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
542 error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
545 if (ssn->ioc_servercs[0] != 0) {
546 error = kiconv_add_xlat16_cspairs
547 (ssn->ioc_servercs, ssn->ioc_localcs);
548 if (error) return error;
550 if (ctx->ct_srvaddr) {
551 error = nb_resolvehost_in(ctx->ct_srvaddr, &sap, ctx->ct_smbtcpport);
553 error = nbns_resolvename(ssn->ioc_srvname, ctx->ct_nb, &sap);
556 smb_error("can't get server address", error);
559 nn.nn_scope = ctx->ct_nb->nb_scope;
560 nn.nn_type = NBT_SERVER;
561 strcpy(nn.nn_name, ssn->ioc_srvname);
562 error = nb_sockaddr(sap, &nn, &saserver);
565 smb_error("can't allocate server address", error);
568 ssn->ioc_server = (struct sockaddr*)saserver;
569 if (ctx->ct_locname[0] == 0) {
570 error = nb_getlocalname(ctx->ct_locname);
572 smb_error("can't get local name", error);
575 nls_str_upper(ctx->ct_locname, ctx->ct_locname);
577 strcpy(nn.nn_name, ctx->ct_locname);
578 nn.nn_type = NBT_WKSTA;
579 nn.nn_scope = ctx->ct_nb->nb_scope;
580 error = nb_sockaddr(NULL, &nn, &salocal);
582 nb_snbfree((struct sockaddr*)saserver);
583 smb_error("can't allocate local address", error);
586 ssn->ioc_local = (struct sockaddr*)salocal;
587 ssn->ioc_lolen = salocal->snb_len;
588 ssn->ioc_svlen = saserver->snb_len;
589 if (ssn->ioc_password[0] == 0 && (ctx->ct_flags & SMBCF_NOPWD) == 0) {
590 cp = getpass("Password:");
591 error = smb_ctx_setpassword(ctx, cp);
595 ctx->ct_flags |= SMBCF_RESOLVED;
600 smb_ctx_gethandle(struct smb_ctx *ctx)
606 * First, try to open as cloned device
608 fd = open("/dev/"NSMB_NAME, O_RDWR);
614 * well, no clone capabilities available - we have to scan
615 * all devices in order to get free one
617 for (i = 0; i < 1024; i++) {
618 snprintf(buf, sizeof(buf), "/dev/%s%d", NSMB_NAME, i);
619 fd = open(buf, O_RDWR);
626 * This is a compatibility with old /dev/net/nsmb device
628 for (i = 0; i < 1024; i++) {
629 snprintf(buf, sizeof(buf), "/dev/net/%s%d", NSMB_NAME, i);
630 fd = open(buf, O_RDWR);
642 smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags)
644 struct smbioc_lookup rq;
647 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
648 smb_error("smb_ctx_lookup() data is not resolved", 0);
651 if (ctx->ct_fd != -1) {
655 error = smb_ctx_gethandle(ctx);
657 smb_error("can't get handle to requester (no /dev/"NSMB_NAME"* device)", 0);
660 bzero(&rq, sizeof(rq));
661 bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof(struct smbioc_ossn));
662 bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof(struct smbioc_oshare));
663 rq.ioc_flags = flags;
664 rq.ioc_level = level;
665 if (ioctl(ctx->ct_fd, SMBIOC_LOOKUP, &rq) == -1) {
667 if (flags & SMBLK_CREATE)
668 smb_error("unable to open connection", error);
675 smb_ctx_login(struct smb_ctx *ctx)
677 struct smbioc_ossn *ssn = &ctx->ct_ssn;
678 struct smbioc_oshare *sh = &ctx->ct_sh;
681 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
682 smb_error("smb_ctx_resolve() should be called first", 0);
685 if (ctx->ct_fd != -1) {
689 error = smb_ctx_gethandle(ctx);
691 smb_error("can't get handle to requester", 0);
694 if (ioctl(ctx->ct_fd, SMBIOC_OPENSESSION, ssn) == -1) {
696 smb_error("can't open session to server %s", error, ssn->ioc_srvname);
699 if (sh->ioc_share[0] == 0)
701 if (ioctl(ctx->ct_fd, SMBIOC_OPENSHARE, sh) == -1) {
703 smb_error("can't connect to share //%s/%s", error,
704 ssn->ioc_srvname, sh->ioc_share);
711 smb_ctx_setflags(struct smb_ctx *ctx, int level, int mask, int flags)
713 struct smbioc_flags fl;
715 if (ctx->ct_fd == -1)
717 fl.ioc_level = level;
719 fl.ioc_flags = flags;
720 if (ioctl(ctx->ct_fd, SMBIOC_SETFLAGS, &fl) == -1)
730 * 3 - server:user:share
733 smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
739 rc_getstringptr(smb_rc, sname, "charsets", &p);
741 error = smb_ctx_setcharset(ctx, p);
743 smb_error("charset specification in the section '%s' ignored", error, sname);
747 rc_getint(smb_rc, sname, "timeout", &ctx->ct_ssn.ioc_timeout);
748 rc_getint(smb_rc, sname, "retry_count", &ctx->ct_ssn.ioc_retrycount);
751 rc_getstringptr(smb_rc, sname, "addr", &p);
753 error = smb_ctx_setsrvaddr(ctx, p);
755 smb_error("invalid address specified in the section %s", 0, sname);
761 rc_getstringptr(smb_rc, sname, "password", &p);
763 smb_ctx_setpassword(ctx, p);
765 rc_getstringptr(smb_rc, sname, "workgroup", &p);
767 smb_ctx_setworkgroup(ctx, p);
772 * read rc file as follows:
773 * 1. read [default] section
774 * 2. override with [server] section
775 * 3. override with [server:user:share] section
776 * Since abcence of rcfile is not fatal, silently ignore this fact.
777 * smb_rc file should be closed by caller.
780 smb_ctx_readrc(struct smb_ctx *ctx)
782 char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN + SMB_MAXSHARENAMELEN + 4];
785 if (smb_open_rcfile() != 0)
788 if (ctx->ct_ssn.ioc_user[0] == 0 || ctx->ct_ssn.ioc_srvname[0] == 0)
791 smb_ctx_readrcsection(ctx, "default", 0);
792 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
793 smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1);
794 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, ctx->ct_ssn.ioc_srvname, 1);
796 * SERVER:USER parameters
798 snprintf(sname, sizeof(sname), "%s:%s", ctx->ct_ssn.ioc_srvname,
799 ctx->ct_ssn.ioc_user);
800 smb_ctx_readrcsection(ctx, sname, 2);
802 if (ctx->ct_sh.ioc_share[0] != 0) {
804 * SERVER:USER:SHARE parameters
806 snprintf(sname, sizeof(sname), "%s:%s:%s", ctx->ct_ssn.ioc_srvname,
807 ctx->ct_ssn.ioc_user, ctx->ct_sh.ioc_share);
808 smb_ctx_readrcsection(ctx, sname, 3);