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 * from: Id: ctx.c,v 1.24 2002/04/13 14:35:28 bp Exp
35 #include <sys/cdefs.h>
36 __RCSID("$NetBSD: ctx.c,v 1.14 2009/09/06 18:38:17 pooka Exp $");
38 #include <sys/param.h>
39 #include <sys/sysctl.h>
40 #include <sys/ioctl.h>
42 #include <sys/mount.h>
52 #include <netsmb/iconv.h>
54 #define NB_NEEDRESOLVER
56 #include <netsmb/smb_lib.h>
57 #include <netsmb/netbios.h>
58 #include <netsmb/nb_lib.h>
59 #include <netsmb/smb_conn.h>
62 #include "smb_kernelops.h"
65 * Prescan command line for [-U user] argument
66 * and fill context with defaults
69 smb_ctx_init(struct smb_ctx
*ctx
, int argc
, char *argv
[],
70 int minlevel
, int maxlevel
, int sharetype
)
77 bzero(ctx
,sizeof(*ctx
));
78 error
= nb_ctx_create(&ctx
->ct_nb
);
82 ctx
->ct_parsedlevel
= SMBL_NONE
;
83 ctx
->ct_minlevel
= minlevel
;
84 ctx
->ct_maxlevel
= maxlevel
;
86 ctx
->ct_ssn
.ioc_opt
= SMBVOPT_CREATE
;
87 ctx
->ct_ssn
.ioc_timeout
= 15;
88 ctx
->ct_ssn
.ioc_retrycount
= 4;
89 ctx
->ct_ssn
.ioc_owner
= SMBM_ANY_OWNER
;
90 ctx
->ct_ssn
.ioc_group
= SMBM_ANY_GROUP
;
91 ctx
->ct_ssn
.ioc_mode
= SMBM_EXEC
;
92 ctx
->ct_ssn
.ioc_rights
= SMBM_DEFAULT
;
94 ctx
->ct_sh
.ioc_opt
= SMBVOPT_CREATE
;
95 ctx
->ct_sh
.ioc_owner
= SMBM_ANY_OWNER
;
96 ctx
->ct_sh
.ioc_group
= SMBM_ANY_GROUP
;
97 ctx
->ct_sh
.ioc_mode
= SMBM_EXEC
;
98 ctx
->ct_sh
.ioc_rights
= SMBM_DEFAULT
;
99 ctx
->ct_sh
.ioc_owner
= SMBM_ANY_OWNER
;
100 ctx
->ct_sh
.ioc_group
= SMBM_ANY_GROUP
;
102 nb_ctx_setscope(ctx
->ct_nb
, "");
104 if ((pwd
= getpwuid(euid
)) != NULL
) {
105 smb_ctx_setuser(ctx
, pwd
->pw_name
);
107 } else if (euid
== 0)
108 smb_ctx_setuser(ctx
, "root");
113 for (opt
= 1; opt
< argc
; opt
++) {
115 if (strncmp(cp
, "//", 2) != 0)
117 error
= smb_ctx_parseunc(ctx
, cp
, sharetype
, (const char**)&cp
);
120 ctx
->ct_uncnext
= cp
;
123 while (error
== 0 && (opt
= cf_getopt(argc
, argv
, ":E:L:U:")) != -1) {
127 error
= smb_ctx_setcharset(ctx
, arg
);
132 error
= nls_setlocale(optarg
);
137 error
= smb_ctx_setuser(ctx
, arg
);
141 cf_optind
= cf_optreset
= 1;
146 smb_ctx_done(struct smb_ctx
*ctx
)
148 if (ctx
->ct_ssn
.ioc_server
)
149 nb_snbfree(ctx
->ct_ssn
.ioc_server
);
150 if (ctx
->ct_ssn
.ioc_local
)
151 nb_snbfree(ctx
->ct_ssn
.ioc_local
);
153 free(ctx
->ct_srvaddr
);
155 nb_ctx_done(ctx
->ct_nb
);
159 getsubstring(const char *p
, u_char sep
, char *dest
, int maxlen
, const char **next
)
164 for (len
= 0; len
< maxlen
&& *p
!= sep
; p
++, len
++, dest
++) {
170 *next
= *p
? p
+ 1 : p
;
175 * Here we expect something like "[proto:]//[user@]host[/share][/path]"
178 smb_ctx_parseunc(struct smb_ctx
*ctx
, const char *unc
, int sharetype
,
186 ctx
->ct_parsedlevel
= SMBL_NONE
;
187 if (*p
++ != '/' || *p
++ != '/') {
188 smb_error("UNC should start with '//'", 0);
192 error
= getsubstring(p
, '@', p1
, sizeof(tmp
), &p
);
194 if (ctx
->ct_maxlevel
< SMBL_VC
) {
195 smb_error("no user name required", 0);
199 smb_error("empty user name", 0);
202 error
= smb_ctx_setuser(ctx
, tmp
);
205 ctx
->ct_parsedlevel
= SMBL_VC
;
207 error
= getsubstring(p
, '/', p1
, sizeof(tmp
), &p
);
209 error
= getsubstring(p
, '\0', p1
, sizeof(tmp
), &p
);
211 smb_error("no server name found", 0);
216 smb_error("empty server name", 0);
219 error
= smb_ctx_setserver(ctx
, tmp
);
222 if (sharetype
== SMB_ST_NONE
) {
226 if (*p
!= 0 && ctx
->ct_maxlevel
< SMBL_SHARE
) {
227 smb_error("no share name required", 0);
230 error
= getsubstring(p
, '/', p1
, sizeof(tmp
), &p
);
232 error
= getsubstring(p
, '\0', p1
, sizeof(tmp
), &p
);
234 smb_error("unexpected end of line", 0);
238 if (*p1
== 0 && ctx
->ct_minlevel
>= SMBL_SHARE
) {
239 smb_error("empty share name", 0);
245 error
= smb_ctx_setshare(ctx
, p1
, sharetype
);
250 smb_ctx_setcharset(struct smb_ctx
*ctx
, const char *arg
)
252 char *cp
, *servercs
, *localcs
;
253 int cslen
= sizeof(ctx
->ct_ssn
.ioc_localcs
);
254 int scslen
, lcslen
, error
;
256 cp
= strchr(arg
, ':');
257 lcslen
= cp
? (cp
- arg
) : 0;
258 if (lcslen
== 0 || lcslen
>= cslen
) {
259 smb_error("invalid local charset specification (%s)", 0, arg
);
262 scslen
= (size_t)strlen(++cp
);
263 if (scslen
== 0 || scslen
>= cslen
) {
264 smb_error("invalid server charset specification (%s)", 0, arg
);
267 localcs
= memcpy(ctx
->ct_ssn
.ioc_localcs
, arg
, lcslen
);
269 servercs
= strcpy(ctx
->ct_ssn
.ioc_servercs
, cp
);
270 error
= nls_setrecode(localcs
, servercs
);
273 smb_error("can't initialize iconv support (%s:%s)",
274 error
, localcs
, servercs
);
281 smb_ctx_setserver(struct smb_ctx
*ctx
, const char *name
)
286 * If the name contains dot, it's likely a IP address
287 * or a name. Update srvaddr in that case, and use
288 * first part of the name (up to the dot) as NetBIOS name.
290 if ((d
= strchr(name
, '.'))) {
291 static char nm
[sizeof(ctx
->ct_ssn
.ioc_srvname
)];
294 error
= smb_ctx_setsrvaddr(ctx
, name
);
298 /* cut name to MAXSRVNAMELEN */
299 if (strlen(name
) >= sizeof(ctx
->ct_ssn
.ioc_srvname
)) {
300 snprintf(nm
, sizeof(nm
), "%.*s",
301 (int)(sizeof(ctx
->ct_ssn
.ioc_srvname
) - 1), name
);
306 if (strlen(name
) >= sizeof(ctx
->ct_ssn
.ioc_srvname
)) {
307 smb_error("server name '%s' too long", 0, name
);
310 nls_str_upper(ctx
->ct_ssn
.ioc_srvname
, name
);
315 smb_ctx_setuser(struct smb_ctx
*ctx
, const char *name
)
317 if (strlen(name
) >= sizeof(ctx
->ct_ssn
.ioc_user
)) {
318 smb_error("user name '%s' too long", 0, name
);
321 nls_str_upper(ctx
->ct_ssn
.ioc_user
, name
);
326 smb_ctx_setworkgroup(struct smb_ctx
*ctx
, const char *name
)
328 if (strlen(name
) >= SMB_MAXUSERNAMELEN
) {
329 smb_error("workgroup name '%s' too long", 0, name
);
332 nls_str_upper(ctx
->ct_ssn
.ioc_workgroup
, name
);
337 smb_ctx_setpassword(struct smb_ctx
*ctx
, const char *passwd
)
341 if (strlen(passwd
) >= SMB_MAXPASSWORDLEN
) {
342 smb_error("password too long", 0);
345 if (strncmp(passwd
, "$$1", 3) == 0)
346 smb_simpledecrypt(ctx
->ct_ssn
.ioc_password
, passwd
);
348 strcpy(ctx
->ct_ssn
.ioc_password
, passwd
);
349 strcpy(ctx
->ct_sh
.ioc_password
, ctx
->ct_ssn
.ioc_password
);
354 smb_ctx_setshare(struct smb_ctx
*ctx
, const char *share
, int stype
)
356 if (strlen(share
) >= SMB_MAXSHARENAMELEN
) {
357 smb_error("share name '%s' too long", 0, share
);
360 nls_str_upper(ctx
->ct_sh
.ioc_share
, share
);
362 ctx
->ct_parsedlevel
= SMBL_SHARE
;
363 ctx
->ct_sh
.ioc_stype
= stype
;
368 smb_ctx_setsrvaddr(struct smb_ctx
*ctx
, const char *addr
)
370 if (addr
== NULL
|| addr
[0] == 0)
373 free(ctx
->ct_srvaddr
);
374 if ((ctx
->ct_srvaddr
= strdup(addr
)) == NULL
)
380 smb_parse_owner(char *pair
, uid_t
*uid
, gid_t
*gid
)
386 cp
= strchr(pair
, ':');
394 smb_error("Invalid group name '%s', ignored",
403 smb_error("Invalid user name '%s', ignored", 0, pair
);
410 smb_ctx_opt(struct smb_ctx
*ctx
, int opt
, const char *arg
)
419 error
= smb_ctx_setsrvaddr(ctx
, arg
);
422 ctx
->ct_ssn
.ioc_rights
= strtol(arg
, &cp
, 8);
424 ctx
->ct_sh
.ioc_rights
= strtol(cp
+ 1, &cp
, 8);
425 ctx
->ct_flags
|= SMBCF_SRIGHTS
;
429 ctx
->ct_flags
|= SMBCF_NOPWD
;
436 error
= smb_parse_owner(cp
, &ctx
->ct_sh
.ioc_owner
,
437 &ctx
->ct_sh
.ioc_group
);
439 if (*p
&& error
== 0) {
440 error
= smb_parse_owner(p
, &ctx
->ct_ssn
.ioc_owner
,
441 &ctx
->ct_ssn
.ioc_group
);
446 /* ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT;*/
449 ctx
->ct_ssn
.ioc_retrycount
= atoi(arg
);
452 ctx
->ct_ssn
.ioc_timeout
= atoi(arg
);
455 error
= smb_ctx_setworkgroup(ctx
, arg
);
463 smb_hexdump(const u_char
*buf
, int len
) {
468 printf("\n%02X: ", ofs
);
469 printf("%02x ", *buf
++);
478 smb_addiconvtbl(const char *to
, const char *from
, const u_char
*tbl
)
482 error
= kiconv_add_xlat_table(to
, from
, tbl
);
483 if (error
&& error
!= EEXIST
) {
484 smb_error("can not setup kernel iconv table (%s:%s)", error
,
492 * Verify context before connect operation(s),
493 * lookup specified server and try to fill all forgotten fields.
496 smb_ctx_resolve(struct smb_ctx
*ctx
)
498 struct smbioc_ossn
*ssn
= &ctx
->ct_ssn
;
499 struct smbioc_oshare
*sh
= &ctx
->ct_sh
;
501 struct sockaddr
*sap
;
502 struct sockaddr_nb
*salocal
, *saserver
;
508 ctx
->ct_flags
&= ~SMBCF_RESOLVED
;
509 if (ssn
->ioc_srvname
[0] == 0) {
510 smb_error("no server name specified", 0);
513 if (ssn
->ioc_user
[0] == 0) {
514 smb_error("no user name specified for server %s",
515 0, ssn
->ioc_srvname
);
518 if (ctx
->ct_minlevel
>= SMBL_SHARE
&& sh
->ioc_share
[0] == 0) {
519 smb_error("no share name specified for %s@%s",
520 0, ssn
->ioc_user
, ssn
->ioc_srvname
);
523 error
= nb_ctx_resolve(ctx
->ct_nb
);
526 if (ssn
->ioc_localcs
[0] == 0)
527 strcpy(ssn
->ioc_localcs
, "default"); /* XXX: locale name ? */
528 error
= smb_addiconvtbl("tolower", ssn
->ioc_localcs
, nls_lower
);
531 error
= smb_addiconvtbl("toupper", ssn
->ioc_localcs
, nls_upper
);
534 if (ssn
->ioc_servercs
[0] != 0) {
535 for(i
= 0; i
< sizeof(cstbl
); i
++)
537 nls_mem_toext(cstbl
, cstbl
, sizeof(cstbl
));
538 error
= smb_addiconvtbl(ssn
->ioc_servercs
, ssn
->ioc_localcs
, cstbl
);
541 for(i
= 0; i
< sizeof(cstbl
); i
++)
543 nls_mem_toloc(cstbl
, cstbl
, sizeof(cstbl
));
544 error
= smb_addiconvtbl(ssn
->ioc_localcs
, ssn
->ioc_servercs
, cstbl
);
548 if (ctx
->ct_srvaddr
) {
549 error
= nb_resolvehost_in(ctx
->ct_srvaddr
, &sap
);
551 error
= nbns_resolvename(ssn
->ioc_srvname
, ctx
->ct_nb
, &sap
);
554 smb_error("can't get server address", error
);
557 nn
.nn_scope
= ctx
->ct_nb
->nb_scope
;
558 nn
.nn_type
= NBT_SERVER
;
559 strcpy(nn
.nn_name
, ssn
->ioc_srvname
);
560 error
= nb_sockaddr(sap
, &nn
, &saserver
);
563 smb_error("can't allocate server address", error
);
566 ssn
->ioc_server
= (struct sockaddr
*)saserver
;
567 if (ctx
->ct_locname
[0] == 0) {
568 error
= nb_getlocalname(ctx
->ct_locname
);
570 smb_error("can't get local name", error
);
573 nls_str_upper(ctx
->ct_locname
, ctx
->ct_locname
);
575 strcpy(nn
.nn_name
, ctx
->ct_locname
);
576 nn
.nn_type
= NBT_WKSTA
;
577 nn
.nn_scope
= ctx
->ct_nb
->nb_scope
;
578 error
= nb_sockaddr(NULL
, &nn
, &salocal
);
580 nb_snbfree((struct sockaddr
*)saserver
);
581 smb_error("can't allocate local address", error
);
584 ssn
->ioc_local
= (struct sockaddr
*)salocal
;
585 ssn
->ioc_lolen
= salocal
->snb_len
;
586 ssn
->ioc_svlen
= saserver
->snb_len
;
587 if (ssn
->ioc_password
[0] == 0 && (ctx
->ct_flags
& SMBCF_NOPWD
) == 0) {
588 cp
= getpass("Password:");
589 error
= smb_ctx_setpassword(ctx
, cp
);
593 ctx
->ct_flags
|= SMBCF_RESOLVED
;
598 smb_ctx_gethandle(struct smb_ctx
*ctx
)
604 * First, try to open as cloned device
606 fd
= smb_kops
.ko_open("/dev/"NSMB_NAME
, O_RDWR
, 0);
613 * well, no clone capabilities available - we have to scan
614 * all devices in order to get free one
616 for (i
= 0; i
< 1024; i
++) {
617 snprintf(buf
, sizeof(buf
), "/dev/"NSMB_NAME
"%d", i
);
618 fd
= smb_kops
.ko_open(buf
, O_RDWR
, 0);
631 smb_ctx_lookup(struct smb_ctx
*ctx
, int level
, int flags
)
633 struct smbioc_lookup rq
;
636 if ((ctx
->ct_flags
& SMBCF_RESOLVED
) == 0) {
637 smb_error("smb_ctx_lookup() data is not resolved", 0);
640 if (ctx
->ct_fd
!= -1) {
641 smb_kops
.ko_close(ctx
->ct_fd
);
644 error
= smb_ctx_gethandle(ctx
);
646 smb_error("can't get handle to requester (no /dev/"NSMB_NAME
"* device available)", 0);
649 bzero(&rq
, sizeof(rq
));
650 bcopy(&ctx
->ct_ssn
, &rq
.ioc_ssn
, sizeof(struct smbioc_ossn
));
651 bcopy(&ctx
->ct_sh
, &rq
.ioc_sh
, sizeof(struct smbioc_oshare
));
652 rq
.ioc_flags
= flags
;
653 rq
.ioc_level
= level
;
654 if (smb_kops
.ko_ioctl(ctx
->ct_fd
, SMBIOC_LOOKUP
, &rq
) == -1) {
657 smb_kops
.ko_close(ctx
->ct_fd
);
661 * Fallback to *SMBSERVER as NetBIOS name. At least
662 * Windows NT and Windows XP require this (or valid
663 * NetBIOS server name), otherwise they refuse connection.
665 if (smb_ctx_setserver(ctx
, "*SMBSERVER") != 0)
668 error
= smb_ctx_resolve(ctx
);
672 error
= smb_ctx_gethandle(ctx
);
676 bcopy(&ctx
->ct_ssn
, &rq
.ioc_ssn
, sizeof(struct smbioc_ossn
));
678 if (smb_kops
.ko_ioctl(ctx
->ct_fd
, SMBIOC_LOOKUP
, &rq
) != -1)
683 if (flags
& SMBLK_CREATE
)
684 smb_error("unable to open connection", error
);
693 smb_ctx_login(struct smb_ctx
*ctx
)
695 struct smbioc_ossn
*ssn
= &ctx
->ct_ssn
;
696 struct smbioc_oshare
*sh
= &ctx
->ct_sh
;
699 if ((ctx
->ct_flags
& SMBCF_RESOLVED
) == 0) {
700 smb_error("smb_ctx_resolve() should be called first", 0);
703 if (ctx
->ct_fd
!= -1) {
704 smb_kops
.ko_close(ctx
->ct_fd
);
707 error
= smb_ctx_gethandle(ctx
);
709 smb_error("can't get handle to requester", 0);
712 if (smb_kops
.ko_ioctl(ctx
->ct_fd
, SMBIOC_OPENSESSION
, ssn
) == -1) {
714 smb_error("can't open session to server %s", error
, ssn
->ioc_srvname
);
717 if (sh
->ioc_share
[0] == 0)
719 if (smb_kops
.ko_ioctl(ctx
->ct_fd
, SMBIOC_OPENSHARE
, sh
) == -1) {
721 smb_error("can't connect to share //%s/%s", error
,
722 ssn
->ioc_srvname
, sh
->ioc_share
);
729 smb_ctx_setflags(struct smb_ctx
*ctx
, int level
, int mask
, int flags
)
731 struct smbioc_flags fl
;
733 if (ctx
->ct_fd
== -1)
735 fl
.ioc_level
= level
;
737 fl
.ioc_flags
= flags
;
738 if (smb_kops
.ko_ioctl(ctx
->ct_fd
, SMBIOC_SETFLAGS
, &fl
) == -1)
748 * 3 - server:user:share
751 smb_ctx_readrcsection(struct smb_ctx
*ctx
, const char *sname
, int level
)
757 rc_getstringptr(smb_rc
, sname
, "charsets", &p
);
759 error
= smb_ctx_setcharset(ctx
, p
);
761 smb_error("charset specification in the section '%s' ignored", error
, sname
);
765 rc_getint(smb_rc
, sname
, "timeout", &ctx
->ct_ssn
.ioc_timeout
);
766 rc_getint(smb_rc
, sname
, "retry_count", &ctx
->ct_ssn
.ioc_retrycount
);
769 rc_getstringptr(smb_rc
, sname
, "addr", &p
);
771 error
= smb_ctx_setsrvaddr(ctx
, p
);
773 smb_error("invalid address specified in the section %s", 0, sname
);
779 rc_getstringptr(smb_rc
, sname
, "password", &p
);
781 smb_ctx_setpassword(ctx
, p
);
783 rc_getstringptr(smb_rc
, sname
, "workgroup", &p
);
785 smb_ctx_setworkgroup(ctx
, p
);
790 * read rc file as follows:
791 * 1. read [default] section
792 * 2. override with [server] section
793 * 3. override with [server:user:share] section
794 * Since abcence of rcfile is not fatal, silently ignore this fact.
795 * smb_rc file should be closed by caller.
798 smb_ctx_readrc(struct smb_ctx
*ctx
)
800 char sname
[SMB_MAXSRVNAMELEN
+ SMB_MAXUSERNAMELEN
+ SMB_MAXSHARENAMELEN
+ 4];
803 if (smb_open_rcfile() != 0)
806 if (ctx
->ct_ssn
.ioc_user
[0] == 0 || ctx
->ct_ssn
.ioc_srvname
[0] == 0)
809 smb_ctx_readrcsection(ctx
, "default", 0);
810 nb_ctx_readrcsection(smb_rc
, ctx
->ct_nb
, "default", 0);
811 smb_ctx_readrcsection(ctx
, ctx
->ct_ssn
.ioc_srvname
, 1);
812 nb_ctx_readrcsection(smb_rc
, ctx
->ct_nb
, ctx
->ct_ssn
.ioc_srvname
, 1);
814 * SERVER:USER parameters
816 snprintf(sname
, sizeof(sname
), "%s:%s", ctx
->ct_ssn
.ioc_srvname
,
817 ctx
->ct_ssn
.ioc_user
);
818 smb_ctx_readrcsection(ctx
, sname
, 2);
820 if (ctx
->ct_sh
.ioc_share
[0] != 0) {
822 * SERVER:USER:SHARE parameters
824 snprintf(sname
, sizeof(sname
), "%s:%s:%s", ctx
->ct_ssn
.ioc_srvname
,
825 ctx
->ct_ssn
.ioc_user
, ctx
->ct_sh
.ioc_share
);
826 smb_ctx_readrcsection(ctx
, sname
, 3);