summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorGordon Ross <Gordon.Ross@Sun.COM>2009-07-02 12:58:38 -0400
committerGordon Ross <Gordon.Ross@Sun.COM>2009-07-02 12:58:38 -0400
commit613a2f6ba31e891e3d947a356daf5e563d43c1ce (patch)
tree0f7f3438a5792c05ed156a43e8cd84f25695d7f2 /usr/src
parentbf73eaa5a8ea69ac16a1e6e7b736f09286d073f9 (diff)
downloadillumos-joyent-613a2f6ba31e891e3d947a356daf5e563d43c1ce.tar.gz
6584198 SMB Client needs authentication improvements
6587713 Need to reconnect after server disconnect --HG-- rename : usr/src/lib/libsmbfs/netsmb/smbfs_isec.h => usr/src/lib/libsmbfs/smb/acl_nt.h
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/fs.d/smbclnt/Makefile16
-rw-r--r--usr/src/cmd/fs.d/smbclnt/lsacl/Makefile6
-rw-r--r--usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c9
-rw-r--r--usr/src/cmd/fs.d/smbclnt/mount/Makefile19
-rw-r--r--usr/src/cmd/fs.d/smbclnt/mount/mount.c193
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbiod/Makefile70
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbiod/smbiod.c362
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/Makefile31
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/common.h34
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/lookup.c9
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/print.c182
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/smbutil.c12
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/status.c19
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/view.c185
-rw-r--r--usr/src/cmd/mdb/common/modules/nsmb/nsmb.c66
-rw-r--r--usr/src/lib/Makefile1
-rw-r--r--usr/src/lib/libsmbfs/Makefile32
-rw-r--r--usr/src/lib/libsmbfs/Makefile.com38
-rw-r--r--usr/src/lib/libsmbfs/cflib.h15
-rw-r--r--usr/src/lib/libsmbfs/netsmb/nb_lib.h9
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smb_lib.h226
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smbfs_acl.h16
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smbfs_api.h158
-rw-r--r--usr/src/lib/libsmbfs/smb/acl_api.c6
-rw-r--r--usr/src/lib/libsmbfs/smb/acl_conv.c15
-rw-r--r--usr/src/lib/libsmbfs/smb/acl_nt.h (renamed from usr/src/lib/libsmbfs/netsmb/smbfs_isec.h)22
-rw-r--r--usr/src/lib/libsmbfs/smb/acl_print.c7
-rw-r--r--usr/src/lib/libsmbfs/smb/cfopt.c25
-rw-r--r--usr/src/lib/libsmbfs/smb/charsets.c2
-rw-r--r--usr/src/lib/libsmbfs/smb/charsets.h4
-rw-r--r--usr/src/lib/libsmbfs/smb/connect.c535
-rw-r--r--usr/src/lib/libsmbfs/smb/crypt.c175
-rw-r--r--usr/src/lib/libsmbfs/smb/ctx.c1880
-rw-r--r--usr/src/lib/libsmbfs/smb/derparse.c16
-rw-r--r--usr/src/lib/libsmbfs/smb/file.c120
-rw-r--r--usr/src/lib/libsmbfs/smb/findvc.c139
-rw-r--r--usr/src/lib/libsmbfs/smb/getaddr.c215
-rw-r--r--usr/src/lib/libsmbfs/smb/iod_cl.c195
-rw-r--r--usr/src/lib/libsmbfs/smb/iod_wk.c176
-rw-r--r--usr/src/lib/libsmbfs/smb/keychain.c204
-rw-r--r--usr/src/lib/libsmbfs/smb/krb5ssp.c535
-rw-r--r--usr/src/lib/libsmbfs/smb/llib-lsmbfs11
-rw-r--r--usr/src/lib/libsmbfs/smb/mapfile-vers32
-rw-r--r--usr/src/lib/libsmbfs/smb/mbuf.c351
-rw-r--r--usr/src/lib/libsmbfs/smb/nb.c108
-rw-r--r--usr/src/lib/libsmbfs/smb/nb_name.c133
-rw-r--r--usr/src/lib/libsmbfs/smb/nb_net.c49
-rw-r--r--usr/src/lib/libsmbfs/smb/nb_ssn.c330
-rw-r--r--usr/src/lib/libsmbfs/smb/nbns_rq.c142
-rw-r--r--usr/src/lib/libsmbfs/smb/negprot.c428
-rw-r--r--usr/src/lib/libsmbfs/smb/netshareenum.c8
-rw-r--r--usr/src/lib/libsmbfs/smb/newvc.c118
-rw-r--r--usr/src/lib/libsmbfs/smb/nls.c41
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlm.c584
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlm.h65
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlmssp.c634
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlmssp.h76
-rw-r--r--usr/src/lib/libsmbfs/smb/print.c51
-rw-r--r--usr/src/lib/libsmbfs/smb/private.h147
-rw-r--r--usr/src/lib/libsmbfs/smb/rap.c5
-rw-r--r--usr/src/lib/libsmbfs/smb/rcfile.c426
-rw-r--r--usr/src/lib/libsmbfs/smb/rcfile_priv.h39
-rw-r--r--usr/src/lib/libsmbfs/smb/rq.c381
-rw-r--r--usr/src/lib/libsmbfs/smb/signing.c265
-rw-r--r--usr/src/lib/libsmbfs/smb/smb_crypt.h49
-rw-r--r--usr/src/lib/libsmbfs/smb/spnegoparse.c4
-rw-r--r--usr/src/lib/libsmbfs/smb/ssnsetup.c519
-rw-r--r--usr/src/lib/libsmbfs/smb/ssp.c395
-rw-r--r--usr/src/lib/libsmbfs/smb/ssp.h56
-rw-r--r--usr/src/lib/libsmbfs/smb/subr.c183
-rw-r--r--usr/src/lib/libsmbfs/smb/ui-sun.c111
-rw-r--r--usr/src/lib/libsmbfs/smb/utf_str.c66
-rw-r--r--usr/src/pkgdefs/SUNWsmbfsu/prototype_com4
-rw-r--r--usr/src/pkgdefs/etc/exception_list_i3863
-rw-r--r--usr/src/pkgdefs/etc/exception_list_sparc3
-rw-r--r--usr/src/tools/scripts/bfu.sh14
-rw-r--r--usr/src/uts/common/Makefile.files4
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/offsets.in121
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c1108
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h432
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_crypt.c662
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c566
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c862
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.c123
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h17
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c299
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h28
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c311
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c1444
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h26
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c151
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h50
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c515
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c1017
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c266
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs.h25
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c8
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c40
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h5
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c187
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c63
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h7
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c78
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c109
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c14
-rw-r--r--usr/src/uts/common/netsmb/mchain.h16
-rw-r--r--usr/src/uts/common/netsmb/netbios.h9
-rw-r--r--usr/src/uts/common/netsmb/smb.h24
-rw-r--r--usr/src/uts/common/netsmb/smb_dev.h360
-rw-r--r--usr/src/uts/intel/nsmb/Makefile6
-rw-r--r--usr/src/uts/intel/nsmb/ioc_check.ref128
-rw-r--r--usr/src/uts/sparc/nsmb/Makefile6
-rw-r--r--usr/src/uts/sparc/nsmb/ioc_check.ref128
113 files changed, 12465 insertions, 8560 deletions
diff --git a/usr/src/cmd/fs.d/smbclnt/Makefile b/usr/src/cmd/fs.d/smbclnt/Makefile
index 8845071f42..9e66620c60 100644
--- a/usr/src/cmd/fs.d/smbclnt/Makefile
+++ b/usr/src/cmd/fs.d/smbclnt/Makefile
@@ -18,20 +18,20 @@
#
# CDDL HEADER END
#
+
#
-#ident "%Z%%M% %I% %E% SMI"
-#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# cmd/fs.d/smbclnt/Makefile
+
#
-# cmd/fs.d/smbclnt contains the CIFS client commands
+# cmd/fs.d/smbclnt/Makefile
+# contains the CIFS client commands
#
include $(SRC)/Makefile.master
-SUBDIRS_CATALOG= smbutil mount umount
+SUBDIRS_CATALOG= smbutil smbiod mount umount
SUBDIRS= $(SUBDIRS_CATALOG) lsacl svc
# for messaging catalog files
@@ -50,9 +50,9 @@ catalog:= TARGET= catalog
.PARALLEL: $(SUBDIRS)
-install clean clobber: $(SUBDIRS)
+all install clean clobber lint: $(SUBDIRS)
-all lint catalog: $(SUBDIRS_CATALOG)
+catalog: $(SUBDIRS_CATALOG)
$(RM) $(POFILE)
cat $(POFILES) > $(POFILE)
diff --git a/usr/src/cmd/fs.d/smbclnt/lsacl/Makefile b/usr/src/cmd/fs.d/smbclnt/lsacl/Makefile
index 22ce8510c0..4fbb347a73 100644
--- a/usr/src/cmd/fs.d/smbclnt/lsacl/Makefile
+++ b/usr/src/cmd/fs.d/smbclnt/lsacl/Makefile
@@ -19,11 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
FSTYPE= smbfs
LIBPROG= lsacl
@@ -38,8 +36,6 @@ LDLIBS += -lsmbfs -lsec
CFLAGS += $(CCVERBOSE)
C99MODE= $(C99_ENABLE)
-CPPFLAGS += -I$(SRC)/lib/libsmbfs \
- -I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common
CLOBBERFILES += $(LIBPROG)
diff --git a/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c b/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c
index 9f73f8eb1e..1285251898 100644
--- a/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c
+++ b/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* This is the smbfs/lsacl command.
* (just for testing - not installed)
@@ -42,7 +40,6 @@
#include <unistd.h>
#include <string.h>
-#include <netsmb/smb_lib.h>
#include <netsmb/smbfs_acl.h>
char *progname;
@@ -81,7 +78,7 @@ main(int argc, char **argv)
error = smbfs_acl_getsd(fd, 7, &sd);
if (error) {
fprintf(stderr, "getsd: %s\n",
- smb_strerror(error));
+ strerror(error));
exit(1);
}
@@ -101,7 +98,7 @@ main(int argc, char **argv)
error = smbfs_acl_get(fd, &acl, &uid, &gid);
if (error) {
fprintf(stderr, "getacl: %s\n",
- smb_strerror(error));
+ strerror(error));
exit(1);
}
printf("Solaris security data:\n");
diff --git a/usr/src/cmd/fs.d/smbclnt/mount/Makefile b/usr/src/cmd/fs.d/smbclnt/mount/Makefile
index d23874bf57..5d5da5ec5c 100644
--- a/usr/src/cmd/fs.d/smbclnt/mount/Makefile
+++ b/usr/src/cmd/fs.d/smbclnt/mount/Makefile
@@ -19,10 +19,10 @@
# CDDL HEADER END
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
+
#
# cmd/fs.d/smbclnt/mount/Makefile
#
@@ -36,15 +36,20 @@ include ../../Makefile.fstype
OBJS= $(LIBPROG).o
SRCS= $(LIBPROG).c $(FSLIBSRC)
POFILE= $(LIBPROG).po
-
-LDLIBS += -lsmbfs -lscf
+CLOBBERFILES += $(LIBPROG)
CFLAGS += $(CCVERBOSE)
C99MODE= $(C99_ENABLE)
-CPPFLAGS += -I$(SRC)/lib/libsmbfs \
- -I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common
-CLOBBERFILES += $(LIBPROG)
+LDLIBS += -lsmbfs -lscf
+
+CPPFLAGS += -I$(SRC)/uts/common -I$(SRC)/lib/libsmbfs
+
+# uncomment these for dbx debugging
+#COPTFLAG = -g
+#CTF_FLAGS =
+#CTFCONVERT_O=
+#CTFMERGE_LIB=
.KEEP_STATE:
diff --git a/usr/src/cmd/fs.d/smbclnt/mount/mount.c b/usr/src/cmd/fs.d/smbclnt/mount/mount.c
index 61bc463321..9068d093b6 100644
--- a/usr/src/cmd/fs.d/smbclnt/mount/mount.c
+++ b/usr/src/cmd/fs.d/smbclnt/mount/mount.c
@@ -37,11 +37,6 @@
* Use is subject to license terms.
*/
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/errno.h>
-#include <sys/mount.h>
-
#include <stdio.h>
#include <string.h>
#include <strings.h>
@@ -57,33 +52,38 @@
#include <locale.h>
#include <libscf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <sys/mount.h>
#include <sys/mntent.h>
#include <sys/mnttab.h>
-#include <cflib.h>
-
-#include <netsmb/smb.h>
+/* This needs to know ctx->ct_dev_fd, etc. */
#include <netsmb/smb_lib.h>
#include <sys/fs/smbfs_mount.h>
#include "mntopts.h"
+extern char *optarg;
+extern int optind;
+
static char mount_point[MAXPATHLEN + 1];
static void usage(void);
-static int setsubopt(int, char *, struct smbfs_args *);
+static int setsubopt(smb_ctx_t *, struct smbfs_args *, int, char *);
/* smbfs options */
-#define MNTOPT_RETRY "retry"
-#define MNTOPT_TIMEOUT "timeout"
+#define MNTOPT_DOMAIN "domain"
+#define MNTOPT_USER "user"
#define MNTOPT_DIRPERMS "dirperms"
#define MNTOPT_FILEPERMS "fileperms"
#define MNTOPT_GID "gid"
#define MNTOPT_UID "uid"
#define MNTOPT_NOPROMPT "noprompt"
-#define OPT_RETRY 1
-#define OPT_TIMEOUT 2
+#define OPT_DOMAIN 1
+#define OPT_USER 2
#define OPT_DIRPERMS 3
#define OPT_FILEPERMS 4
#define OPT_GID 5
@@ -108,8 +108,8 @@ struct smbfsopts {
};
struct smbfsopts opts[] = {
- {MNTOPT_RETRY, OPT_RETRY},
- {MNTOPT_TIMEOUT, OPT_TIMEOUT},
+ {MNTOPT_DOMAIN, OPT_DOMAIN},
+ {MNTOPT_USER, OPT_USER},
{MNTOPT_DIRPERMS, OPT_DIRPERMS},
{MNTOPT_FILEPERMS, OPT_FILEPERMS},
{MNTOPT_GID, OPT_GID},
@@ -132,22 +132,20 @@ static int Oflg = 0; /* Overlay mounts */
static int qflg = 0; /* quiet - don't print warnings on bad options */
static int ro = 0; /* read-only mount */
static int noprompt = 0; /* don't prompt for password */
-static int retry = -1;
-static int timeout = -1;
#define RET_ERR 33
#define SERVICE "svc:/network/smb/client:default"
+struct smbfs_args mdata;
+struct mnttab mnt;
+char optbuf[MAX_MNTOPT_STR];
+
int
main(int argc, char *argv[])
{
- struct smb_ctx sctx, *ctx = &sctx;
- struct smbfs_args mdata;
+ struct smb_ctx *ctx = NULL;
struct stat st;
- int opt, error, mntflags;
- struct mnttab mnt;
- struct mnttab *mntp = &mnt;
- char optbuf[MAX_MNTOPT_STR];
+ int opt, error, err2, mntflags;
static char *fstype = MNTTYPE_SMBFS;
char *env, *state;
@@ -174,8 +172,9 @@ main(int argc, char *argv[])
fprintf(stderr,
gettext("mount_smbfs: service \"%s\" not enabled.\n"),
SERVICE);
- exit(1);
+ exit(RET_ERR);
}
+ free(state);
/* Debugging support. */
if ((env = getenv("SMBFS_DEBUG")) != NULL) {
@@ -186,22 +185,35 @@ main(int argc, char *argv[])
error = smb_lib_init();
if (error)
- exit(error);
+ exit(RET_ERR);
mnt.mnt_mntopts = optbuf;
mntflags = MS_DATA;
+
bzero(&mdata, sizeof (mdata));
+ mdata.version = SMBFS_VERSION; /* smbfs mount version */
mdata.uid = (uid_t)-1;
mdata.gid = (gid_t)-1;
mdata.caseopt = SMB_CS_NONE;
- error = smb_ctx_init(ctx, argc, argv, SMBL_SHARE, SMBL_SHARE,
- SMB_ST_DISK);
+ error = smb_ctx_alloc(&ctx);
if (error)
- exit(error);
+ exit(RET_ERR);
+
+ /*
+ * Parse the UNC path so we have the server (etc.)
+ * that we need during rcfile+sharectl parsing.
+ */
+ if (argc < 3)
+ usage();
+ error = smb_ctx_parseunc(ctx, argv[argc - 2],
+ SMBL_SHARE, SMBL_SHARE, USE_DISKDEV, NULL);
+ if (error)
+ exit(RET_ERR);
+
error = smb_ctx_readrc(ctx);
if (error)
- exit(error);
+ exit(RET_ERR);
while ((opt = getopt(argc, argv, "ro:Oq")) != -1) {
switch (opt) {
@@ -254,7 +266,8 @@ main(int argc, char *argv[])
*comma = ',';
continue;
}
- ret = setsubopt(opts[i].index, soptval, &mdata);
+ ret = setsubopt(ctx, &mdata,
+ opts[i].index, soptval);
if (ret != 0)
exit(RET_ERR);
if (equals)
@@ -280,24 +293,19 @@ main(int argc, char *argv[])
mntflags |= MS_RDONLY;
/* convert "rw"->"ro" */
- if (p = strstr(mntp->mnt_mntopts, "rw")) {
+ if (p = strstr(mnt.mnt_mntopts, "rw")) {
if (*(p+2) == ',' || *(p+2) == '\0')
*(p+1) = 'o';
}
}
+ if (optind + 2 != argc)
+ usage();
+
mnt.mnt_special = argv[optind];
mnt.mnt_mountp = argv[optind+1];
- mdata.version = SMBFS_VERSION; /* smbfs mount version */
-
- if (optind == argc - 2)
- optind++;
-
- if (optind != argc - 1)
- usage();
- realpath(unpercent(argv[optind]), mount_point);
-
+ realpath(argv[optind+1], mount_point);
if (stat(mount_point, &st) == -1)
err(EX_OSERR, gettext("could not find mount point %s"),
mount_point);
@@ -325,90 +333,76 @@ main(int argc, char *argv[])
mdata.dir_mode |= S_IXOTH;
}
- /*
- * XXX: The driver can fill these in more reliably,
- * so why do we set them here? (Just set both = -1)
- */
- ctx->ct_ssn.ioc_owner = ctx->ct_sh.ioc_owner = getuid();
- ctx->ct_ssn.ioc_group = ctx->ct_sh.ioc_group = getgid();
- opt = 0;
- if (mdata.dir_mode & S_IXGRP)
- opt |= SMBM_EXECGRP;
- if (mdata.dir_mode & S_IXOTH)
- opt |= SMBM_EXECOTH;
- ctx->ct_ssn.ioc_rights |= opt;
- ctx->ct_sh.ioc_rights |= opt;
+ ctx->ct_ssn.ssn_owner = SMBM_ANY_OWNER;
if (noprompt)
ctx->ct_flags |= SMBCF_NOPWD;
- if (retry != -1)
- ctx->ct_ssn.ioc_retrycount = retry;
- if (timeout != -1)
- ctx->ct_ssn.ioc_timeout = timeout;
/*
- * If we got our password from the keychain and get an
- * authorization error, we come back here to obtain a new
- * password from user input.
+ * Resolve the server address,
+ * setup derived defaults.
*/
-reauth:
error = smb_ctx_resolve(ctx);
if (error)
- exit(error);
-
- mdata.devfd = ctx->ct_fd; /* file descriptor */
+ exit(RET_ERR);
+ /*
+ * Have server, share, etc. from above:
+ * smb_ctx_scan_argv, option settings.
+ * Get the session and tree.
+ */
again:
- error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE);
- if (error == ENOENT && ctx->ct_origshare) {
- strcpy(ctx->ct_sh.ioc_share, ctx->ct_origshare);
- free(ctx->ct_origshare);
- ctx->ct_origshare = NULL;
- goto again; /* try again using share name as given */
+ error = smb_ctx_get_ssn(ctx);
+ if (error == EAUTH && noprompt == 0) {
+ err2 = smb_get_authentication(ctx);
+ if (err2 == 0)
+ goto again;
}
- if (ctx->ct_flags & SMBCF_KCFOUND && smb_autherr(error)) {
- ctx->ct_ssn.ioc_password[0] = '\0';
- smb_error(gettext("main(lookup): bad keychain entry"), 0);
- ctx->ct_flags |= SMBCF_KCBAD;
- goto reauth;
+ if (error) {
+ smb_error(gettext("//%s: login failed"),
+ error, ctx->ct_fullserver);
+ exit(RET_ERR);
+ }
+
+ error = smb_ctx_get_tree(ctx);
+ if (error) {
+ smb_error(gettext("//%s/%s: tree connect failed"),
+ error, ctx->ct_fullserver, ctx->ct_origshare);
+ exit(RET_ERR);
}
- if (error)
- exit(error);
- mdata.version = SMBFS_VERSION;
- mdata.devfd = ctx->ct_fd;
+ /*
+ * Have tree connection, now mount it.
+ */
+ mdata.devfd = ctx->ct_dev_fd;
- if (mount(mntp->mnt_special, mntp->mnt_mountp,
+ if (mount(mnt.mnt_special, mnt.mnt_mountp,
mntflags, fstype, &mdata, sizeof (mdata),
- mntp->mnt_mntopts, MAX_MNTOPT_STR) < 0) {
+ mnt.mnt_mntopts, MAX_MNTOPT_STR) < 0) {
if (errno != ENOENT) {
err(EX_OSERR, gettext("mount_smbfs: %s"),
- mntp->mnt_mountp);
+ mnt.mnt_mountp);
} else {
struct stat sb;
- if (stat(mntp->mnt_mountp, &sb) < 0 &&
+ if (stat(mnt.mnt_mountp, &sb) < 0 &&
errno == ENOENT)
err(EX_OSERR, gettext("mount_smbfs: %s"),
- mntp->mnt_mountp);
+ mnt.mnt_mountp);
else
err(EX_OSERR, gettext("mount_smbfs: %s"),
- mntp->mnt_special);
-
- error = smb_ctx_tdis(ctx);
- if (error) /* unable to clean up?! */
- exit(error);
+ mnt.mnt_special);
}
}
- smb_ctx_done(ctx);
+ smb_ctx_free(ctx);
if (error) {
smb_error(gettext("mount error: %s"), error, mount_point);
- exit(errno);
+ exit(RET_ERR);
}
return (0);
}
int
-setsubopt(int index, char *optarg, struct smbfs_args *mdatap)
+setsubopt(smb_ctx_t *ctx, struct smbfs_args *mdatap, int index, char *optarg)
{
struct passwd *pwd;
struct group *grp;
@@ -429,6 +423,15 @@ setsubopt(int index, char *optarg, struct smbfs_args *mdatap)
case OPT_NOEXEC:
/* We don't have to handle generic options here */
return (0);
+
+ case OPT_DOMAIN:
+ err = smb_ctx_setdomain(ctx, optarg, B_TRUE);
+ break;
+
+ case OPT_USER:
+ err = smb_ctx_setuser(ctx, optarg, B_TRUE);
+ break;
+
case OPT_UID:
pwd = isdigit(optarg[0]) ?
getpwuid(atoi(optarg)) : getpwnam(optarg);
@@ -474,12 +477,6 @@ setsubopt(int index, char *optarg, struct smbfs_args *mdatap)
mdatap->file_mode = l;
}
break;
- case OPT_RETRY:
- retry = atoi(optarg);
- break;
- case OPT_TIMEOUT:
- timeout = atoi(optarg);
- break;
case OPT_NOPROMPT:
noprompt++;
}
diff --git a/usr/src/cmd/fs.d/smbclnt/smbiod/Makefile b/usr/src/cmd/fs.d/smbclnt/smbiod/Makefile
new file mode 100644
index 0000000000..626304a88a
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/smbiod/Makefile
@@ -0,0 +1,70 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# cmd/fs.d/smbclnt/smbiod/Makefile
+#
+
+FSTYPE= smbfs
+TYPEPROG= smbiod
+
+include ../../Makefile.fstype
+
+OBJS= $(TYPEPROG).o
+SRCS= $(TYPEPROG).c
+POFILE= $(TYPEPROG).po
+
+CLOBBERFILES += $(TYPEPROG)
+
+CFLAGS += $(CCVERBOSE)
+C99MODE= $(C99_ENABLE)
+
+# This is a multi-thread program but Nevada
+# no longer needs -lthread
+LDLIBS += -lsmbfs -ldoor
+
+CPPFLAGS += -I$(SRC)/lib/libsmbfs \
+ -I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common
+
+# Debugging
+${NOT_RELEASE_BUILD} CPPFLAGS += -DDEBUG
+
+# uncomment these for dbx debugging
+#COPTFLAG = -g
+#CTF_FLAGS =
+#CTFCONVERT_O=
+#CTFMERGE_LIB=
+
+all: $(TYPEPROG)
+
+catalog: $(POFILE)
+
+lint: lint_SRCS
+
+clean:
+ $(RM) $(OBJS) $(POFILE)
+
+.KEEP_STATE:
diff --git a/usr/src/cmd/fs.d/smbclnt/smbiod/smbiod.c b/usr/src/cmd/fs.d/smbclnt/smbiod/smbiod.c
new file mode 100644
index 0000000000..27677874ac
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/smbiod/smbiod.c
@@ -0,0 +1,362 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * SMBFS I/O Deamon (smbiod)
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/note.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <synch.h>
+#include <time.h>
+#include <unistd.h>
+#include <ucred.h>
+
+#include <err.h>
+#include <door.h>
+#include <thread.h>
+
+#include <netsmb/smb_lib.h>
+
+#define ALARM_TIME 30 /* sec. */
+#define EXIT_FAIL 1
+#define EXIT_OK 0
+
+#if defined(DEBUG) || defined(__lint)
+#define DPRINT(...) do \
+{ \
+ if (smb_debug) \
+ fprintf(stderr, __VA_ARGS__); \
+ _NOTE(CONSTCOND) \
+} while (0)
+#else
+#define DPRINT(...) ((void)0)
+#endif
+
+mutex_t iod_mutex = DEFAULTMUTEX;
+int iod_thr_count; /* threads, excluding main */
+int iod_terminating;
+
+void iod_dispatch(void *cookie, char *argp, size_t argsz,
+ door_desc_t *dp, uint_t n_desc);
+int iod_newvc(smb_iod_ssn_t *clnt_ssn);
+void * iod_work(void *arg);
+
+int
+main(int argc, char **argv)
+{
+ static const int door_attrs =
+ DOOR_REFUSE_DESC | DOOR_NO_CANCEL;
+ sigset_t oldmask, tmpmask;
+ char *env, *door_path = NULL;
+ int door_fd = -1, tmp_fd = -1;
+ int err, i, sig;
+ int rc = EXIT_FAIL;
+
+ /* Debugging support. */
+ if ((env = getenv("SMBFS_DEBUG")) != NULL) {
+ smb_debug = atoi(env);
+ if (smb_debug < 1)
+ smb_debug = 1;
+ }
+
+ /*
+ * Find out if an IOD is already running.
+ * If so, we lost a harmless startup race.
+ * An IOD did start, so exit success.
+ */
+ err = smb_iod_open_door(&door_fd);
+ if (err == 0) {
+ close(door_fd);
+ door_fd = -1;
+ DPRINT("main: already running\n");
+ exit(EXIT_OK);
+ }
+
+ /*
+ * Create a file for the door.
+ */
+ door_path = smb_iod_door_path();
+ unlink(door_path);
+ tmp_fd = open(door_path, O_RDWR|O_CREAT|O_EXCL, 0600);
+ if (tmp_fd < 0) {
+ perror(door_path);
+ exit(EXIT_FAIL);
+ }
+ close(tmp_fd);
+ tmp_fd = -1;
+
+
+ /*
+ * Close FDs 0,1,2 so we don't have a TTY, and
+ * re-open them on /dev/null so they won't be
+ * used for device handles (etc.) later, and
+ * we don't have to worry about printf calls
+ * or whatever going to these FDs.
+ */
+ for (i = 0; i < 3; i++) {
+ /* Exception: If smb_debug, keep stderr */
+ if (smb_debug && i == 2)
+ break;
+ close(i);
+ tmp_fd = open("/dev/null", O_RDWR);
+ if (tmp_fd < 0)
+ perror("/dev/null");
+ if (tmp_fd != i)
+ DPRINT("Open /dev/null - wrong fd?\n");
+ }
+
+ /*
+ * Become session leader.
+ */
+ setsid();
+
+ /*
+ * Create door service threads with signals blocked.
+ */
+ sigfillset(&tmpmask);
+ sigprocmask(SIG_BLOCK, &tmpmask, &oldmask);
+
+ /* Setup the door service. */
+ door_fd = door_create(iod_dispatch, NULL, door_attrs);
+ if (door_fd < 0) {
+ fprintf(stderr, "%s: door_create failed\n", argv[0]);
+ rc = EXIT_FAIL;
+ goto errout;
+ }
+ fdetach(door_path);
+ if (fattach(door_fd, door_path) < 0) {
+ fprintf(stderr, "%s: fattach failed\n", argv[0]);
+ rc = EXIT_FAIL;
+ goto errout;
+ }
+
+ /*
+ * Post the initial alarm, and then just
+ * wait for signals.
+ */
+ alarm(ALARM_TIME);
+again:
+ sig = sigwait(&tmpmask);
+ DPRINT("main: sig=%d\n", sig);
+
+ /*
+ * If a door call races with the alarm, ignore the alarm.
+ * It will be rescheduled when the threads go away.
+ */
+ mutex_lock(&iod_mutex);
+ if (sig == SIGALRM && iod_thr_count > 0) {
+ mutex_unlock(&iod_mutex);
+ goto again;
+ }
+ iod_terminating = 1;
+ mutex_unlock(&iod_mutex);
+ rc = EXIT_OK;
+
+errout:
+ fdetach(door_path);
+ door_revoke(door_fd);
+ door_fd = -1;
+ unlink(door_path);
+
+ return (rc);
+}
+
+/*ARGSUSED*/
+void
+iod_dispatch(void *cookie, char *argp, size_t argsz,
+ door_desc_t *dp, uint_t n_desc)
+{
+ smb_iod_ssn_t *ssn;
+ ucred_t *ucred;
+ uid_t cl_uid;
+ int rc;
+
+ /*
+ * Verify that the calling process has the same UID.
+ * Paranoia: The door we created has mode 0600, so
+ * this check is probably redundant.
+ */
+ ucred = NULL;
+ if (door_ucred(&ucred) != 0) {
+ rc = EACCES;
+ goto out;
+ }
+ cl_uid = ucred_getruid(ucred);
+ ucred_free(ucred);
+ ucred = NULL;
+ if (cl_uid != getuid()) {
+ DPRINT("iod_dispatch: wrong UID\n");
+ rc = EACCES;
+ goto out;
+ }
+
+ /*
+ * The library uses a NULL arg call to check if
+ * the deamon is running. Just return zero.
+ */
+ if (argp == NULL) {
+ rc = 0;
+ goto out;
+ }
+
+ /*
+ * Otherwise, the arg must be the (fixed size)
+ * smb_iod_ssn_t
+ */
+ if (argsz != sizeof (*ssn)) {
+ rc = EINVAL;
+ goto out;
+ }
+
+ mutex_lock(&iod_mutex);
+ if (iod_terminating) {
+ mutex_unlock(&iod_mutex);
+ DPRINT("iod_dispatch: terminating\n");
+ rc = EINTR;
+ goto out;
+ }
+ if (iod_thr_count++ == 0) {
+ alarm(0);
+ DPRINT("iod_dispatch: cancelled alarm\n");
+ }
+ mutex_unlock(&iod_mutex);
+
+ ssn = (void *) argp;
+ rc = iod_newvc(ssn);
+
+ mutex_lock(&iod_mutex);
+ if (--iod_thr_count == 0) {
+ DPRINT("iod_dispatch: schedule alarm\n");
+ alarm(ALARM_TIME);
+ }
+ mutex_unlock(&iod_mutex);
+
+out:
+ door_return((void *)&rc, sizeof (rc), NULL, 0);
+}
+
+/*
+ * Try making a connection with the server described by
+ * the info in the smb_iod_ssn_t arg. If successful,
+ * start an IOD thread to service it, then return to
+ * the client side of the door.
+ */
+int
+iod_newvc(smb_iod_ssn_t *clnt_ssn)
+{
+ smb_ctx_t *ctx;
+ thread_t tid;
+ int err;
+
+
+ /*
+ * This needs to essentially "clone" the smb_ctx_t
+ * from the client side of the door, or at least
+ * as much of it as we need while creating a VC.
+ */
+ err = smb_ctx_alloc(&ctx);
+ if (err)
+ return (err);
+ bcopy(clnt_ssn, &ctx->ct_iod_ssn, sizeof (ctx->ct_iod_ssn));
+
+ /*
+ * Do the initial connection setup here, so we can
+ * report the outcome to the door client.
+ */
+ err = smb_iod_connect(ctx);
+ if (err != 0)
+ goto out;
+
+ /*
+ * Create the driver session now, so we don't
+ * race with the door client findvc call.
+ */
+ if ((err = smb_ctx_gethandle(ctx)) != 0)
+ goto out;
+ if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_CREATE, &ctx->ct_ssn) < 0) {
+ err = errno;
+ goto out;
+ }
+
+ /* The rest happens in the iod_work thread. */
+ err = thr_create(NULL, 0, iod_work, ctx, THR_DETACHED, &tid);
+ if (err == 0) {
+ /*
+ * Given to the new thread.
+ * free at end of iod_work
+ */
+ ctx = NULL;
+ }
+
+out:
+ if (ctx)
+ smb_ctx_free(ctx);
+
+ return (err);
+}
+
+/*
+ * Be the reader thread for some VC.
+ *
+ * This is started by a door call thread, which means
+ * this is always at least the 2nd thread, therefore
+ * it should never see thr_count==0 or terminating.
+ */
+void *
+iod_work(void *arg)
+{
+ smb_ctx_t *ctx = arg;
+
+ mutex_lock(&iod_mutex);
+ if (iod_thr_count++ == 0) {
+ alarm(0);
+ DPRINT("iod_work: cancelled alarm\n");
+ }
+ mutex_unlock(&iod_mutex);
+
+ (void) smb_iod_work(ctx);
+
+ mutex_lock(&iod_mutex);
+ if (--iod_thr_count == 0) {
+ DPRINT("iod_work: schedule alarm\n");
+ alarm(ALARM_TIME);
+ }
+ mutex_unlock(&iod_mutex);
+
+ smb_ctx_free(ctx);
+ return (NULL);
+}
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile b/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile
index 9d6017b35b..31d52961fe 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile
@@ -18,11 +18,12 @@
#
# CDDL HEADER END
#
+
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
+
#
# cmd/fs.d/smbclnt/smbutil/Makefile
#
@@ -32,14 +33,31 @@ PROG= smbutil
include $(SRC)/cmd/Makefile.cmd
OBJS= smbutil.o login.o lookup.o print.o status.o view.o
+
SRCS= $(OBJS:%.o=%.c)
POFILE= smbutil_all.po
POFILES= $(OBJS:%.o=%.po)
+CLOBBERFILES+= $(POFILE) $(POFILES)
C99MODE= $(C99_ENABLE)
+
+LDLIBS += -lsmbfs -lnsl
+
CPPFLAGS += -I$(SRC)/lib/libsmbfs \
-I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common
-LDLIBS += -lsmbfs -lnsl
+
+# Debugging
+${NOT_RELEASE_BUILD} CPPFLAGS += -DDEBUG
+
+# uncomment these for dbx debugging
+#COPTFLAG = -g
+#CTF_FLAGS =
+#CTFCONVERT_O=
+#CTFMERGE_LIB=
+
+# disable some of the less important lint
+LINTFLAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2
+LINTFLAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2
all: $(PROG)
@@ -58,8 +76,11 @@ $(POFILE): $(POFILES)
$(RM) $@
$(CAT) $(POFILES) > $@
+lint: lint_SRCS
+
clean :
$(RM) $(OBJS)
-clobber: clean
- $(RM) $(PROG) $(POFILES)
+.KEEP_STATE:
+
+include ../../../Makefile.targ
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/common.h b/usr/src/cmd/fs.d/smbclnt/smbutil/common.h
index 280c4744f4..24cb1436a0 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/common.h
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/common.h
@@ -1,8 +1,38 @@
+/*
+ * Copyright (c) 2000, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
#ifndef _SMBUTIL_COMMON_H
#define _SMBUTIL_COMMON_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/lookup.c b/usr/src/cmd/fs.d/smbclnt/smbutil/lookup.c
index 199d785277..5e8049e71b 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/lookup.c
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/lookup.c
@@ -32,7 +32,10 @@
* $Id: lookup.c,v 1.1.1.1 2001/06/09 00:28:13 zarzycki Exp $
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
#include <sys/param.h>
#include <sys/errno.h>
@@ -74,9 +77,9 @@ cmd_lookup(int argc, char *argv[])
exit(1);
}
if (smb_open_rcfile(NULL) == 0) {
- if (nb_ctx_readrcsection(smb_rc, ctx, "default", 0) != 0)
+ if (nb_ctx_readrcsection(NULL, ctx, "default", 0) != 0)
exit(1);
- rc_close(smb_rc);
+ smb_close_rcfile();
}
if ((ctx->nb_flags & NBCF_NS_ENABLE) == 0) {
fprintf(stderr,
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/print.c b/usr/src/cmd/fs.d/smbclnt/smbutil/print.c
index dd986e1b49..7379acfd90 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/print.c
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/print.c
@@ -29,21 +29,22 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: print.c,v 1.7 2004/03/19 01:49:48 lindak Exp $
+ * from: Id: print.c,v 1.4 2001/01/28 07:35:01 bp Exp
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
-#include <sys/param.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
+#include <sys/types.h>
+#include <err.h>
+#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
-#include <err.h>
-#include <unistd.h>
-#include <strings.h>
+#include <string.h>
#include <stdlib.h>
-#include <sysexits.h>
+#include <unistd.h>
#include <libintl.h>
#include <cflib.h>
@@ -52,13 +53,174 @@
#include "common.h"
+static char titlebuf[256];
+static char databuf[4096];
+static int print_file(smb_ctx_t *, char *, int);
void
print_usage(void)
{
printf(gettext("usage: smbutil print [connection options] //"
"[workgroup;][user[:password]@]"
- "server/share\n"));
+ "server/share {print_file|-}\n"));
exit(1);
}
+
+int
+cmd_print(int argc, char *argv[])
+{
+ struct smb_ctx *ctx = NULL;
+ char *filename;
+ int error, opt;
+ int file = -1;
+
+ /* last arg is the print file. */
+ if (argc < 3)
+ print_usage();
+
+ error = smb_ctx_alloc(&ctx);
+ if (error)
+ goto out;
+
+ error = smb_ctx_scan_argv(ctx, argc-1, argv,
+ SMBL_SHARE, SMBL_SHARE, USE_SPOOLDEV);
+ if (error)
+ goto out;
+
+ error = smb_ctx_readrc(ctx);
+ if (error)
+ goto out;
+
+ while ((opt = getopt(argc-1, argv, STDPARAM_OPT)) != EOF) {
+ if (opt == '?')
+ print_usage();
+ error = smb_ctx_opt(ctx, opt, optarg);
+ if (error)
+ goto out;
+ }
+ if (optind != argc-2)
+ print_usage();
+ filename = argv[argc-1];
+
+ if (strcmp(filename, "-") == 0) {
+ file = 0; /* stdin */
+ filename = "stdin";
+ } else {
+ file = open(filename, O_RDONLY, 0);
+ if (file < 0) {
+ smb_error("could not open file %s\n", errno, filename);
+ exit(1);
+ }
+ }
+
+ /*
+ * Resolve the server address,
+ * setup derived defaults.
+ */
+ error = smb_ctx_resolve(ctx);
+ if (error)
+ goto out;
+
+ /*
+ * Have server + share names, options etc.
+ * Get the session and tree.
+ */
+again:
+ error = smb_ctx_get_ssn(ctx);
+ if (error == EAUTH) {
+ int err2 = smb_get_authentication(ctx);
+ if (err2 == 0)
+ goto again;
+ }
+ if (error) {
+ smb_error(gettext("//%s: login failed"),
+ error, ctx->ct_fullserver);
+ goto out;
+ }
+
+ error = smb_ctx_get_tree(ctx);
+ if (error) {
+ smb_error(gettext("//%s/%s: tree connect failed"),
+ error, ctx->ct_fullserver, ctx->ct_origshare);
+ goto out;
+ }
+
+ /*
+ * Have the printer share connection.
+ * Print the file.
+ */
+ snprintf(titlebuf, sizeof (titlebuf), "%s_%s",
+ ctx->ct_user, filename);
+
+ error = print_file(ctx, titlebuf, file);
+
+
+out:
+ /* don't close stdin (file=0) */
+ if (file > 0)
+ close(file);
+
+ smb_ctx_free(ctx);
+
+ return (error);
+}
+
+/*
+ * Documentation for OPEN_PRINT_FILE is scarse.
+ * It's in a 1996 MS doc. entitled:
+ * SMB FILE SHARING PROTOCOL
+ *
+ * The extra parameters are:
+ * SetupLength: what part of the file is printer setup
+ * Mode: text or graphics (raw data)
+ * IdentifierString: job title
+ */
+enum {
+ MODE_TEXT = 0, /* TAB expansion, etc. */
+ MODE_GRAPHICS /* raw data */
+};
+
+static int
+print_file(smb_ctx_t *ctx, char *title, int file)
+{
+ off_t offset;
+ int error, rcnt, wcnt;
+ int setup_len = 0; /* No printer setup data */
+ int mode = MODE_GRAPHICS; /* treat as raw data */
+ int fh = -1;
+
+ error = smb_printer_open(ctx, setup_len, mode, title, &fh);
+ if (error) {
+ smb_error("could not open print job", error);
+ return (error);
+ }
+
+ offset = 0;
+ for (;;) {
+ rcnt = read(file, databuf, sizeof (databuf));
+ if (rcnt < 0) {
+ error = errno;
+ smb_error("error reading input file\n", error);
+ break;
+ }
+ if (rcnt == 0)
+ break;
+
+ wcnt = smb_fh_write(ctx, fh, offset, rcnt, databuf);
+ if (wcnt < 0) {
+ error = errno;
+ smb_error("error writing spool file\n", error);
+ break;
+ }
+ if (wcnt != rcnt) {
+ smb_error("incomplete write to spool file\n", 0);
+ error = EIO;
+ break;
+ }
+ offset += wcnt;
+ }
+
+ (void) smb_printer_close(ctx, fh);
+ return (error);
+}
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/smbutil.c b/usr/src/cmd/fs.d/smbclnt/smbutil/smbutil.c
index ca5eeb425d..404b436d16 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/smbutil.c
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/smbutil.c
@@ -31,7 +31,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -74,7 +74,8 @@ static struct commands {
{"logout", cmd_logout, logout_usage, 0},
{"logoutall", cmd_logoutall, logoutall_usage, 0},
{"lookup", cmd_lookup, lookup_usage, CMDFL_NO_KMOD},
- {"status", cmd_status, status_usage, 0},
+ {"print", cmd_print, print_usage, 0},
+ {"status", cmd_status, status_usage, CMDFL_NO_KMOD},
{"view", cmd_view, view_usage, 0},
{NULL, NULL, NULL, 0}
};
@@ -134,7 +135,7 @@ main(int argc, char *argv[])
{
struct commands *cmd;
char *cp;
- int opt;
+ int err, opt;
(void) setlocale(LC_ALL, "");
(void) textdomain(TEXT_DOMAIN);
@@ -176,7 +177,8 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
optind = 1;
- return (cmd->fn(argc, argv));
+ err = cmd->fn(argc, argv);
+ return ((err) ? 1 : 0);
}
static void
@@ -191,7 +193,7 @@ help(void) {
" logout logout from specified host\n"
" logoutall logout all users (requires privilege)\n"
" lookup resolve NetBIOS name to IP address\n"
- /* " print print file to the specified remote printer\n" */
+ " print print file to the specified remote printer\n"
" status resolve IP address or DNS name to NetBIOS names\n"
" view list resources on specified host\n"
"\n"));
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/status.c b/usr/src/cmd/fs.d/smbclnt/smbutil/status.c
index 9353c69e16..9707becaa6 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/status.c
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/status.c
@@ -32,7 +32,10 @@
* $Id: status.c,v 1.2 2001/08/18 05:44:50 conrad Exp $
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
#include <sys/param.h>
#include <sys/errno.h>
@@ -62,10 +65,10 @@ int
cmd_status(int argc, char *argv[])
{
struct nb_ctx *ctx;
- struct sockaddr *sap;
+ struct in_addr ina;
char *hostname;
- char servername[SMB_MAXSRVNAMELEN + 1];
- char workgroupname[SMB_MAXUSERNAMELEN + 1];
+ char servername[NB_NAMELEN];
+ char workgroupname[NB_NAMELEN];
int error, opt;
if (argc < 2)
@@ -76,9 +79,9 @@ cmd_status(int argc, char *argv[])
exit(1);
}
if (smb_open_rcfile(NULL) == 0) {
- if (nb_ctx_readrcsection(smb_rc, ctx, "default", 0) != 0)
+ if (nb_ctx_readrcsection(NULL, ctx, "default", 0) != 0)
exit(1);
- rc_close(smb_rc);
+ smb_close_rcfile();
}
while ((opt = getopt(argc, argv, "")) != EOF) {
switch (opt) {
@@ -91,7 +94,7 @@ cmd_status(int argc, char *argv[])
status_usage();
hostname = argv[argc - 1];
- error = nb_resolvehost_in(hostname, &sap);
+ error = nb_resolvehost_in(hostname, &ina);
if (error) {
smb_error(gettext(
"unable to resolve DNS hostname %s"), error, hostname);
@@ -104,7 +107,7 @@ cmd_status(int argc, char *argv[])
}
servername[0] = (char)0;
workgroupname[0] = (char)0;
- error = nbns_getnodestatus(sap, ctx, servername, workgroupname);
+ error = nbns_getnodestatus(ctx, &ina, servername, workgroupname);
if (error) {
smb_error(
gettext("unable to get status from %s"), error, hostname);
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/view.c b/usr/src/cmd/fs.d/smbclnt/smbutil/view.c
index 035d15132d..365e5b6f37 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/view.c
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/view.c
@@ -32,9 +32,13 @@
* $Id: view.c,v 1.9 2004/12/13 00:25:39 lindak Exp $
*/
-#include <sys/param.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
#include <stdio.h>
#include <err.h>
#include <unistd.h>
@@ -43,12 +47,101 @@
#include <sysexits.h>
#include <libintl.h>
-#include <cflib.h>
+#include <netsmb/smb.h>
#include <netsmb/smb_lib.h>
#include <netsmb/smb_netshareenum.h>
#include "common.h"
+int enum_shares(smb_ctx_t *);
+void print_shares(int, int, struct share_info *);
+
+void
+view_usage(void)
+{
+ printf(gettext("usage: smbutil view [connection options] //"
+ "[workgroup;][user[:password]@]server\n"));
+ exit(1);
+}
+
+int
+cmd_view(int argc, char *argv[])
+{
+ struct smb_ctx *ctx;
+ int error, err2, opt;
+
+ if (argc < 2)
+ view_usage();
+
+ error = smb_ctx_alloc(&ctx);
+ if (error)
+ return (error);
+
+ error = smb_ctx_scan_argv(ctx, argc, argv,
+ SMBL_SERVER, SMBL_SERVER, USE_WILDCARD);
+ if (error)
+ return (error);
+
+ error = smb_ctx_readrc(ctx);
+ if (error)
+ return (error);
+
+ while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) {
+ if (opt == '?')
+ view_usage();
+ error = smb_ctx_opt(ctx, opt, optarg);
+ if (error)
+ return (error);
+ }
+
+ smb_ctx_setshare(ctx, "IPC$", USE_IPC);
+
+ /*
+ * Resolve the server address,
+ * setup derived defaults.
+ */
+ error = smb_ctx_resolve(ctx);
+ if (error)
+ return (error);
+
+ /*
+ * Have server, share, etc. from above:
+ * smb_ctx_scan_argv, option settings.
+ * Get the session and tree.
+ */
+again:
+ error = smb_ctx_get_ssn(ctx);
+ if (error == EAUTH) {
+ err2 = smb_get_authentication(ctx);
+ if (err2 == 0)
+ goto again;
+ }
+ if (error) {
+ smb_error(gettext("//%s: login failed"),
+ error, ctx->ct_fullserver);
+ return (error);
+ }
+
+ error = smb_ctx_get_tree(ctx);
+ if (error) {
+ smb_error(gettext("//%s/%s: tree connect failed"),
+ error, ctx->ct_fullserver, ctx->ct_origshare);
+ return (error);
+ }
+
+ /*
+ * Have IPC$ tcon, now list shares.
+ */
+ error = enum_shares(ctx);
+ if (error) {
+ smb_error("cannot list shares", error);
+ return (error);
+ }
+
+ smb_ctx_free(ctx);
+ return (0);
+}
+
#ifdef I18N /* not defined, put here so xgettext(1) can find strings */
static char *shtype[] = {
gettext("disk"),
@@ -68,60 +161,34 @@ static char *shtype[] = {
#endif
int
-cmd_view(int argc, char *argv[])
+enum_shares(smb_ctx_t *ctx)
{
- struct smb_ctx sctx, *ctx = &sctx;
- struct share_info *share_info, *ep;
- int error, opt, i, entries, total;
+ struct share_info *share_info;
+ int error, entries, total;
- if (argc < 2)
- view_usage();
- error = smb_ctx_init(ctx, argc, argv, SMBL_VC, SMBL_VC, SMB_ST_ANY);
- if (error)
- exit(error);
- error = smb_ctx_readrc(ctx);
- if (error)
- exit(error);
- if (smb_rc)
- rc_close(smb_rc);
- while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) {
- switch (opt) {
- case STDPARAM_ARGS:
- error = smb_ctx_opt(ctx, opt, optarg);
- if (error)
- exit(error);
- break;
- default:
- view_usage();
- /*NOTREACHED*/
- }
- }
-#ifdef APPLE
- if (loadsmbvfs())
- fprintf(stderr, gettext("SMB filesystem is not available"));
-#endif
-reauth:
- smb_ctx_setshare(ctx, "IPC$", SMB_ST_ANY);
- error = smb_ctx_resolve(ctx);
- if (error)
- exit(error);
- error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE);
- if (ctx->ct_flags & SMBCF_KCFOUND && smb_autherr(error)) {
- ctx->ct_ssn.ioc_password[0] = '\0';
- goto reauth;
- }
- if (error) {
- smb_error(gettext("could not login to server %s"),
- error, ctx->ct_ssn.ioc_srvname);
- exit(error);
- }
- printf(gettext("Share Type Comment\n"));
- printf("-------------------------------\n");
+ /*
+ * XXX: Later, try RPC first,
+ * then fall back to RAP...
+ */
error = smb_netshareenum(ctx, &entries, &total, &share_info);
if (error) {
smb_error(gettext("unable to list resources"), error);
- exit(error);
+ return (error);
}
+ print_shares(entries, total, share_info);
+ return (0);
+}
+
+void
+print_shares(int entries, int total,
+ struct share_info *share_info)
+{
+ struct share_info *ep;
+ int i;
+
+ printf(gettext("Share Type Comment\n"));
+ printf("-------------------------------\n");
+
for (ep = share_info, i = 0; i < entries; i++, ep++) {
int sti = ep->type & STYPE_MASK;
if (sti > STYPE_UNKNOWN)
@@ -136,18 +203,4 @@ reauth:
entries, total);
free(share_info);
- smb_ctx_done(ctx);
-#ifdef APPLE
- smb_save2keychain(ctx);
-#endif
- return (0);
-}
-
-
-void
-view_usage(void)
-{
- printf(gettext("usage: smbutil view [connection options] //"
- "[workgroup;][user[:password]@]server\n"));
- exit(1);
}
diff --git a/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c b/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c
index cea159d529..70a176bb46 100644
--- a/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c
+++ b/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c
@@ -20,15 +20,15 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/mdb_modapi.h>
+#include <mdb/mdb_ctf.h>
#include <sys/types.h>
+#include <sys/socket.h>
#include "smb_conn.h"
#include "smb_rq.h"
@@ -210,6 +210,7 @@ smb_co_walk_step(mdb_walk_state_t *wsp)
typedef struct smb_co_cbdata {
int flags; /* OPT_... */
int printed_header;
+ mdb_ctf_id_t ctf_id;
} smb_co_cbdata_t;
/*
@@ -221,9 +222,7 @@ smb_ss_cb(uintptr_t addr, const void *data, void *arg)
const smb_share_t *ssp = data;
smb_co_cbdata_t *cbd = arg;
- mdb_printf(" %-p", addr);
- print_str((uintptr_t)ssp->ss_name);
- mdb_printf("\n");
+ mdb_printf(" %-p\t%s\n", addr, ssp->ss_name);
if (cbd->flags & OPT_VERBOSE) {
mdb_inc_indent(2);
@@ -234,6 +233,28 @@ smb_ss_cb(uintptr_t addr, const void *data, void *arg)
return (WALK_NEXT);
}
+static const char *
+vcstate_str(smb_co_cbdata_t *cbd, int stval)
+{
+ static const char prefix[] = "SMBIOD_ST_";
+ int prefix_len = sizeof (prefix) - 1;
+ mdb_ctf_id_t vcst_enum;
+ const char *cp;
+
+ /* Got this in smb_vc_dcmd. */
+ vcst_enum = cbd->ctf_id;
+
+ /* Get the name for the enum value. */
+ if ((cp = mdb_ctf_enum_name(vcst_enum, stval)) == NULL)
+ return ("?");
+
+ /* Skip the prefix part. */
+ if (strncmp(cp, prefix, prefix_len) == 0)
+ cp += prefix_len;
+
+ return (cp);
+}
+
/*
* Call-back function for walking the VC list.
*/
@@ -245,14 +266,33 @@ smb_vc_cb(uintptr_t addr, const void *data, void *arg)
if (cbd->printed_header == 0) {
cbd->printed_header = 1;
- mdb_printf("// smb_vc_t uid server user\n");
+ mdb_printf("// smb_vc_t uid server \tuser\t\tstate\n");
}
mdb_printf("%-p", addr);
- mdb_printf(" %d", vcp->vc_uid);
- print_str((uintptr_t)vcp->vc_srvname);
- print_str((uintptr_t)vcp->vc_username);
- mdb_printf("\n");
+ mdb_printf(" %7d", vcp->vc_owner);
+
+ switch (vcp->vc_srvaddr.sa.sa_family) {
+ case AF_INET:
+ mdb_printf(" %I", vcp->vc_srvaddr.sin.sin_addr);
+ break;
+ case AF_INET6:
+ mdb_printf(" %N", &vcp->vc_srvaddr.sin6.sin6_addr);
+ break;
+ default:
+ mdb_printf(" %15s", "(bad af)");
+ break;
+ }
+
+ if (vcp->vc_username[0] != '\0')
+ mdb_printf("\t%s", vcp->vc_username);
+ else
+ mdb_printf("\t%s", "(?)");
+
+ if (vcp->vc_domain[0] != '\0')
+ mdb_printf("@%s", vcp->vc_domain);
+
+ mdb_printf("\t%s\n", vcstate_str(cbd, vcp->vc_state));
if (cbd->flags & OPT_RECURSE) {
mdb_inc_indent(2);
@@ -282,6 +322,10 @@ smb_vc_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
return (DCMD_USAGE);
}
+ if (mdb_ctf_lookup_by_name("enum smbiod_state", &cbd.ctf_id) == -1) {
+ mdb_warn("Could not find enum smbiod_state");
+ }
+
if (!(flags & DCMD_ADDRSPEC)) {
if (mdb_walk("nsmb_vc", smb_vc_cb, &cbd) == -1) {
mdb_warn("failed to walk 'nsmb_vc'");
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index 934df8f983..60b65de7d3 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -475,6 +475,7 @@ HDRSUBDIRS= \
udapl \
libmapid \
libkrb5 \
+ libsmbfs \
libshare \
libidmap \
libvscan \
diff --git a/usr/src/lib/libsmbfs/Makefile b/usr/src/lib/libsmbfs/Makefile
index 0ab1f6c137..26e499e2fa 100644
--- a/usr/src/lib/libsmbfs/Makefile
+++ b/usr/src/lib/libsmbfs/Makefile
@@ -19,16 +19,22 @@
# CDDL HEADER END
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
+
#
# lib/libsmbfs/Makefile
#
include $(SRC)/lib/Makefile.lib
+HDRS= smbfs_acl.h smbfs_api.h
+HDRDIR= netsmb
+
+ROOTHDRDIR= $(ROOT)/usr/include/netsmb
+ROOTHDRS= $(HDRS:%=$(ROOTHDRDIR)/%)
+
# ISA targets
SUBDIRS = $(MACH)
$(BUILD64)SUBDIRS += $(MACH64)
@@ -40,29 +46,26 @@ clean := TARGET= clean
clobber := TARGET= clobber
lint := TARGET= lint
+MSGFILES = `$(GREP) -l gettext smb/*.[ch]`
POFILE = libsmbfs.po
.KEEP_STATE:
all install clean clobber lint: $(SUBDIRS)
-include $(SRC)/Makefile.msg.targ
+_msg: $(MSGDOMAINPOFILE)
-MSGFILES=smb/cfopt.c smb/charsets.c smb/charsets.h smb/ctx.c smb/derparse.c \
- smb/derparse.h smb/file.c smb/keychain.c smb/mbuf.c smb/nb.c \
- smb/nb_name.c smb/nb_net.c smb/nbns_rq.c smb/netshareenum.c \
- smb/nls.c smb/print.c smb/queue.h smb/rap.c smb/rcfile.c \
- smb/rcfile_priv.h smb/rq.c smb/spnego.c smb/spnego.h \
- smb/spnegoparse.c smb/spnegoparse.h smb/subr.c smb/ui-sun.c
+$(POFILE): pofile_MSGFILES
-_msg: $(MSGDOMAINPOFILE)
+install_h: $(ROOTHDRDIR) $(ROOTHDRS)
-$(MSGDOMAINPOFILE): $(POFILE)
+check: $(CHECKHDRS)
-$(POFILE): $(MSGFILES)
- $(BUILDPO.msgfiles)
+$(ROOTHDRDIR)/%: %
+ $(INS.file)
-install: $(ROOTLIBS)
+$(ROOTHDRDIR):
+ $(INS.dir)
$(SUBDIRS): FRC
@cd $@; pwd; $(MAKE) $(TARGET)
@@ -70,3 +73,4 @@ $(SUBDIRS): FRC
FRC:
include $(SRC)/lib/Makefile.targ
+include $(SRC)/Makefile.msg.targ
diff --git a/usr/src/lib/libsmbfs/Makefile.com b/usr/src/lib/libsmbfs/Makefile.com
index a2232234de..656ba731b3 100644
--- a/usr/src/lib/libsmbfs/Makefile.com
+++ b/usr/src/lib/libsmbfs/Makefile.com
@@ -18,11 +18,15 @@
#
# CDDL HEADER END
#
+
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+
+#
# lib/libsmbfs/Makefile.com
+#
LIBRARY= libsmbfs.a
VERS= .1
@@ -35,23 +39,38 @@ OBJECTS=\
acl_print.o \
charsets.o \
cfopt.o \
+ connect.o \
+ crypt.o \
ctx.o \
derparse.o \
file.o \
+ findvc.o \
+ getaddr.o \
+ iod_cl.o \
+ iod_wk.o \
keychain.o \
+ krb5ssp.o \
mbuf.o \
nb.o \
nb_name.o \
nb_net.o \
+ nb_ssn.o \
nbns_rq.o \
+ negprot.o \
netshareenum.o \
+ newvc.o \
nls.o \
+ ntlm.o \
+ ntlmssp.o \
print.o \
rap.o \
rcfile.o \
rq.o \
+ signing.o \
spnego.o \
spnegoparse.o \
+ ssnsetup.o \
+ ssp.o \
subr.o \
ui-sun.o \
utf_str.o
@@ -68,7 +87,7 @@ $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
C99MODE= $(C99_ENABLE)
-LDLIBS += -lsocket -lnsl -lc -lkrb5 -lsec -lidmap
+LDLIBS += -lsocket -lnsl -lc -lmd -lpkcs11 -lkrb5 -lsec -lidmap
# normal warnings...
CFLAGS += $(CCVERBOSE)
@@ -76,25 +95,24 @@ CFLAGS += $(CCVERBOSE)
CPPFLAGS += -D__EXTENSIONS__ -D_REENTRANT -DMIA \
-I$(SRCDIR) -I.. -I$(SRC)/uts/common
-# uncomment these if you want to use dbx
+# Debugging
+${NOT_RELEASE_BUILD} CPPFLAGS += -DDEBUG
+
+# uncomment these for dbx debugging
#COPTFLAG = -g
#CTF_FLAGS =
#CTFCONVERT_O=
#CTFMERGE_LIB=
# disable some of the less important lint
-LINTCHECKFLAGS += -erroff=E_FUNC_ARG_UNUSED
LINTCHECKFLAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2
LINTCHECKFLAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2
-LINTCHECKFLAGS += -erroff=E_FUNC_VAR_UNUSED
-LINTCHECKFLAGS += -erroff=E_STATIC_UNUSED
-LINTCHECKFLAGS += -erroff=E_CONSTANT_CONDITION
-LINTCHECKFLAGS += -erroff=E_TRUE_LOGICAL_EXPR
-
-.KEEP_STATE:
+LINTCHECKFLAGS += -DDEBUG
all: $(LIBS)
lint: lintcheck
include ../../Makefile.targ
+
+.KEEP_STATE:
diff --git a/usr/src/lib/libsmbfs/cflib.h b/usr/src/lib/libsmbfs/cflib.h
index 0b6941931e..0e8d6b57ee 100644
--- a/usr/src/lib/libsmbfs/cflib.h
+++ b/usr/src/lib/libsmbfs/cflib.h
@@ -32,7 +32,10 @@
* $Id: cflib.h,v 1.1.1.1 2001/06/09 00:28:11 zarzycki Exp $
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
#ifndef _CFLIB_H_
#define _CFLIB_H_
@@ -68,6 +71,7 @@ typedef struct opt_args opt_args_t;
extern int cf_opterr, cf_optind, cf_optopt, cf_optreset;
extern const char *cf_optarg;
+extern struct rcfile *smb_rc;
#ifdef __cplusplus
extern "C" {
@@ -78,16 +82,17 @@ int opt_args_parse(struct rcfile *, struct opt_args *, const char *,
int opt_args_parseopt(struct opt_args *, int, char *, opt_callback_t *);
int cf_getopt(int, char * const *, const char *);
+void cf_opt_lock(void);
+void cf_opt_unlock(void);
-int rc_open(const char *, const char *, struct rcfile **);
-int rc_close(struct rcfile *);
-int rc_merge(const char *, struct rcfile **);
-int rc_merge_pipe(const char *, struct rcfile **);
int rc_getstringptr(struct rcfile *, const char *, const char *, char **);
int rc_getstring(struct rcfile *, const char *, const char *, size_t, char *);
int rc_getint(struct rcfile *, const char *, const char *, int *);
int rc_getbool(struct rcfile *, const char *, const char *, int *);
+int smb_open_rcfile(char *);
+void smb_close_rcfile(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libsmbfs/netsmb/nb_lib.h b/usr/src/lib/libsmbfs/netsmb/nb_lib.h
index d2403edf75..b758050959 100644
--- a/usr/src/lib/libsmbfs/netsmb/nb_lib.h
+++ b/usr/src/lib/libsmbfs/netsmb/nb_lib.h
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -107,10 +107,11 @@ struct sockaddr;
extern "C" {
#endif
-int nb_resolvehost_in(const char *, struct sockaddr **);
+struct rcfile;
+int nb_resolvehost_in(const char *, struct in_addr *);
int nbns_resolvename(const char *, struct nb_ctx *, struct sockaddr **);
-int nbns_getnodestatus(struct sockaddr *targethost,
- struct nb_ctx *ctx, char *system, char *workgroup);
+int nbns_getnodestatus(struct nb_ctx *ctx, struct in_addr *,
+ char *system, char *workgroup);
int nb_getlocalname(char *name, size_t maxlen);
const char *nb_strerror(int error);
diff --git a/usr/src/lib/libsmbfs/netsmb/smb_lib.h b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
index bec4a1c0b5..c13cb1b648 100644
--- a/usr/src/lib/libsmbfs/netsmb/smb_lib.h
+++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
@@ -33,31 +33,29 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _NETSMB_SMB_LIB_H_
#define _NETSMB_SMB_LIB_H_
+/*
+ * Internal interface exported to our commands in:
+ * usr/src/cmd/fs.d/smbclnt/
+ */
+
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/byteorder.h>
-#include <netsmb/smb.h>
+#include <netsmb/smbfs_api.h>
#include <netsmb/smb_dev.h>
-#define SMB_CFG_FILE "/etc/nsmb.conf"
-#define OLD_SMB_CFG_FILE "/usr/local/etc/nsmb.conf"
-
-#define STDPARAM_ARGS \
- 'A':case 'B':case 'C':case 'E':case 'I':case 'L':case \
- 'M':case 'N':case 'U':case 'R':case 'S':case 'T':case \
- 'W':case 'O':case 'P'
-
-#define STDPARAM_OPT "ABCE:I:L:M:NO:P:U:R:S:T:W:"
+extern const char smbutil_std_opts[];
+#define STDPARAM_OPT smbutil_std_opts
/*
* bits to indicate the source of error
@@ -68,33 +66,94 @@
#define SMB_NB_ERROR 0x20000
/*
+ * Size of all LM/NTLM hashes (16 bytes).
+ * The driver needs to know this, so it's
+ * defined by smb_dev.h
+ */
+#define NTLM_HASH_SZ SMBIOC_HASH_SZ
+#define NTLM_CHAL_SZ 8 /* challenge size */
+
+/*
+ * This is what goes across the door call to the IOD
+ * when asking for a new connection.
+ */
+struct smb_iod_ssn {
+ struct smbioc_ossn iod_ossn;
+ int iod_authflags; /* SMB_AT_x */
+ uchar_t iod_nthash[NTLM_HASH_SZ];
+ uchar_t iod_lmhash[NTLM_HASH_SZ];
+ /* Kerberos cred. cache res. name? */
+};
+typedef struct smb_iod_ssn smb_iod_ssn_t;
+
+
+/*
* SMB work context. Used to store all values which are necessary
* to establish connection to an SMB server.
*/
struct smb_ctx {
int ct_flags; /* SMBCF_ */
- int ct_fd; /* handle of connection */
+ int ct_dev_fd; /* device handle */
int ct_parsedlevel;
int ct_minlevel;
int ct_maxlevel;
- char *ct_fullserver; /* original server name from cmd line */
- char *ct_srvaddr; /* hostname or IP address of server */
- struct sockaddr_in ct_srvinaddr; /* IP address of server */
- char ct_locname[SMB_MAXUSERNAMELEN + 1];
- struct nb_ctx *ct_nb;
- struct smbioc_ossn ct_ssn;
- struct smbioc_oshare ct_sh;
+ char *ct_fullserver; /* orig. server name from cmd line */
+ char *ct_srvaddr_s; /* hostname or IP address of server */
+ struct addrinfo *ct_addrinfo; /* IP addresses of the server */
+ struct nb_ctx *ct_nb; /* NetBIOS info. */
+ char *ct_locname; /* local (machine) name */
+ smb_iod_ssn_t ct_iod_ssn;
+ /* smbioc_oshare_t ct_sh; XXX */
+ int ct_minauth;
+ int ct_shtype_req; /* share type wanted */
char *ct_origshare;
char *ct_home;
- void *ct_secblob;
- int ct_secbloblen;
- /* krb5 stuff: all anonymous struct pointers here. */
- struct _krb5_context *ct_krb5ctx;
- struct _krb5_ccache *ct_krb5cc; /* credentials cache */
- struct krb5_principal_data *ct_krb5cp; /* client principal */
+
+ /* Connection setup SMB stuff. */
+ /* Strings from the SMB negotiate response. */
+ char *ct_srv_OS;
+ char *ct_srv_LM;
+
+ /* NTLM auth. stuff */
+ uchar_t ct_clnonce[NTLM_CHAL_SZ];
+ uchar_t ct_ntlm_chal[NTLM_CHAL_SZ];
+ char ct_password[SMBIOC_MAX_NAME];
+
+ /* See ssp.c */
+ void *ct_ssp_ctx;
+ smbioc_ssn_work_t ct_work;
};
-typedef struct smb_ctx smb_ctx_t;
+
+/*
+ * Short-hand for some of the substruct fields above
+ */
+#define ct_ssn ct_iod_ssn.iod_ossn
+#define ct_vopt ct_iod_ssn.iod_ossn.ssn_vopt
+#define ct_owner ct_iod_ssn.iod_ossn.ssn_owner
+#define ct_srvaddr ct_iod_ssn.iod_ossn.ssn_srvaddr
+#define ct_domain ct_iod_ssn.iod_ossn.ssn_domain
+#define ct_user ct_iod_ssn.iod_ossn.ssn_user
+#define ct_srvname ct_iod_ssn.iod_ossn.ssn_srvname
+#define ct_authflags ct_iod_ssn.iod_authflags
+#define ct_nthash ct_iod_ssn.iod_nthash
+#define ct_lmhash ct_iod_ssn.iod_lmhash
+
+#define ct_sopt ct_work.wk_sopt
+#define ct_iods ct_work.wk_iods
+#define ct_tran_fd ct_work.wk_iods.is_tran_fd
+#define ct_hflags ct_work.wk_iods.is_hflags
+#define ct_hflags2 ct_work.wk_iods.is_hflags2
+#define ct_vcflags ct_work.wk_iods.is_vcflags
+#define ct_ssn_key ct_work.wk_iods.is_ssn_key
+#define ct_mac_seqno ct_work.wk_iods.is_next_seq
+#define ct_mackeylen ct_work.wk_iods.is_u_maclen
+#define ct_mackey ct_work.wk_iods.is_u_mackey.lp_ptr
+
+
+/*
+ * Bits in smb_ctx_t.ct_flags
+ */
#define SMBCF_NOPWD 0x0001 /* don't ask for a password */
#define SMBCF_SRIGHTS 0x0002 /* share access rights supplied */
#define SMBCF_LOCALE 0x0004 /* use current locale */
@@ -111,100 +170,35 @@ typedef struct smb_ctx smb_ctx_t;
#define SMBCF_SSNACTIVE 0x02000000 /* session setup succeeded */
#define SMBCF_KCDOMAIN 0x04000000 /* use domain in KC lookup */
-/*
- * access modes (see also smb_dev.h)
- */
-#define SMBM_READ S_IRUSR /* read conn attrs. (like list shares) */
-#define SMBM_WRITE S_IWUSR /* modify conn attrs */
-#define SMBM_EXEC S_IXUSR /* can send SMB requests */
-#define SMBM_READGRP S_IRGRP
-#define SMBM_WRITEGRP S_IWGRP
-#define SMBM_EXECGRP S_IXGRP
-#define SMBM_READOTH S_IROTH
-#define SMBM_WRITEOTH S_IWOTH
-#define SMBM_EXECOTH S_IXOTH
-#define SMBM_ALL S_IRWXU
-#define SMBM_DEFAULT S_IRWXU
-
/*
- * Share type for smb_ctx_init
+ * Context management
*/
-#define SMB_ST_DISK STYPE_DISKTREE
-#define SMB_ST_PRINTER STYPE_PRINTQ
-#define SMB_ST_COMM STYPE_DEVICE
-#define SMB_ST_PIPE STYPE_IPC
-#define SMB_ST_ANY STYPE_UNKNOWN
-#define SMB_ST_MAX STYPE_UNKNOWN
-#define SMB_ST_NONE 0xff /* not a part of protocol */
-
-struct mbdata {
- struct mbuf *mb_top;
- struct mbuf *mb_cur;
- char *mb_pos;
- int mb_count;
-};
-typedef struct mbdata mbdata_t;
-struct smb_bitname {
- uint_t bn_bit;
- char *bn_name;
-};
-typedef struct smb_bitname smb_bitname_t;
+int smb_ctx_init(struct smb_ctx *);
+void smb_ctx_done(struct smb_ctx *);
+int smb_open_driver(void);
-extern int smb_debug, smb_verbose;
-extern struct rcfile *smb_rc;
+int smb_ctx_gethandle(struct smb_ctx *);
+int smb_ctx_findvc(struct smb_ctx *);
+int smb_ctx_newvc(struct smb_ctx *);
-#ifdef __cplusplus
-extern "C" {
-#endif
+/*
+ * I/O daemon stuff
+ */
-int smb_lib_init(void);
-int smb_open_driver(void);
-int smb_open_rcfile(struct smb_ctx *ctx);
-void smb_error(const char *, int, ...);
-char *smb_printb(char *, int, const struct smb_bitname *);
+int smb_iod_cl_newvc(smb_ctx_t *ctx);
+char *smb_iod_door_path(void);
+int smb_iod_open_door(int *);
+int smb_iod_connect(struct smb_ctx *);
+int smb_iod_work(struct smb_ctx *);
/*
- * Context management
+ * Other stuff
*/
-int smb_ctx_init(struct smb_ctx *, int, char *[], int, int, int);
-void smb_ctx_done(struct smb_ctx *);
-int smb_ctx_parseunc(struct smb_ctx *, const char *, int, const char **);
-int smb_ctx_setcharset(struct smb_ctx *, const char *);
-int smb_ctx_setfullserver(struct smb_ctx *, const char *);
-void smb_ctx_setserver(struct smb_ctx *, const char *);
-int smb_ctx_setuser(struct smb_ctx *, const char *, int);
-int smb_ctx_setshare(struct smb_ctx *, const char *, int);
-int smb_ctx_setscope(struct smb_ctx *, const char *);
-int smb_ctx_setworkgroup(struct smb_ctx *, const char *, int);
-int smb_ctx_setpassword(struct smb_ctx *, const char *, int);
-int smb_ctx_setsrvaddr(struct smb_ctx *, const char *);
-int smb_ctx_opt(struct smb_ctx *, int, const char *);
-int smb_ctx_findvc(struct smb_ctx *, int, int);
-int smb_ctx_negotiate(struct smb_ctx *, int, int, char *);
-int smb_ctx_tdis(struct smb_ctx *ctx);
-int smb_ctx_lookup(struct smb_ctx *, int, int);
-int smb_ctx_login(struct smb_ctx *);
-int smb_ctx_readrc(struct smb_ctx *);
-int smb_ctx_resolve(struct smb_ctx *);
-int smb_ctx_setflags(struct smb_ctx *, int, int, int);
-int smb_ctx_flags2(struct smb_ctx *);
-
-int smb_smb_open_print_file(struct smb_ctx *, int, int, const char *, smbfh*);
-int smb_smb_close_print_file(struct smb_ctx *, smbfh);
-
-typedef void (*smb_ctx_close_hook_t)(struct smb_ctx *);
-void smb_ctx_set_close_hook(smb_ctx_close_hook_t);
-int smb_fh_close(struct smb_ctx *ctx, smbfh fh);
-int smb_fh_open(struct smb_ctx *ctx, const char *, int, smbfh *);
-int smb_fh_read(struct smb_ctx *, smbfh, off_t, size_t, char *);
-int smb_fh_write(struct smb_ctx *, smbfh, off_t, size_t, const char *);
-int smb_fh_xactnp(struct smb_ctx *, smbfh, int, const char *,
- int *, char *, int *);
-
-int smb_t2_request(struct smb_ctx *, int, uint16_t *, const char *,
- int, void *, int, void *, int *, void *, int *, void *, int *);
+
+int smb_open_rcfile(char *);
+void smb_close_rcfile(void);
void smb_simplecrypt(char *dst, const char *src);
int smb_simpledecrypt(char *dst, const char *src);
@@ -218,19 +212,7 @@ void *nls_mem_toloc(void *, const void *, int);
char *nls_str_upper(char *, const char *);
char *nls_str_lower(char *, const char *);
-int smb_get_authentication(char *, size_t, char *, size_t, char *, size_t,
- const char *, struct smb_ctx *);
-int smb_browse(struct smb_ctx *, int);
-void smb_save2keychain(struct smb_ctx *);
-#define smb_autherr(e) ((e) == EAUTH || (e) == EACCES || (e) == EPERM)
-char *smb_strerror(int);
char *smb_getprogname();
#define __progname smb_getprogname()
-extern char *unpercent(char *component);
-
-#ifdef __cplusplus
-}
-#endif
-
#endif /* _NETSMB_SMB_LIB_H_ */
diff --git a/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h b/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h
index dc8972e5cb..d1da5bda22 100644
--- a/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h
+++ b/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _NETSMB_SMBFS_ACL_H
#define _NETSMB_SMBFS_ACL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Get/set ACL via contracted interface in libsmbfs.
* The ACL is in the form used by libsec (type=ACE_T)
@@ -37,6 +35,10 @@
#include <sys/acl.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* Get a ZFS-style acl from an FD opened in smbfs.
* Intentionally similar to: facl_get(3SEC)
@@ -87,6 +89,12 @@ int smbfs_acl_sd2zfs(i_ntsd_t *, acl_t *, uid_t *, gid_t *);
int smbfs_acl_zfs2sd(acl_t *, uid_t, gid_t, i_ntsd_t **);
void smbfs_acl_free_sd(i_ntsd_t *);
-void smbfs_acl_print_sd(FILE *, i_ntsd_t *);
+
+struct __FILE;
+void smbfs_acl_print_sd(struct __FILE *, i_ntsd_t *);
+
+#ifdef __cplusplus
+}
+#endif
#endif /* _NETSMB_SMBFS_ACL_H */
diff --git a/usr/src/lib/libsmbfs/netsmb/smbfs_api.h b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h
new file mode 100644
index 0000000000..eeeb17ea1a
--- /dev/null
+++ b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h
@@ -0,0 +1,158 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NETSMB_SMBFS_API_H
+#define _NETSMB_SMBFS_API_H
+
+/*
+ * Define the API exported to our commands and to the
+ * MS-style RPC-over-named-pipes library (mlrpc).
+ */
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Some errno values we need to expose in this API.
+ * NB: These two defines are duplicated from the
+ * driver smb_dev.h to avoid exposing that here.
+ *
+ * EBADRPC is used for message decoding errors.
+ * EAUTH is used for CIFS authentication errors.
+ */
+#ifndef EBADRPC
+#define EBADRPC 113
+#endif
+#ifndef EAUTH
+#define EAUTH 114
+#endif
+
+
+/*
+ * Share type values for smb_ctx_new, _init
+ * Based on NetUseAdd() USE_INFO_[12] _asg_type values
+ * They also happen to match: STYPE_DISKTREE, etc.
+ */
+typedef enum {
+ USE_WILDCARD = -1,
+ USE_DISKDEV,
+ USE_SPOOLDEV,
+ USE_CHARDEV,
+ USE_IPC
+} smb_use_shtype_t;
+
+/*
+ * Parse "level" spec. for smb_ctx_parseunc()
+ * i.e. whether we require a share name, etc.
+ */
+typedef enum {
+ SMBL_NONE = 0, /* have nothing */
+ SMBL_SERVER, /* have server */
+ SMBL_VC = 1, /* alias for _SERVER */
+ SMBL_SHARE, /* have server share */
+ SMBL_PATH /* have server share path */
+} smb_parse_level_t;
+
+/*
+ * Authentication type flags
+ * See: smb_ctx_setauthflags()
+ */
+#define SMB_AT_ANON 1 /* anonymous (NULL session) */
+#define SMB_AT_LM1 2 /* LM1 (with NTLM) */
+#define SMB_AT_NTLM1 4 /* NTLM (v1) */
+#define SMB_AT_NTLM2 8 /* NTLMv2 */
+#define SMB_AT_KRB5 0x10 /* Kerberos5 (AD) */
+#define SMB_AT_DEFAULT (SMB_AT_KRB5 | SMB_AT_NTLM2 | SMB_AT_NTLM1)
+
+struct smb_ctx; /* anonymous here; real one in smb_lib.h */
+typedef struct smb_ctx smb_ctx_t;
+
+extern int smb_debug, smb_verbose;
+
+int smb_lib_init(void);
+void smb_error(const char *, int, ...);
+
+/*
+ * Context management
+ */
+int smb_ctx_alloc(struct smb_ctx **);
+void smb_ctx_free(struct smb_ctx *);
+int smb_ctx_kill(struct smb_ctx *);
+
+int smb_ctx_scan_argv(struct smb_ctx *, int, char **, int, int, int);
+int smb_ctx_parseunc(struct smb_ctx *, const char *, int, int, int,
+ const char **);
+int smb_ctx_readrc(struct smb_ctx *);
+int smb_ctx_opt(struct smb_ctx *, int, const char *);
+int smb_get_authentication(struct smb_ctx *);
+
+int smb_ctx_flags2(struct smb_ctx *);
+int smb_ctx_resolve(struct smb_ctx *);
+int smb_ctx_get_ssn(struct smb_ctx *);
+int smb_ctx_get_ssnkey(struct smb_ctx *, uchar_t *, size_t);
+int smb_ctx_get_tree(struct smb_ctx *);
+
+int smb_ctx_setauthflags(struct smb_ctx *, int);
+int smb_ctx_setcharset(struct smb_ctx *, const char *);
+int smb_ctx_setflags(struct smb_ctx *, int, int, int);
+int smb_ctx_setfullserver(struct smb_ctx *, const char *);
+int smb_ctx_setscope(struct smb_ctx *, const char *);
+int smb_ctx_setwins(struct smb_ctx *, const char *, const char *);
+
+int smb_ctx_setsrvaddr(struct smb_ctx *, const char *);
+int smb_ctx_setserver(struct smb_ctx *, const char *);
+int smb_ctx_setshare(struct smb_ctx *, const char *, int);
+
+int smb_ctx_setdomain(struct smb_ctx *, const char *, int);
+int smb_ctx_setuser(struct smb_ctx *, const char *, int);
+int smb_ctx_setpassword(struct smb_ctx *, const char *, int);
+int smb_ctx_setpwhash(struct smb_ctx *, const uchar_t *, const uchar_t *);
+
+typedef void (*smb_ctx_close_hook_t)(struct smb_ctx *);
+void smb_ctx_set_close_hook(smb_ctx_close_hook_t);
+int smb_fh_close(struct smb_ctx *ctx, int);
+int smb_fh_open(struct smb_ctx *ctx, const char *, int, int *);
+int smb_fh_read(struct smb_ctx *, int, off_t, size_t, char *);
+int smb_fh_write(struct smb_ctx *, int, off_t, size_t, const char *);
+int smb_fh_xactnp(struct smb_ctx *, int, int, const char *,
+ int *, char *, int *);
+
+int smb_t2_request(struct smb_ctx *, int, uint16_t *, const char *,
+ int, void *, int, void *, int *, void *, int *, void *, int *);
+
+int smb_printer_open(struct smb_ctx *, int, int, const char *, int *);
+int smb_printer_close(struct smb_ctx *, int);
+
+char *smb_strerror(int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NETSMB_SMBFS_API_H */
diff --git a/usr/src/lib/libsmbfs/smb/acl_api.c b/usr/src/lib/libsmbfs/smb/acl_api.c
index 6c8552e75a..3e9d703c99 100644
--- a/usr/src/lib/libsmbfs/smb/acl_api.c
+++ b/usr/src/lib/libsmbfs/smb/acl_api.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -49,9 +49,11 @@
#include <sys/fs/smbfs_ioctl.h>
+#include <netsmb/smb.h>
#include <netsmb/smb_lib.h>
#include <netsmb/smbfs_acl.h>
-#include <netsmb/smbfs_isec.h>
+
+#include "acl_nt.h"
#include "private.h"
/* Sanity check SD sizes */
diff --git a/usr/src/lib/libsmbfs/smb/acl_conv.c b/usr/src/lib/libsmbfs/smb/acl_conv.c
index ec77c8f3c5..d19b323dfe 100644
--- a/usr/src/lib/libsmbfs/smb/acl_conv.c
+++ b/usr/src/lib/libsmbfs/smb/acl_conv.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -54,10 +54,13 @@
#include <sys/fs/smbfs_ioctl.h>
+#include <netsmb/mchain.h>
+#include <netsmb/smb.h>
+
#include <netsmb/smb_lib.h>
#include <netsmb/smbfs_acl.h>
-#include <netsmb/smbfs_isec.h>
-#include <netsmb/mchain.h>
+
+#include "acl_nt.h"
#include "private.h"
#ifdef _KERNEL
@@ -167,7 +170,6 @@ errout:
static void
ifree_ace(i_ntace_t *ace)
{
- size_t sz;
if (ace == NULL)
return;
@@ -282,7 +284,6 @@ mb_get_acl(mbdata_t *mbp, i_ntacl_t **aclp)
i_ntace_t **acep;
uint8_t revision;
uint16_t acl_len, acecount;
- uint32_t *subauthp;
size_t aclsz;
int i, error;
@@ -327,10 +328,7 @@ static int
mb_put_acl(mbdata_t *mbp, i_ntacl_t *acl)
{
i_ntace_t **acep;
- uint8_t revision;
uint16_t acl_len, *acl_len_p;
- uint32_t *subauthp;
- size_t aclsz;
int i, cnt0, error;
cnt0 = mbp->mb_count;
@@ -929,6 +927,7 @@ errout:
* Include owner/group too if uid/gid != -1.
* Note optional arg: vsa/acl
*/
+/*ARGSUSED*/
int smbfs_acl_zfs2sd(
#ifdef _KERNEL
vsecattr_t *vsa,
diff --git a/usr/src/lib/libsmbfs/netsmb/smbfs_isec.h b/usr/src/lib/libsmbfs/smb/acl_nt.h
index f6b3555345..844a7e6543 100644
--- a/usr/src/lib/libsmbfs/netsmb/smbfs_isec.h
+++ b/usr/src/lib/libsmbfs/smb/acl_nt.h
@@ -20,17 +20,16 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#ifndef _SMBFS_ISEC_H
-#define _SMBFS_ISEC_H
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+#ifndef _ACL_NT_H
+#define _ACL_NT_H
/*
- * Internal Security Descriptor (SD)
+ * Internal functions for dealing with
+ * NT Security data structures.
*/
#include <netsmb/smbfs_acl.h>
@@ -78,36 +77,37 @@ struct i_ntsd {
i_ntacl_t *sd_dacl;
};
+struct mbdata;
/*
* Import a raw SD (mb chain) into "internal" form.
* (like "absolute" form per. NT docs)
* Returns allocated data in sdp
*/
-int mb_get_ntsd(mbdata_t *mbp, i_ntsd_t **sdp);
+int mb_get_ntsd(struct mbdata *mbp, i_ntsd_t **sdp);
/*
* Export an "internal" SD into an raw SD (mb chain).
* (a.k.a "self-relative" form per. NT docs)
* Returns allocated mbchain in mbp.
*/
-int mb_put_ntsd(mbdata_t *mbp, i_ntsd_t *sd);
+int mb_put_ntsd(struct mbdata *mbp, i_ntsd_t *sd);
/*
* Get an SD via ioctl on FD (with "selector" bits),
* stroing the raw Windows SD in the mb chain mbp.
*/
-int smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp);
+int smbfs_acl_iocget(int fd, uint32_t selector, struct mbdata *mbp);
/*
* Set an SD via ioctl on FD (with "selector" bits),
* with a raw Windows SD from the chain mbp.
*/
-int smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp);
+int smbfs_acl_iocset(int fd, uint32_t selector, struct mbdata *mbp);
int smbfs_sid2str(i_ntsid_t *sid,
char *obuf, size_t olen, uint32_t *ridp);
-#endif /* _SMBFS_ISEC_H */
+#endif /* _ACL_NT_H */
diff --git a/usr/src/lib/libsmbfs/smb/acl_print.c b/usr/src/lib/libsmbfs/smb/acl_print.c
index 9a1d51e320..259258a9f1 100644
--- a/usr/src/lib/libsmbfs/smb/acl_print.c
+++ b/usr/src/lib/libsmbfs/smb/acl_print.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Print an NT Security Descriptor (SD) and its sub-components.
*/
@@ -54,7 +52,8 @@
#include <netsmb/smb_lib.h>
#include <netsmb/smbfs_acl.h>
-#include <netsmb/smbfs_isec.h>
+
+#include "acl_nt.h"
static void
fprint_sid(FILE *fp, i_ntsid_t *sid)
diff --git a/usr/src/lib/libsmbfs/smb/cfopt.c b/usr/src/lib/libsmbfs/smb/cfopt.c
index 094682f6d8..3b2672b2cd 100644
--- a/usr/src/lib/libsmbfs/smb/cfopt.c
+++ b/usr/src/lib/libsmbfs/smb/cfopt.c
@@ -32,16 +32,19 @@
* $Id: cfopt.c,v 1.1.1.1 2001/06/09 00:28:12 zarzycki Exp $
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include <sys/param.h>
+#include <sys/types.h>
#include <stdio.h>
#include <string.h>
+#include <synch.h>
#include <libintl.h>
#include <cflib.h>
#include <netsmb/smb_lib.h>
+#include <assert.h>
+
+/* lock for the variables below */
+mutex_t cf_opt_mutex = DEFAULTMUTEX;
int cf_opterr = 1, /* if error message should be printed */
cf_optind = 1, /* index into parent argv vector */
@@ -53,6 +56,18 @@ const char *cf_optarg; /* argument associated with option */
#define BADARG (int)':'
#define EMSG ""
+void
+cf_opt_lock(void)
+{
+ mutex_lock(&cf_opt_mutex);
+}
+
+void
+cf_opt_unlock(void)
+{
+ mutex_unlock(&cf_opt_mutex);
+}
+
int
cf_getopt(nargc, nargv, ostr)
int nargc;
@@ -63,10 +78,12 @@ cf_getopt(nargc, nargv, ostr)
char *oli; /* option letter list index */
int tmpind;
+ assert(MUTEX_HELD(&cf_opt_mutex));
+
if (cf_optreset || !*place) { /* update scanning pointer */
cf_optreset = 0;
tmpind = cf_optind;
- while (1) {
+ for (;;) {
if (tmpind >= nargc) {
place = EMSG;
return (-1);
diff --git a/usr/src/lib/libsmbfs/smb/charsets.c b/usr/src/lib/libsmbfs/smb/charsets.c
index 81075a3a2f..1ca0eb751c 100644
--- a/usr/src/lib/libsmbfs/smb/charsets.c
+++ b/usr/src/lib/libsmbfs/smb/charsets.c
@@ -43,7 +43,9 @@
#include <iconv.h>
#include <langinfo.h>
#include <strings.h>
+#include <libintl.h>
+#include <sys/isa_defs.h>
#include <netsmb/smb_lib.h>
#include <netsmb/mchain.h>
diff --git a/usr/src/lib/libsmbfs/smb/charsets.h b/usr/src/lib/libsmbfs/smb/charsets.h
index c754425f37..4c917c99d2 100644
--- a/usr/src/lib/libsmbfs/smb/charsets.h
+++ b/usr/src/lib/libsmbfs/smb/charsets.h
@@ -43,5 +43,9 @@ extern char *convert_leunicode_to_utf8(unsigned short *windows_string);
extern char *convert_unicode_to_utf8(unsigned short *windows_string);
extern unsigned short *convert_utf8_to_leunicode(const char *utf8_string);
extern size_t unicode_strlen(const uint16_t *unicode_string);
+extern char *utf8_str_tolower(const char *s);
+extern char *utf8_str_toupper(const char *s);
+
+extern char *unpercent(char *component);
#endif /* __CHARSETS_H__ */
diff --git a/usr/src/lib/libsmbfs/smb/connect.c b/usr/src/lib/libsmbfs/smb/connect.c
new file mode 100644
index 0000000000..d0f4e2b228
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/connect.c
@@ -0,0 +1,535 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Functions to setup connections (TCP and/or NetBIOS)
+ * This has the fall-back logic for IP6, IP4, NBT
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "charsets.h"
+#include "private.h"
+
+/*
+ * SMB messages are up to 64K.
+ * Let's leave room for two.
+ */
+static int smb_tcpsndbuf = 0x20000;
+static int smb_tcprcvbuf = 0x20000;
+static int smb_connect_timeout = 30; /* seconds */
+int smb_recv_timeout = 30; /* seconds */
+
+int conn_tcp6(struct smb_ctx *, const struct sockaddr *, int);
+int conn_tcp4(struct smb_ctx *, const struct sockaddr *, int);
+int conn_nbt(struct smb_ctx *, const struct sockaddr *, char *);
+
+/*
+ * Internal set sockopt for int-sized options.
+ * Borrowed from: libnsl/rpc/ti_opts.c
+ */
+static int
+smb_setopt_int(int fd, int level, int name, int val)
+{
+ struct t_optmgmt oreq, ores;
+ struct {
+ struct t_opthdr oh;
+ int ival;
+ } opts;
+
+ /* opt header */
+ opts.oh.len = sizeof (opts);
+ opts.oh.level = level;
+ opts.oh.name = name;
+ opts.oh.status = 0;
+ opts.ival = val;
+
+ oreq.flags = T_NEGOTIATE;
+ oreq.opt.buf = (void *)&opts;
+ oreq.opt.len = sizeof (opts);
+
+ ores.flags = 0;
+ ores.opt.buf = NULL;
+ ores.opt.maxlen = 0;
+
+ if (t_optmgmt(fd, &oreq, &ores) < 0) {
+ DPRINT("t_opgmgnt, t_errno = %d", t_errno);
+ if (t_errno == TSYSERR)
+ return (errno);
+ return (EPROTO);
+ }
+ if (ores.flags != T_SUCCESS) {
+ DPRINT("flags 0x%x, status 0x%x",
+ (int)ores.flags, (int)opts.oh.status);
+ return (EPROTO);
+ }
+
+ return (0);
+}
+
+static int
+smb_setopts(int fd)
+{
+ int err;
+
+ /*
+ * Set various socket/TCP options.
+ * Failures here are not fatal -
+ * just log a complaint.
+ *
+ * We don't need these two:
+ * SO_RCVTIMEO, SO_SNDTIMEO
+ */
+
+ err = smb_setopt_int(fd, SOL_SOCKET, SO_SNDBUF, smb_tcpsndbuf);
+ if (err) {
+ DPRINT("set SO_SNDBUF, err %d", err);
+ }
+
+ err = smb_setopt_int(fd, SOL_SOCKET, SO_RCVBUF, smb_tcprcvbuf);
+ if (err) {
+ DPRINT("set SO_RCVBUF, err %d", err);
+ }
+
+ err = smb_setopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, 1);
+ if (err) {
+ DPRINT("set SO_KEEPALIVE, err %d", err);
+ }
+
+ err = smb_setopt_int(fd, IPPROTO_TCP, TCP_NODELAY, 1);
+ if (err) {
+ DPRINT("set TCP_NODELAY, err %d", err);
+ }
+
+ /* Set the connect timeout (in milliseconds). */
+ err = smb_setopt_int(fd, IPPROTO_TCP,
+ TCP_CONN_ABORT_THRESHOLD,
+ smb_connect_timeout * 1000);
+ if (err) {
+ DPRINT("set connect timeout, err %d", err);
+ }
+ return (0);
+}
+
+
+int
+conn_tcp6(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
+{
+ struct sockaddr_in6 sin6;
+ char *dev = "/dev/tcp6";
+ char paddrbuf[INET6_ADDRSTRLEN];
+ struct t_call sndcall;
+ int fd, err;
+
+ if (sa->sa_family != AF_INET6) {
+ DPRINT("bad af %d", sa->sa_family);
+ return (EINVAL);
+ }
+ bcopy(sa, &sin6, sizeof (sin6));
+ sin6.sin6_port = htons(port);
+
+ DPRINT("tcp6: %s (%d)",
+ inet_ntop(AF_INET6, &sin6.sin6_addr,
+ paddrbuf, sizeof (paddrbuf)), port);
+
+ fd = t_open(dev, O_RDWR, NULL);
+ if (fd < 0) {
+ /* Assume t_errno = TSYSERR */
+ err = errno;
+ perror(dev);
+ return (err);
+ }
+ if ((err = smb_setopts(fd)) != 0)
+ goto errout;
+ if (t_bind(fd, NULL, NULL) < 0) {
+ DPRINT("t_bind t_errno %d", t_errno);
+ if (t_errno == TSYSERR)
+ err = errno;
+ else
+ err = EPROTO;
+ goto errout;
+ }
+ sndcall.addr.maxlen = sizeof (sin6);
+ sndcall.addr.len = sizeof (sin6);
+ sndcall.addr.buf = (void *) &sin6;
+ sndcall.opt.len = 0;
+ sndcall.udata.len = 0;
+ if (t_connect(fd, &sndcall, NULL) < 0) {
+ err = get_xti_err(fd);
+ DPRINT("connect, err %d", err);
+ goto errout;
+ }
+
+ DPRINT("tcp6: connected, fd=%d", fd);
+ ctx->ct_tran_fd = fd;
+ return (0);
+
+errout:
+ close(fd);
+ return (err);
+}
+
+/*
+ * This is used for both SMB over TCP (port 445)
+ * and NetBIOS - see conn_nbt().
+ */
+int
+conn_tcp4(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
+{
+ struct sockaddr_in sin;
+ char *dev = "/dev/tcp";
+ char paddrbuf[INET_ADDRSTRLEN];
+ struct t_call sndcall;
+ int fd, err;
+
+ if (sa->sa_family != AF_INET) {
+ DPRINT("bad af %d", sa->sa_family);
+ return (EINVAL);
+ }
+ bcopy(sa, &sin, sizeof (sin));
+ sin.sin_port = htons(port);
+
+ DPRINT("tcp4: %s (%d)",
+ inet_ntop(AF_INET, &sin.sin_addr,
+ paddrbuf, sizeof (paddrbuf)), port);
+
+ fd = t_open(dev, O_RDWR, NULL);
+ if (fd < 0) {
+ /* Assume t_errno = TSYSERR */
+ err = errno;
+ perror(dev);
+ return (err);
+ }
+ if ((err = smb_setopts(fd)) != 0)
+ goto errout;
+ if (t_bind(fd, NULL, NULL) < 0) {
+ DPRINT("t_bind t_errno %d", t_errno);
+ if (t_errno == TSYSERR)
+ err = errno;
+ else
+ err = EPROTO;
+ goto errout;
+ }
+ sndcall.addr.maxlen = sizeof (sin);
+ sndcall.addr.len = sizeof (sin);
+ sndcall.addr.buf = (void *) &sin;
+ sndcall.opt.len = 0;
+ sndcall.udata.len = 0;
+ if (t_connect(fd, &sndcall, NULL) < 0) {
+ err = get_xti_err(fd);
+ DPRINT("connect, err %d", err);
+ goto errout;
+ }
+
+ DPRINT("tcp4: connected, fd=%d", fd);
+ ctx->ct_tran_fd = fd;
+ return (0);
+
+errout:
+ close(fd);
+ return (err);
+}
+
+/*
+ * Open a NetBIOS connection (session, port 139)
+ *
+ * The optional name parameter, if passed, means
+ * we found the sockaddr via NetBIOS name lookup,
+ * and can just use that for our session request.
+ * Otherwise (if name is NULL), we're connecting
+ * by IP address, and need to come up with the
+ * NetBIOS name by other means.
+ */
+int
+conn_nbt(struct smb_ctx *ctx, const struct sockaddr *saarg, char *name)
+{
+ struct sockaddr_in sin;
+ struct sockaddr *sa;
+ char server[NB_NAMELEN];
+ char workgroup[NB_NAMELEN];
+ int err, nberr, port;
+
+ bcopy(saarg, &sin, sizeof (sin));
+ sa = (struct sockaddr *)&sin;
+
+ switch (sin.sin_family) {
+ case AF_NETBIOS: /* our fake AF */
+ sin.sin_family = AF_INET;
+ break;
+ case AF_INET:
+ break;
+ default:
+ DPRINT("bad af %d", sin.sin_family);
+ return (EINVAL);
+ }
+ port = IPPORT_NETBIOS_SSN;
+
+ /*
+ * If we have a NetBIOS name, just use it.
+ * This is the path taken when we've done a
+ * NetBIOS name lookup on this name to get
+ * the IP address in the passed sa. Otherwise,
+ * we're connecting by IP address, and need to
+ * figure out what NetBIOS name to use.
+ */
+ if (name) {
+ strlcpy(server, name, sizeof (server));
+ DPRINT("given name: %s", server);
+ } else {
+ /*
+ *
+ * Try a NetBIOS node status query,
+ * which searches for a type=[20] name.
+ * If that doesn't work, just use the
+ * (fake) "*SMBSERVER" name.
+ */
+ DPRINT("try node status");
+ server[0] = '\0';
+ nberr = nbns_getnodestatus(ctx->ct_nb,
+ &sin.sin_addr, server, workgroup);
+ if (nberr == 0 && server[0] != '\0') {
+ /* Found the name. Save for reconnect. */
+ DPRINT("found name: %s", server);
+ strlcpy(ctx->ct_srvname, server,
+ sizeof (ctx->ct_srvname));
+ } else {
+ DPRINT("getnodestatus, nberr %d", nberr);
+ strlcpy(server, "*SMBSERVER", sizeof (server));
+ }
+ }
+
+ /*
+ * Establish the TCP connection.
+ * Careful to close it on errors.
+ */
+ if ((err = conn_tcp4(ctx, sa, port)) != 0) {
+ DPRINT("TCP connect: err=%d", err);
+ goto out;
+ }
+
+ /* Connected. Do NetBIOS session request. */
+ err = nb_ssn_request(ctx, server);
+ if (err)
+ DPRINT("ssn_rq, err %d", err);
+
+out:
+ if (err) {
+ if (ctx->ct_tran_fd != -1) {
+ close(ctx->ct_tran_fd);
+ ctx->ct_tran_fd = -1;
+ }
+ }
+ return (err);
+}
+
+/*
+ * Make a new connection, or reconnect.
+ */
+int
+smb_iod_connect(smb_ctx_t *ctx)
+{
+ struct sockaddr *sa;
+ int err, err2;
+ struct mbdata blob;
+
+ memset(&blob, 0, sizeof (blob));
+
+ if (ctx->ct_srvname[0] == '\0') {
+ DPRINT("sername not set!");
+ return (EINVAL);
+ }
+ DPRINT("server: %s", ctx->ct_srvname);
+
+ if (smb_debug)
+ dump_ctx("smb_iod_connect", ctx);
+
+ /*
+ * This may be a reconnect, so
+ * cleanup if necessary.
+ */
+ if (ctx->ct_tran_fd != -1) {
+ close(ctx->ct_tran_fd);
+ ctx->ct_tran_fd = -1;
+ }
+
+ /*
+ * Get local machine name.
+ * Full name - not a NetBIOS name.
+ */
+ if (ctx->ct_locname == NULL) {
+ err = smb_getlocalname(&ctx->ct_locname);
+ if (err) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "can't get local name"), err);
+ return (err);
+ }
+ }
+
+ /*
+ * We're called with each IP address
+ * already copied into ct_srvaddr.
+ */
+ ctx->ct_flags |= SMBCF_RESOLVED;
+
+ sa = &ctx->ct_srvaddr.sa;
+ switch (sa->sa_family) {
+
+ case AF_INET6:
+ err = conn_tcp6(ctx, sa, IPPORT_SMB);
+ break;
+
+ case AF_INET:
+ err = conn_tcp4(ctx, sa, IPPORT_SMB);
+ /*
+ * If port 445 was not listening, try port 139.
+ * Note: Not doing NetBIOS name lookup here.
+ * We already have the IP address.
+ */
+ switch (err) {
+ case ECONNRESET:
+ case ECONNREFUSED:
+ err2 = conn_nbt(ctx, sa, NULL);
+ if (err2 == 0)
+ err = 0;
+ }
+ break;
+
+ case AF_NETBIOS:
+ /* Like AF_INET, but use NetBIOS ssn. */
+ err = conn_nbt(ctx, sa, ctx->ct_srvname);
+ break;
+
+ default:
+ DPRINT("skipped family %d", sa->sa_family);
+ err = EPROTONOSUPPORT;
+ break;
+ }
+
+
+ if (err) {
+ DPRINT("connect, err=%d", err);
+ return (err);
+ }
+
+ /*
+ * SMB Negotiate Protocol and
+ * SMB Session Setup, one of 3 ways:
+ * NULL session
+ * Extended security,
+ * NTLM (v2, v1)
+ *
+ * Empty user name means an explicit request for
+ * NULL session setup. No fall-back logic here.
+ *
+ * For NULL session, don't offer extended security.
+ * That's a lot simpler than dealing with NTLMSSP.
+ */
+ if (ctx->ct_user[0] == '\0') {
+ ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
+ err = smb_negprot(ctx, &blob);
+ if (err)
+ goto out;
+ err = smb_ssnsetup_null(ctx);
+ } else {
+ /*
+ * Do SMB Negotiate Protocol.
+ */
+ err = smb_negprot(ctx, &blob);
+ if (err)
+ goto out;
+
+ /*
+ * Do SMB Session Setup (authenticate)
+ *
+ * If the server negotiated extended security,
+ * run the SPNEGO state machine.
+ */
+ if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
+ err = smb_ssnsetup_spnego(ctx, &blob);
+ } else {
+ /*
+ * Server did NOT negotiate extended security.
+ * Try NTLMv2, NTLMv1 (if enabled).
+ */
+ if ((ctx->ct_authflags &
+ (SMB_AT_NTLM2 | SMB_AT_NTLM1)) == 0) {
+ /*
+ * Don't return EAUTH, because a
+ * new password will not help.
+ */
+ DPRINT("No NTLM authflags");
+ err = ENOTSUP;
+ goto out;
+ }
+ if (ctx->ct_authflags & SMB_AT_NTLM2)
+ err = smb_ssnsetup_ntlm2(ctx);
+ else
+ err = EAUTH;
+ if (err == EAUTH && 0 !=
+ (ctx->ct_authflags & SMB_AT_NTLM1))
+ err = smb_ssnsetup_ntlm1(ctx);
+ }
+ }
+
+ /* Tell library code we have a session. */
+ ctx->ct_flags |= SMBCF_RESOLVED | SMBCF_SSNACTIVE;
+
+out:
+ mb_done(&blob);
+
+ if (err) {
+ close(ctx->ct_tran_fd);
+ ctx->ct_tran_fd = -1;
+ } else
+ DPRINT("tran_fd = %d", ctx->ct_tran_fd);
+
+ return (err);
+}
diff --git a/usr/src/lib/libsmbfs/smb/crypt.c b/usr/src/lib/libsmbfs/smb/crypt.c
new file mode 100644
index 0000000000..ea1d7e6dd1
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/crypt.c
@@ -0,0 +1,175 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Crypto support, using libpkcs11
+ *
+ * Some code copied from the server: libsmb smb_crypt.c
+ * with minor changes, i.e. errno.h return values.
+ * XXX: Move this to a common library (later).
+ */
+
+#include <sys/types.h>
+#include <sys/md4.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+#include <cryptoutil.h>
+
+#include "smb_crypt.h"
+
+static void
+smb_initlmkey(uchar_t *keyout, const uchar_t *keyin);
+
+/*
+ * Like libsmb smb_auth_DES,
+ * but use uchar_t, return errno.
+ */
+int
+smb_encrypt_DES(uchar_t *Result, int ResultLen,
+ const uchar_t *Key, int KeyLen,
+ const uchar_t *Data, int DataLen)
+{
+ CK_RV rv;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE hKey;
+ CK_SESSION_HANDLE hSession;
+ CK_ULONG ciphertext_len;
+ uchar_t des_key[8];
+ int error = 0;
+ int K, D;
+ int k, d;
+
+ /* Calculate proper number of iterations */
+ K = KeyLen / 7;
+ D = DataLen / 8;
+
+ if (ResultLen < (K * 8 * D)) {
+ return (EINVAL);
+ }
+
+ /*
+ * Use SUNW convenience function to initialize the cryptoki
+ * library, and open a session with a slot that supports
+ * the mechanism we plan on using.
+ */
+ mechanism.mechanism = CKM_DES_ECB;
+ mechanism.pParameter = NULL;
+ mechanism.ulParameterLen = 0;
+ rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
+ if (rv != CKR_OK) {
+ return (ENOTSUP);
+ }
+
+ for (k = 0; k < K; k++) {
+ smb_initlmkey(des_key, &Key[k * 7]);
+ rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
+ des_key, 8, &hKey);
+ if (rv != CKR_OK) {
+ error = EIO;
+ goto exit_session;
+ }
+ /* Initialize the encryption operation in the session */
+ rv = C_EncryptInit(hSession, &mechanism, hKey);
+ if (rv != CKR_OK) {
+ error = EIO;
+ goto exit_encrypt;
+ }
+ ciphertext_len = DataLen;
+ for (d = 0; d < D; d++) {
+ /* Read in the data and encrypt this portion */
+ rv = C_EncryptUpdate(hSession,
+ (CK_BYTE_PTR)Data + (d * 8), 8,
+ &Result[(k * (8 * D)) + (d * 8)],
+ &ciphertext_len);
+ if (rv != CKR_OK) {
+ error = EIO;
+ goto exit_encrypt;
+ }
+ }
+ (void) C_DestroyObject(hSession, hKey);
+ }
+ goto exit_session;
+
+exit_encrypt:
+ (void) C_DestroyObject(hSession, hKey);
+exit_session:
+ (void) C_CloseSession(hSession);
+
+ return (error);
+}
+
+/*
+ * See "Netlogon Credential Computation" section of MS-NRPC document.
+ * Same as in libsmb, but output arg first.
+ */
+static void
+smb_initlmkey(uchar_t *keyout, const uchar_t *keyin)
+{
+ int i;
+
+ keyout[0] = keyin[0] >> 0x01;
+ keyout[1] = ((keyin[0] & 0x01) << 6) | (keyin[1] >> 2);
+ keyout[2] = ((keyin[1] & 0x03) << 5) | (keyin[2] >> 3);
+ keyout[3] = ((keyin[2] & 0x07) << 4) | (keyin[3] >> 4);
+ keyout[4] = ((keyin[3] & 0x0f) << 3) | (keyin[4] >> 5);
+ keyout[5] = ((keyin[4] & 0x1f) << 2) | (keyin[5] >> 6);
+ keyout[6] = ((keyin[5] & 0x3f) << 1) | (keyin[6] >> 7);
+ keyout[7] = keyin[6] & 0x7f;
+
+ for (i = 0; i < 8; i++)
+ keyout[i] = (keyout[i] << 1) & 0xfe;
+}
+
+/*
+ * Get some random bytes from /dev/urandom
+ *
+ * There may be a preferred way to call this via libpkcs11
+ * XXX: (see: C_GenerateRandom, etc. -- later...)
+ * Just read from /dev/urandom for now.
+ */
+int
+smb_get_urandom(void *data, size_t dlen)
+{
+ int fd, rlen;
+
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0)
+ return (errno);
+
+ rlen = read(fd, data, dlen);
+ close(fd);
+
+ if (rlen < 0)
+ return (errno);
+ if (rlen < dlen)
+ return (EIO);
+ return (0);
+}
diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c
index dfc86bd191..87f069402c 100644
--- a/usr/src/lib/libsmbfs/smb/ctx.c
+++ b/usr/src/lib/libsmbfs/smb/ctx.c
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -58,28 +58,35 @@
#include <assert.h>
#include <nss_dbdefs.h>
-#include <kerberosv5/krb5.h>
-#include <kerberosv5/com_err.h>
-
+#include <cflib.h>
#include <netsmb/smb_lib.h>
#include <netsmb/netbios.h>
#include <netsmb/nb_lib.h>
#include <netsmb/smb_dev.h>
-#include <cflib.h>
-#include <charsets.h>
-#include <spnego.h>
+#include "charsets.h"
+#include "spnego.h"
#include "derparse.h"
#include "private.h"
+#include "ntlm.h"
-extern MECH_OID g_stcMechOIDList [];
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
-#define POWEROF2(x) (((x) & ((x)-1)) == 0)
/* These two may be set by commands. */
int smb_debug, smb_verbose;
/*
+ * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt
+ */
+const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:";
+
+/*
* Give the RPC library a callback hook that will be
* called whenever we destroy or reinit an smb_ctx_t.
* The name rpc_cleanup_smbctx() is legacy, and was
@@ -138,21 +145,30 @@ dump_ctx_flags(int flags)
}
void
-dump_ctx_ssn(struct smbioc_ossn *ssn)
+dump_iod_ssn(smb_iod_ssn_t *is)
{
- printf(" srvname=\"%s\", dom=\"%s\", user=\"%s\", password=%s\n",
- ssn->ioc_srvname, ssn->ioc_workgroup, ssn->ioc_user,
- ssn->ioc_password[0] ? "(non-null)" : "NULL");
- printf(" timeout=%d, retry=%d, owner=%d, group=%d\n",
- ssn->ioc_timeout, ssn->ioc_retrycount,
- ssn->ioc_owner, ssn->ioc_group);
-}
+ static const char zeros[NTLM_HASH_SZ] = {0};
+ struct smbioc_ossn *ssn = &is->iod_ossn;
+
+ printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname);
+ dump_sockaddr(&ssn->ssn_srvaddr.sa);
+ printf(" dom=\"%s\", user=\"%s\"\n",
+ ssn->ssn_domain, ssn->ssn_user);
+ printf(" ct_vopt=0x%x, ct_owner=%d\n",
+ ssn->ssn_vopt, ssn->ssn_owner);
+ printf(" ct_authflags=0x%x\n", is->iod_authflags);
+
+ printf(" ct_nthash:");
+ if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ))
+ smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ);
+ else
+ printf(" {0}\n");
-void
-dump_ctx_sh(struct smbioc_oshare *sh)
-{
- printf(" share_name=\"%s\", share_pw=\"%s\"\n",
- sh->ioc_share, sh->ioc_password);
+ printf(" ct_lmhash:");
+ if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ))
+ smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ);
+ else
+ printf(" {0}\n");
}
void
@@ -161,24 +177,105 @@ dump_ctx(char *where, struct smb_ctx *ctx)
printf("context %s:\n", where);
dump_ctx_flags(ctx->ct_flags);
- printf(" localname=\"%s\"", ctx->ct_locname);
+ if (ctx->ct_locname)
+ printf(" localname=\"%s\"", ctx->ct_locname);
+ else
+ printf(" localname=NULL");
if (ctx->ct_fullserver)
printf(" fullserver=\"%s\"", ctx->ct_fullserver);
else
printf(" fullserver=NULL");
- if (ctx->ct_srvaddr)
- printf(" srvaddr=\"%s\"\n", ctx->ct_srvaddr);
+ if (ctx->ct_srvaddr_s)
+ printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s);
+ else
+ printf(" srvaddr_s=NULL\n");
+
+ if (ctx->ct_addrinfo)
+ dump_addrinfo(ctx->ct_addrinfo);
else
- printf(" srvaddr=NULL\n");
+ printf(" ct_addrinfo = NULL\n");
+
+ dump_iod_ssn(&ctx->ct_iod_ssn);
+
+ printf(" share_name=\"%s\", share_type=%d\n",
+ ctx->ct_origshare ? ctx->ct_origshare : "",
+ ctx->ct_shtype_req);
- dump_ctx_ssn(&ctx->ct_ssn);
- dump_ctx_sh(&ctx->ct_sh);
+ /* dump_iod_work()? */
+}
+
+int
+smb_ctx_alloc(struct smb_ctx **ctx_pp)
+{
+ smb_ctx_t *ctx;
+ int err;
+
+ ctx = malloc(sizeof (*ctx));
+ if (ctx == NULL)
+ return (ENOMEM);
+ err = smb_ctx_init(ctx);
+ if (err != 0) {
+ free(ctx);
+ return (err);
+ }
+ *ctx_pp = ctx;
+ return (0);
}
/*
- * Initialize an smb_ctx struct.
+ * Initialize an smb_ctx struct (defaults)
+ */
+int
+smb_ctx_init(struct smb_ctx *ctx)
+{
+ char pwbuf[NSS_BUFLEN_PASSWD];
+ struct passwd pw;
+ int error = 0;
+
+ bzero(ctx, sizeof (*ctx));
+
+ error = nb_ctx_create(&ctx->ct_nb);
+ if (error)
+ return (error);
+
+ ctx->ct_dev_fd = -1;
+ ctx->ct_tran_fd = -1;
+ ctx->ct_parsedlevel = SMBL_NONE;
+ ctx->ct_minlevel = SMBL_NONE;
+ ctx->ct_maxlevel = SMBL_PATH;
+
+ /* Fill in defaults */
+ ctx->ct_vopt = SMBVOPT_EXT_SEC;
+ ctx->ct_owner = SMBM_ANY_OWNER;
+ ctx->ct_authflags = SMB_AT_DEFAULT;
+ ctx->ct_minauth = SMB_AT_DEFAULT;
+
+ nb_ctx_setscope(ctx->ct_nb, "");
+
+ /*
+ * if the user name is not specified some other way,
+ * use the current user name (built-in default)
+ */
+ if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) {
+ smb_ctx_setuser(ctx, pw.pw_name, 0);
+ ctx->ct_home = strdup(pw.pw_name);
+ }
+
+ /*
+ * Set a built-in default domain (workgroup).
+ * Using the Windows/NT default for now.
+ */
+ smb_ctx_setdomain(ctx, "WORKGROUP", 0);
+
+ return (error);
+}
+
+/*
+ * "Scan" the command line args to find the server name,
+ * user name, and share name, as needed. We need these
+ * before reading the RC files and/or sharectl values.
*
* The sequence for getting all the members filled in
* has some tricky aspects. Here's how it works:
@@ -211,154 +308,137 @@ dump_ctx(char *where, struct smb_ctx *ctx)
* ignore options not in the options string.
*/
int
-smb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[],
+smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv,
int minlevel, int maxlevel, int sharetype)
{
- int opt, error = 0;
- const char *arg, *cp;
- struct passwd pw;
- char pwbuf[NSS_BUFLEN_PASSWD];
+ int ind, opt, error = 0;
int aflg = 0, uflg = 0;
-
- bzero(ctx, sizeof (*ctx));
- if (sharetype == SMB_ST_DISK)
- ctx->ct_flags |= SMBCF_BROWSEOK;
- error = nb_ctx_create(&ctx->ct_nb);
- if (error)
- return (error);
-
- ctx->ct_fd = -1;
- ctx->ct_parsedlevel = SMBL_NONE;
- ctx->ct_minlevel = minlevel;
- ctx->ct_maxlevel = maxlevel;
-
- /* Fill in defaults */
- ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE | SMBVOPT_MINAUTH_NTLM;
-
- ctx->ct_ssn.ioc_timeout = 15;
- ctx->ct_ssn.ioc_retrycount = 4;
- ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER;
- ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP;
- ctx->ct_ssn.ioc_mode = SMBM_EXEC;
- ctx->ct_ssn.ioc_rights = SMBM_DEFAULT;
-
- ctx->ct_sh.ioc_opt = SMBVOPT_CREATE;
- ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER;
- ctx->ct_sh.ioc_group = SMBM_ANY_GROUP;
- ctx->ct_sh.ioc_mode = SMBM_EXEC;
- ctx->ct_sh.ioc_rights = SMBM_DEFAULT;
- ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER;
- ctx->ct_sh.ioc_group = SMBM_ANY_GROUP;
-
- nb_ctx_setscope(ctx->ct_nb, "");
-
- /*
- * if the user name is not specified some other way,
- * use the current user name (built-in default)
- */
- if (getpwuid_r(geteuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL)
- smb_ctx_setuser(ctx, pw.pw_name, 0);
-
- /*
- * Set a built-in default domain (workgroup).
- * XXX: What's the best default? Use "?" instead?
- * Using the Windows/NT default for now.
- */
- smb_ctx_setworkgroup(ctx, "WORKGROUP", 0);
-
- /*
- * Parse the UNC path. Values from here are
- * marked as "from CMD".
- */
- if (argv == NULL)
- goto done;
- for (opt = 1; opt < argc; opt++) {
- cp = argv[opt];
- if (strncmp(cp, "//", 2) != 0)
- continue;
- error = smb_ctx_parseunc(ctx, cp, sharetype, &cp);
- if (error)
- return (error);
- break;
- }
+ const char *arg;
/*
* Parse options, if any. Values from here too
* are marked as "from CMD".
*/
- while (error == 0 && (opt = cf_getopt(argc, argv, ":AU:E:L:")) != -1) {
+ if (argv == NULL)
+ return (0);
+
+ ctx->ct_minlevel = minlevel;
+ ctx->ct_maxlevel = maxlevel;
+ ctx->ct_shtype_req = sharetype;
+
+ cf_opt_lock();
+ /* Careful: no return/goto before cf_opt_unlock! */
+ while (error == 0) {
+ opt = cf_getopt(argc, argv, STDPARAM_OPT);
+ if (opt == -1)
+ break;
arg = cf_optarg;
+ /* NB: handle most in smb_ctx_opt */
switch (opt) {
case 'A':
aflg = 1;
error = smb_ctx_setuser(ctx, "", TRUE);
- error = smb_ctx_setpassword(ctx, "", TRUE);
ctx->ct_flags |= SMBCF_NOPWD;
break;
- case 'E':
-#if 0 /* We don't support any "charset" stuff. (ignore -E) */
- error = smb_ctx_setcharset(ctx, arg);
- if (error)
- return (error);
-#endif
- break;
- case 'L':
-#if 0 /* Use the standard environment variables (ignore -L) */
- error = nls_setlocale(optarg);
- if (error)
- break;
-#endif
- break;
case 'U':
uflg = 1;
error = smb_ctx_setuser(ctx, arg, TRUE);
break;
+ default:
+ DPRINT("skip opt=%c", opt);
+ break;
}
}
+ ind = cf_optind;
+ arg = argv[ind];
+ cf_optind = cf_optreset = 1;
+ cf_opt_unlock();
+
+ if (error)
+ return (error);
+
if (aflg && uflg) {
printf(gettext("-A and -U flags are exclusive.\n"));
- return (1);
+ return (EINVAL);
}
- cf_optind = cf_optreset = 1;
-done:
- if (smb_debug)
- dump_ctx("after smb_ctx_init", ctx);
+ /*
+ * Parse the UNC path. Values from here are
+ * marked as "from CMD".
+ */
+ for (; ind < argc; ind++) {
+ arg = argv[ind];
+ if (strncmp(arg, "//", 2) != 0)
+ continue;
+ error = smb_ctx_parseunc(ctx, arg,
+ minlevel, maxlevel, sharetype, &arg);
+ if (error)
+ return (error);
+ break;
+ }
return (error);
}
void
+smb_ctx_free(smb_ctx_t *ctx)
+{
+ smb_ctx_done(ctx);
+ free(ctx);
+}
+
+void
smb_ctx_done(struct smb_ctx *ctx)
{
rpc_cleanup_smbctx(ctx);
- /* Kerberos stuff. See smb_ctx_krb5init() */
- if (ctx->ct_krb5ctx) {
- if (ctx->ct_krb5cp)
- krb5_free_principal(ctx->ct_krb5ctx, ctx->ct_krb5cp);
- krb5_free_context(ctx->ct_krb5ctx);
+ if (ctx->ct_dev_fd != -1) {
+ close(ctx->ct_dev_fd);
+ ctx->ct_dev_fd = -1;
}
-
- if (ctx->ct_fd != -1)
- close(ctx->ct_fd);
-#if 0 /* XXX: not pointers anymore */
- if (&ctx->ct_ssn.ioc_server)
- nb_snbfree(&ctx->ct_ssn.ioc_server);
- if (&ctx->ct_ssn.ioc_local)
- nb_snbfree(&ctx->ct_ssn.ioc_local);
-#endif
- if (ctx->ct_srvaddr)
- free(ctx->ct_srvaddr);
- if (ctx->ct_nb)
+ if (ctx->ct_tran_fd != -1) {
+ close(ctx->ct_tran_fd);
+ ctx->ct_tran_fd = -1;
+ }
+ if (ctx->ct_srvaddr_s) {
+ free(ctx->ct_srvaddr_s);
+ ctx->ct_srvaddr_s = NULL;
+ }
+ if (ctx->ct_nb) {
nb_ctx_done(ctx->ct_nb);
- if (ctx->ct_secblob)
- free(ctx->ct_secblob);
- if (ctx->ct_origshare)
+ ctx->ct_nb = NULL;
+ }
+ if (ctx->ct_locname) {
+ free(ctx->ct_locname);
+ ctx->ct_locname = NULL;
+ }
+ if (ctx->ct_origshare) {
free(ctx->ct_origshare);
- if (ctx->ct_fullserver)
+ ctx->ct_origshare = NULL;
+ }
+ if (ctx->ct_fullserver) {
free(ctx->ct_fullserver);
+ ctx->ct_fullserver = NULL;
+ }
+ if (ctx->ct_addrinfo) {
+ freeaddrinfo(ctx->ct_addrinfo);
+ ctx->ct_addrinfo = NULL;
+ }
+ if (ctx->ct_home)
+ free(ctx->ct_home);
+ if (ctx->ct_srv_OS) {
+ free(ctx->ct_srv_OS);
+ ctx->ct_srv_OS = NULL;
+ }
+ if (ctx->ct_srv_LM) {
+ free(ctx->ct_srv_LM);
+ ctx->ct_srv_LM = NULL;
+ }
+ if (ctx->ct_mackey) {
+ free(ctx->ct_mackey);
+ ctx->ct_mackey = NULL;
+ }
}
static int
@@ -385,20 +465,30 @@ getsubstring(const char *p, uchar_t sep, char *dest, int maxlen,
* Values found here are marked as "from CMD".
*/
int
-smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
+smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc,
+ int minlevel, int maxlevel, int sharetype,
const char **next)
{
const char *p = unc;
- char *p1, *colon, *servername;
+ char *p1, *colon;
char tmp[1024];
char tmp2[1024];
int error;
+ /*
+ * This may be called outside of _scan_argv,
+ * so make sure these get initialized.
+ */
+ ctx->ct_minlevel = minlevel;
+ ctx->ct_maxlevel = maxlevel;
+ ctx->ct_shtype_req = sharetype;
+
ctx->ct_parsedlevel = SMBL_NONE;
if (*p++ != '/' || *p++ != '/') {
smb_error(dgettext(TEXT_DOMAIN,
"UNC should start with '//'"), 0);
- return (EINVAL);
+ error = EINVAL;
+ goto out;
}
p1 = tmp;
error = getsubstring(p, ';', p1, sizeof (tmp), &p);
@@ -406,12 +496,13 @@ smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
if (*p1 == 0) {
smb_error(dgettext(TEXT_DOMAIN,
"empty workgroup name"), 0);
- return (EINVAL);
+ error = EINVAL;
+ goto out;
}
nls_str_upper(tmp, tmp);
- error = smb_ctx_setworkgroup(ctx, unpercent(tmp), TRUE);
+ error = smb_ctx_setdomain(ctx, unpercent(tmp), TRUE);
if (error)
- return (error);
+ goto out;
}
colon = (char *)p;
error = getsubstring(p, '@', p1, sizeof (tmp), &p);
@@ -419,7 +510,8 @@ smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
if (ctx->ct_maxlevel < SMBL_VC) {
smb_error(dgettext(TEXT_DOMAIN,
"no user name required"), 0);
- return (EINVAL);
+ error = EINVAL;
+ goto out;
}
p1 = strchr(tmp, ':');
if (p1) {
@@ -427,7 +519,7 @@ smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
*p1++ = (char)0;
error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE);
if (error)
- return (error);
+ goto out;
if (p - colon > 2)
memset(colon+1, '*', p - colon - 2);
}
@@ -435,11 +527,12 @@ smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
if (*p1 == 0) {
smb_error(dgettext(TEXT_DOMAIN,
"empty user name"), 0);
- return (EINVAL);
+ error = EINVAL;
+ goto out;
}
error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE);
if (error)
- return (error);
+ goto out;
ctx->ct_parsedlevel = SMBL_VC;
}
error = getsubstring(p, '/', p1, sizeof (tmp), &p);
@@ -448,15 +541,15 @@ smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
if (error) {
smb_error(dgettext(TEXT_DOMAIN,
"no server name found"), 0);
- return (error);
+ goto out;
}
}
if (*p1 == 0) {
smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0);
- return (EINVAL);
+ error = EINVAL;
+ goto out;
}
-
/*
* It's safe to uppercase this string, which
* consists of ascii characters that should
@@ -464,49 +557,32 @@ smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
* hex digits 0-9 and A-F (already uppercased, and
* if not uppercased they need to be). However,
* it is NOT safe to uppercase after it has been
- * converted, below!
+ * "unpercent" converted, below!
*/
-
nls_str_upper(tmp2, tmp);
/*
- * scan for % in the string.
- * If we find one, convert
- * to the assumed codepage.
+ * Save ct_fullserver without case conversion.
*/
-
- if (strchr(tmp2, '%')) {
- /* use the 1st buffer, we don't need the old string */
- servername = tmp;
- if (!(servername = convert_utf8_to_wincs(unpercent(tmp2)))) {
- smb_error(dgettext(TEXT_DOMAIN, "bad server name"), 0);
- return (EINVAL);
- }
- /*
- * Converts utf8 to win equivalent of
- * what is configured on this machine.
- * Note that we are assuming this is the
- * encoding used on the server, and that
- * assumption might be incorrect. This is
- * the best we can do now, and we should
- * move to use port 445 to avoid having
- * to worry about server codepages.
- */
- } else /* no conversion needed */
- servername = tmp2;
-
- smb_ctx_setserver(ctx, servername);
- error = smb_ctx_setfullserver(ctx, servername);
-
+ if (strchr(tmp, '%'))
+ (void) unpercent(tmp);
+ smb_ctx_setfullserver(ctx, tmp);
if (error)
- return (error);
+ goto out;
+
+#ifdef SMB_ST_NONE
if (sharetype == SMB_ST_NONE) {
- *next = p;
- return (0);
+ if (next)
+ *next = p;
+ error = 0;
+ goto out;
}
+#endif
+
if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0);
- return (EINVAL);
+ error = EINVAL;
+ goto out;
}
error = getsubstring(p, '/', p1, sizeof (tmp), &p);
if (error) {
@@ -514,21 +590,31 @@ smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
if (error) {
smb_error(dgettext(TEXT_DOMAIN,
"unexpected end of line"), 0);
- return (error);
+ goto out;
}
}
if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE &&
!(ctx->ct_flags & SMBCF_BROWSEOK)) {
smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0);
- return (EINVAL);
+ error = EINVAL;
+ goto out;
+ }
+ if (next)
+ *next = p;
+ if (*p1 == 0) {
+ error = 0;
+ goto out;
}
- *next = p;
- if (*p1 == 0)
- return (0);
error = smb_ctx_setshare(ctx, unpercent(p1), sharetype);
+
+out:
+ if (error == 0 && smb_debug > 0)
+ dump_ctx("after smb_ctx_parseunc", ctx);
+
return (error);
}
+#ifdef KICONV_SUPPORT
int
smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
{
@@ -562,98 +648,43 @@ smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
servercs[0] = 0;
return (error);
}
+#endif /* KICONV_SUPPORT */
int
-smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name)
+smb_ctx_setauthflags(struct smb_ctx *ctx, int flags)
{
- ctx->ct_fullserver = strdup(name);
- if (ctx->ct_fullserver == NULL)
- return (ENOMEM);
+ ctx->ct_authflags = flags;
return (0);
}
-/*
- * XXX TODO FIXME etc etc
- * If the call to nbns_getnodestatus(...) fails we can try one of two other
- * methods; use a name of "*SMBSERVER", which is supported by Samba (at least)
- * or, as a last resort, try the "truncate-at-dot" heuristic.
- * And the heuristic really should attempt truncation at
- * each dot in turn, left to right.
- *
- * These fallback heuristics should be triggered when the attempt to open the
- * session fails instead of in the code below.
- *
- * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
- */
int
-smb_ctx_getnbname(struct smb_ctx *ctx, struct sockaddr *sap)
+smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name)
{
- char server[SMB_MAXSRVNAMELEN + 1];
- char workgroup[SMB_MAXUSERNAMELEN + 1];
- int error;
-#if 0
- char *dot;
-#endif
+ char *p = strdup(name);
- server[0] = workgroup[0] = '\0';
- error = nbns_getnodestatus(sap, ctx->ct_nb, server, workgroup);
- if (error == 0) {
- /*
- * Used to set our domain name to be the same as
- * the server's domain name. Unnecessary at best,
- * and wrong for accounts in a trusted domain.
- */
-#ifdef APPLE
- if (workgroup[0] && !ctx->ct_ssn.ioc_workgroup[0])
- smb_ctx_setworkgroup(ctx, workgroup, 0);
-#endif
- if (server[0])
- smb_ctx_setserver(ctx, server);
- } else {
- if (smb_verbose)
- smb_error(dgettext(TEXT_DOMAIN,
- "Failed to get NetBIOS node status."), 0);
- if (ctx->ct_ssn.ioc_srvname[0] == (char)0)
- smb_ctx_setserver(ctx, "*SMBSERVER");
- }
-#if 0
- if (server[0] == (char)0) {
- dot = strchr(ctx->ct_fullserver, '.');
- if (dot)
- *dot = '\0';
- if (strlen(ctx->ct_fullserver) <= SMB_MAXSRVNAMELEN) {
- /*
- * don't uppercase the server name. it comes from
- * NBNS and uppercasing can clobber the characters
- */
- strcpy(ctx->ct_ssn.ioc_srvname, ctx->ct_fullserver);
- error = 0;
- } else {
- error = -1;
- }
- if (dot)
- *dot = '.';
- }
-#endif
- return (error);
+ if (p == NULL)
+ return (ENOMEM);
+ if (ctx->ct_fullserver)
+ free(ctx->ct_fullserver);
+ ctx->ct_fullserver = p;
+ return (0);
}
/* this routine does not uppercase the server name */
-void
+int
smb_ctx_setserver(struct smb_ctx *ctx, const char *name)
{
/* don't uppercase the server name */
- if (strlen(name) > SMB_MAXSRVNAMELEN) { /* NB limit is 15 */
- ctx->ct_ssn.ioc_srvname[0] = '\0';
- } else
- strcpy(ctx->ct_ssn.ioc_srvname, name);
+ strlcpy(ctx->ct_srvname, name,
+ sizeof (ctx->ct_srvname));
+ return (0);
}
int
smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd)
{
- if (strlen(name) >= SMB_MAXUSERNAMELEN) {
+ if (strlen(name) >= sizeof (ctx->ct_user)) {
smb_error(dgettext(TEXT_DOMAIN,
"user name '%s' too long"), 0, name);
return (ENAMETOOLONG);
@@ -667,7 +698,8 @@ smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd)
return (0);
/* don't uppercase the username, just copy it. */
- strcpy(ctx->ct_ssn.ioc_user, name);
+ strlcpy(ctx->ct_user, name,
+ sizeof (ctx->ct_user));
/* Mark this as "from the command line". */
if (from_cmd)
@@ -686,10 +718,10 @@ smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd)
* See smb_ctx_init() for notes about this.
*/
int
-smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name, int from_cmd)
+smb_ctx_setdomain(struct smb_ctx *ctx, const char *name, int from_cmd)
{
- if (strlen(name) >= SMB_MAXUSERNAMELEN) {
+ if (strlen(name) >= sizeof (ctx->ct_domain)) {
smb_error(dgettext(TEXT_DOMAIN,
"workgroup name '%s' too long"), 0, name);
return (ENAMETOOLONG);
@@ -702,7 +734,8 @@ smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name, int from_cmd)
if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM))
return (0);
- strcpy(ctx->ct_ssn.ioc_workgroup, name);
+ strlcpy(ctx->ct_domain, name,
+ sizeof (ctx->ct_domain));
/* Mark this as "from the command line". */
if (from_cmd)
@@ -714,26 +747,41 @@ smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name, int from_cmd)
int
smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd)
{
+ int err;
- if (passwd == NULL) /* XXX Huh? */
+ if (passwd == NULL)
return (EINVAL);
- if (strlen(passwd) >= SMB_MAXPASSWORDLEN) {
+ if (strlen(passwd) >= sizeof (ctx->ct_password)) {
smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0);
return (ENAMETOOLONG);
}
/*
- * Don't overwrite a value from the command line
- * with one from anywhere else.
+ * If called again after comand line parsing,
+ * don't overwrite a value from the command line
+ * with one from any stored config.
*/
if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW))
return (0);
+ memset(ctx->ct_password, 0, sizeof (ctx->ct_password));
if (strncmp(passwd, "$$1", 3) == 0)
- smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd);
+ smb_simpledecrypt(ctx->ct_password, passwd);
else
- strcpy(ctx->ct_ssn.ioc_password, passwd);
- strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password);
+ strlcpy(ctx->ct_password, passwd,
+ sizeof (ctx->ct_password));
+
+ /*
+ * Compute LM hash, NT hash.
+ */
+ if (ctx->ct_password[0]) {
+ err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password);
+ if (err != 0)
+ return (err);
+ err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password);
+ if (err != 0)
+ return (err);
+ }
/* Mark this as "from the command line". */
if (from_cmd)
@@ -742,10 +790,37 @@ smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd)
return (0);
}
+/*
+ * Use this to set NTLM auth. info (hashes)
+ * when we don't have the password.
+ */
+int
+smb_ctx_setpwhash(smb_ctx_t *ctx,
+ const uchar_t *nthash, const uchar_t *lmhash)
+{
+
+ /* Need ct_password to be non-null. */
+ if (ctx->ct_password[0] == '\0')
+ strlcpy(ctx->ct_password, "$HASH",
+ sizeof (ctx->ct_password));
+
+ /*
+ * Compute LM hash, NT hash.
+ */
+ memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
+
+ /* The LM hash is optional */
+ if (lmhash) {
+ memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
+ }
+
+ return (0);
+}
+
int
smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
{
- if (strlen(share) >= SMB_MAXSHARENAMELEN) {
+ if (strlen(share) >= SMBIOC_MAX_NAME) {
smb_error(dgettext(TEXT_DOMAIN,
"share name '%s' too long"), 0, share);
return (ENAMETOOLONG);
@@ -754,10 +829,9 @@ smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
free(ctx->ct_origshare);
if ((ctx->ct_origshare = strdup(share)) == NULL)
return (ENOMEM);
- nls_str_upper(ctx->ct_sh.ioc_share, share);
- if (share[0] != 0)
- ctx->ct_parsedlevel = SMBL_SHARE;
- ctx->ct_sh.ioc_stype = stype;
+
+ ctx->ct_shtype_req = stype;
+
return (0);
}
@@ -766,9 +840,9 @@ smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr)
{
if (addr == NULL || addr[0] == 0)
return (EINVAL);
- if (ctx->ct_srvaddr)
- free(ctx->ct_srvaddr);
- if ((ctx->ct_srvaddr = strdup(addr)) == NULL)
+ if (ctx->ct_srvaddr_s)
+ free(ctx->ct_srvaddr_s);
+ if ((ctx->ct_srvaddr_s = strdup(addr)) == NULL)
return (ENOMEM);
return (0);
}
@@ -784,7 +858,7 @@ smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
cp = strchr(pair, ':');
if (cp) {
*cp++ = '\0';
- if (*cp) {
+ if (*cp && gid) {
if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
*gid = gr.gr_gid;
} else
@@ -824,11 +898,8 @@ smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
error = smb_ctx_setsrvaddr(ctx, arg);
break;
case 'M':
- ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8);
- if (*cp == '/') {
- ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8);
- ctx->ct_flags |= SMBCF_SRIGHTS;
- }
+ /* share connect rights - ignored */
+ ctx->ct_flags |= SMBCF_SRIGHTS;
break;
case 'N':
ctx->ct_flags |= SMBCF_NOPWD;
@@ -836,61 +907,40 @@ smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
case 'O':
p = strdup(arg);
cp = strchr(p, '/');
- if (cp) {
- *cp++ = '\0';
- error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner,
- &ctx->ct_sh.ioc_group);
- }
- if (*p && error == 0) {
- error = smb_parse_owner(cp, &ctx->ct_ssn.ioc_owner,
- &ctx->ct_ssn.ioc_group);
- }
+ if (cp)
+ *cp = '\0';
+ error = smb_parse_owner(cp, &ctx->ct_owner, NULL);
free(p);
break;
case 'P':
-/* ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT; */
+/* ctx->ct_vopt |= SMBCOPT_PERMANENT; */
break;
case 'R':
- ctx->ct_ssn.ioc_retrycount = atoi(arg);
+ /* retry count - ignored */
break;
case 'T':
- ctx->ct_ssn.ioc_timeout = atoi(arg);
+ /* timeout - ignored */
break;
- case 'W':
+ case 'D': /* domain */
+ case 'W': /* workgroup (legacy alias) */
nls_str_upper(tmp, arg);
- error = smb_ctx_setworkgroup(ctx, tmp, TRUE);
+ error = smb_ctx_setdomain(ctx, tmp, TRUE);
break;
}
return (error);
}
-#if 0
-static void
-smb_hexdump(const uchar_t *buf, int len) {
- int ofs = 0;
-
- while (len--) {
- if (ofs % 16 == 0)
- printf("\n%02X: ", ofs);
- printf("%02x ", *buf++);
- ofs++;
- }
- printf("\n");
-}
-#endif
-
+/*
+ * Original code injected iconv tables into the kernel.
+ * Not sure if we'll need this or not... REVISIT
+ */
+#ifdef KICONV_SUPPORT
static int
smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
{
- int error;
+ int error = 0;
- /*
- * Not able to find out what is the work of this routine till
- * now. Still investigating.
- * REVISIT
- */
-#ifdef KICONV_SUPPORT
error = kiconv_add_xlat_table(to, from, tbl);
if (error && error != EEXIST) {
smb_error(dgettext(TEXT_DOMAIN,
@@ -898,47 +948,44 @@ smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
error, from, to);
return (error);
}
-#endif
- return (0);
+ return (error);
}
+#endif /* KICONV_SUPPORT */
/*
- * Verify context before connect operation(s),
+ * Verify context info. before connect operation(s),
* lookup specified server and try to fill all forgotten fields.
+ * Legacy name used by commands.
*/
int
smb_ctx_resolve(struct smb_ctx *ctx)
{
struct smbioc_ossn *ssn = &ctx->ct_ssn;
- struct smbioc_oshare *sh = &ctx->ct_sh;
- struct nb_name nn;
- struct sockaddr *sap;
- struct sockaddr_nb *salocal, *saserver;
- char *cp;
+ int error = 0;
+#ifdef KICONV_SUPPORT
uchar_t cstbl[256];
uint_t i;
- int error = 0;
- int browseok = ctx->ct_flags & SMBCF_BROWSEOK;
- int renego = 0;
+#endif
ctx->ct_flags &= ~SMBCF_RESOLVED;
- if (isatty(STDIN_FILENO))
- browseok = 0;
- if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == 0) {
+
+ if (ctx->ct_fullserver == NULL) {
smb_error(dgettext(TEXT_DOMAIN,
"no server name specified"), 0);
return (EINVAL);
}
- if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0 &&
- !browseok) {
+
+ if (ctx->ct_minlevel >= SMBL_SHARE &&
+ ctx->ct_origshare == NULL) {
smb_error(dgettext(TEXT_DOMAIN,
"no share name specified for %s@%s"),
- 0, ssn->ioc_user, ssn->ioc_srvname);
+ 0, ssn->ssn_user, ctx->ct_fullserver);
return (EINVAL);
}
error = nb_ctx_resolve(ctx->ct_nb);
if (error)
return (error);
+#ifdef KICONV_SUPPORT
if (ssn->ioc_localcs[0] == 0)
strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */
error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
@@ -963,177 +1010,57 @@ smb_ctx_resolve(struct smb_ctx *ctx)
if (error)
return (error);
}
- /*
- * If we have an explicit address set for the server in
- * an "addr=X" setting in .nsmbrc or SMF, just try using a
- * gethostbyname() lookup for it.
- */
- if (ctx->ct_srvaddr) {
- error = nb_resolvehost_in(ctx->ct_srvaddr, &sap);
- if (error == 0)
- (void) smb_ctx_getnbname(ctx, sap);
- } else
- error = -1;
-
- /*
- * Next try a gethostbyname() lookup on the original user-
- * specified server name. This is similar to Windows
- * NBT option "Use DNS for name resolution."
- */
- if (error && ctx->ct_fullserver) {
- error = nb_resolvehost_in(ctx->ct_fullserver, &sap);
- if (error == 0)
- (void) smb_ctx_getnbname(ctx, sap);
- }
+#endif /* KICONV_SUPPORT */
/*
- * Finally, try the shorter, upper-cased ssn->ioc_srvname
- * with a NBNS/WINS lookup if the "nbns_enable" property is
- * true (the default). nbns_resolvename() may unicast to the
- * "nbns" server or broadcast on the subnet.
+ * Lookup the IP address.
+ * Puts a list in ct_addrinfo
*/
- if (error && ssn->ioc_srvname[0] &&
- ctx->ct_nb->nb_flags & NBCF_NS_ENABLE) {
- error = nbns_resolvename(ssn->ioc_srvname,
- ctx->ct_nb, &sap);
- /*
- * Used to get the NetBIOS node status here.
- * Not necessary (we have the NetBIOS name).
- */
- }
+ error = smb_ctx_getaddr(ctx);
if (error) {
smb_error(dgettext(TEXT_DOMAIN,
"can't get server address"), error);
return (error);
}
+ assert(ctx->ct_addrinfo != NULL);
- /* XXX: no nls_str_upper(ssn->ioc_srvname) here? */
-
- assert(sizeof (nn.nn_name) == sizeof (ssn->ioc_srvname));
- memcpy(nn.nn_name, ssn->ioc_srvname, NB_NAMELEN);
- nn.nn_type = NBT_SERVER;
- nn.nn_scope = ctx->ct_nb->nb_scope;
-
- error = nb_sockaddr(sap, &nn, &saserver);
- memcpy(&ctx->ct_srvinaddr, sap, sizeof (struct sockaddr_in));
- nb_snbfree(sap);
- if (error) {
- smb_error(dgettext(TEXT_DOMAIN,
- "can't allocate server address"), error);
- return (error);
- }
- /* We know it's a NetBIOS address here. */
- bcopy(saserver, &ssn->ioc_server.nb,
- sizeof (struct sockaddr_nb));
- if (ctx->ct_locname[0] == 0) {
- error = nb_getlocalname(ctx->ct_locname,
- SMB_MAXUSERNAMELEN + 1);
- if (error) {
- smb_error(dgettext(TEXT_DOMAIN,
- "can't get local name"), error);
- return (error);
- }
- nls_str_upper(ctx->ct_locname, ctx->ct_locname);
- }
-
- /* XXX: no nls_str_upper(ctx->ct_locname); here? */
-
- memcpy(nn.nn_name, ctx->ct_locname, NB_NAMELEN);
- nn.nn_type = NBT_WKSTA;
- nn.nn_scope = ctx->ct_nb->nb_scope;
-
- error = nb_sockaddr(NULL, &nn, &salocal);
- if (error) {
- nb_snbfree((struct sockaddr *)saserver);
- smb_error(dgettext(TEXT_DOMAIN,
- "can't allocate local address"), error);
- return (error);
- }
-
- /* We know it's a NetBIOS address here. */
- bcopy(salocal, &ssn->ioc_local.nb,
- sizeof (struct sockaddr_nb));
-
- error = smb_ctx_findvc(ctx, SMBL_VC, 0);
- if (error == 0) {
- /* re-use and existing VC */
- ctx->ct_flags |= SMBCF_RESOLVED | SMBCF_SSNACTIVE;
- return (0);
- }
-
- /* Make a new connection via smb_ctx_negotiate()... */
- error = smb_ctx_negotiate(ctx, SMBL_SHARE, SMBLK_CREATE,
- ssn->ioc_workgroup);
- if (error)
- return (error);
- ctx->ct_flags &= ~SMBCF_AUTHREQ;
- if (!ctx->ct_secblob && browseok && !sh->ioc_share[0] &&
- !(ctx->ct_flags & SMBCF_XXX)) {
- /* assert: anon share list is subset of overall server shares */
- error = smb_browse(ctx, 1);
- if (error) /* user cancel or other error? */
- return (error);
+ /*
+ * If we have a user name but no password,
+ * check for a keychain entry.
+ * XXX: Only for auth NTLM?
+ */
+ if (ctx->ct_user[0] == '\0') {
/*
- * A share was selected, authenticate button was pressed,
- * or anon-authentication failed getting browse list.
+ * No user name (anonymous session).
+ * The minauth checks do not apply.
*/
- }
- if ((ctx->ct_secblob == NULL) && (ctx->ct_flags & SMBCF_AUTHREQ ||
- (ssn->ioc_password[0] == '\0' &&
- !(ctx->ct_flags & SMBCF_NOPWD)))) {
-reauth:
+ ctx->ct_authflags = SMB_AT_ANON;
+ } else {
/*
- * This function is implemented in both
- * ui-apple.c and ui-sun.c so let's try to
- * keep the same interface. Not sure why
- * they didn't just pass ssn here.
+ * Have a user name.
+ * If we don't have a p/w yet,
+ * try the keychain.
*/
- error = smb_get_authentication(
- ssn->ioc_workgroup, sizeof (ssn->ioc_workgroup) - 1,
- ssn->ioc_user, sizeof (ssn->ioc_user) - 1,
- ssn->ioc_password, sizeof (ssn->ioc_password) - 1,
- ssn->ioc_srvname, ctx);
- if (error)
- return (error);
- }
- /*
- * if we have a session it is either anonymous
- * or from a stale authentication. re-negotiating
- * gets us ready for a fresh session
- */
- if (ctx->ct_flags & SMBCF_SSNACTIVE || renego) {
- renego = 0;
- /* don't clobber workgroup name, pass null arg */
- error = smb_ctx_negotiate(ctx, SMBL_SHARE, SMBLK_CREATE, NULL);
- if (error)
- return (error);
- }
- if (browseok && !sh->ioc_share[0]) {
- ctx->ct_flags &= ~SMBCF_AUTHREQ;
- error = smb_browse(ctx, 0);
- if (ctx->ct_flags & SMBCF_KCFOUND && smb_autherr(error)) {
- smb_error(dgettext(TEXT_DOMAIN,
- "smb_ctx_resolve: bad keychain entry"), 0);
- ctx->ct_flags |= SMBCF_KCBAD;
- renego = 1;
- goto reauth;
- }
- if (error) /* auth, user cancel, or other error */
- return (error);
+ if (ctx->ct_password[0] == '\0')
+ (void) smb_get_keychain(ctx);
/*
- * Re-authenticate button was pressed?
+ * If we're doing p/w based auth,
+ * that means not using Kerberos.
*/
- if (ctx->ct_flags & SMBCF_AUTHREQ)
- goto reauth;
- if (!sh->ioc_share[0] && !(ctx->ct_flags & SMBCF_XXX)) {
- smb_error(dgettext(TEXT_DOMAIN,
- "no share specified for %s@%s"),
- 0, ssn->ioc_user, ssn->ioc_srvname);
- return (EINVAL);
- }
+ if (ctx->ct_password[0] != '\0')
+ ctx->ct_authflags &= ~SMB_AT_KRB5;
+ /*
+ * Mask out disallowed auth types.
+ */
+ ctx->ct_authflags &= ctx->ct_minauth;
+ }
+ if (ctx->ct_authflags == 0) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "no valid auth. types"), 0);
+ return (ENOTSUP);
}
- ctx->ct_flags |= SMBCF_RESOLVED;
+ ctx->ct_flags |= SMBCF_RESOLVED;
if (smb_debug)
dump_ctx("after smb_ctx_resolve", ctx);
@@ -1143,50 +1070,23 @@ reauth:
int
smb_open_driver()
{
- char buf[20];
- int err, fd, i;
+ int err, fd;
uint32_t version;
- /*
- * First try to open as clone
- */
fd = open("/dev/"NSMB_NAME, O_RDWR);
- if (fd >= 0)
- goto opened;
-
- err = errno; /* from open */
-#ifdef APPLE
- /*
- * well, no clone capabilities available - we have to scan
- * all devices in order to get free one
- */
- for (i = 0; i < 1024; i++) {
- snprintf(buf, sizeof (buf), "/dev/%s%d", NSMB_NAME, i);
- fd = open(buf, O_RDWR);
- if (fd >= 0)
- goto opened;
- if (i && POWEROF2(i+1))
- smb_error(dgettext(TEXT_DOMAIN,
- "%d failures to open smb device"), errno, i+1);
+ if (fd < 0) {
+ err = errno;
+ smb_error(dgettext(TEXT_DOMAIN,
+ "failed to open driver"), err);
+ return (-1);
}
- err = ENOENT;
-#endif
- smb_error(dgettext(TEXT_DOMAIN,
- "failed to open %s"), err, "/dev/" NSMB_NAME);
- return (-1);
-opened:
/*
* Check the driver version (paranoia)
* Do this BEFORE any other ioctl calls.
*/
- if (ioctl(fd, SMBIOC_GETVERS, &version) < 0) {
- err = errno;
- smb_error(dgettext(TEXT_DOMAIN,
- "failed to get driver version"), err);
- close(fd);
- return (-1);
- }
+ if (ioctl(fd, SMBIOC_GETVERS, &version) < 0)
+ version = 0;
if (version != NSMB_VERSION) {
smb_error(dgettext(TEXT_DOMAIN,
"incorrect driver version"), 0);
@@ -1194,18 +1094,21 @@ opened:
return (-1);
}
+ /* This handle controls per-process resources. */
+ (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+
return (fd);
}
-static int
+int
smb_ctx_gethandle(struct smb_ctx *ctx)
{
- int err, fd;
+ int fd;
- if (ctx->ct_fd != -1) {
+ if (ctx->ct_dev_fd != -1) {
rpc_cleanup_smbctx(ctx);
- close(ctx->ct_fd);
- ctx->ct_fd = -1;
+ close(ctx->ct_dev_fd);
+ ctx->ct_dev_fd = -1;
ctx->ct_flags &= ~SMBCF_SSNACTIVE;
}
@@ -1213,733 +1116,195 @@ smb_ctx_gethandle(struct smb_ctx *ctx)
if (fd < 0)
return (ENODEV);
- ctx->ct_fd = fd;
+ ctx->ct_dev_fd = fd;
return (0);
}
-int
-smb_ctx_ioctl(struct smb_ctx *ctx, int inum, struct smbioc_lookup *rqp)
-{
- size_t siz = DEF_SEC_TOKEN_LEN;
- int rc = 0;
- struct sockaddr sap1, sap2;
- int i;
-
- if (rqp->ioc_ssn.ioc_outtok)
- free(rqp->ioc_ssn.ioc_outtok);
- rqp->ioc_ssn.ioc_outtoklen = siz;
- rqp->ioc_ssn.ioc_outtok = malloc(siz+1);
- if (rqp->ioc_ssn.ioc_outtok == NULL)
- return (ENOMEM);
- bzero(rqp->ioc_ssn.ioc_outtok, siz+1);
- /* Note: No longer put length in outtok[0] */
- /* *((int *)rqp->ioc_ssn.ioc_outtok) = (int)siz; */
-
- if (ioctl(ctx->ct_fd, inum, rqp) == -1) {
- rc = errno;
- goto out;
- }
- if (rqp->ioc_ssn.ioc_outtoklen <= siz)
- goto out;
-
- /*
- * Operation completed, but our output token wasn't large enough.
- * The re-call below only pulls the token from the kernel.
- */
- siz = rqp->ioc_ssn.ioc_outtoklen;
- free(rqp->ioc_ssn.ioc_outtok);
- rqp->ioc_ssn.ioc_outtok = malloc(siz + 1);
- if (rqp->ioc_ssn.ioc_outtok == NULL) {
- rc = ENOMEM;
- goto out;
- }
- bzero(rqp->ioc_ssn.ioc_outtok, siz+1);
- /* Note: No longer put length in outtok[0] */
- /* *((int *)rqp->ioc_ssn.ioc_outtok) = siz; */
- if (ioctl(ctx->ct_fd, inum, rqp) == -1)
- rc = errno;
-out:
- return (rc);
-}
-
-int
-smb_ctx_findvc(struct smb_ctx *ctx, int level, int flags)
-{
- struct smbioc_lookup rq;
- int error = 0;
-
- if ((error = smb_ctx_gethandle(ctx)))
- return (error);
-
- bzero(&rq, sizeof (rq));
- bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn));
- bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare));
-
- rq.ioc_flags = flags;
- rq.ioc_level = level;
-
- return (smb_ctx_ioctl(ctx, SMBIOC_FINDVC, &rq));
-}
/*
- * adds a GSSAPI wrapper
+ * Find or create a connection + logon session
*/
-char *
-smb_ctx_tkt2gtok(uchar_t *tkt, ulong_t tktlen,
- uchar_t **gtokp, ulong_t *gtoklenp)
-{
- ulong_t bloblen = tktlen;
- ulong_t len;
- uchar_t krbapreq[2] = "\x01\x00"; /* see RFC 1964 */
- char *failure;
- uchar_t *blob = NULL; /* result */
- uchar_t *b;
-
- bloblen += sizeof (krbapreq);
- bloblen += g_stcMechOIDList[spnego_mech_oid_Kerberos_V5].iLen;
- len = bloblen;
- bloblen = ASNDerCalcTokenLength(bloblen, bloblen);
- failure = dgettext(TEXT_DOMAIN, "smb_ctx_tkt2gtok malloc");
- if (!(blob = malloc(bloblen)))
- goto out;
- b = blob;
- b += ASNDerWriteToken(b, SPNEGO_NEGINIT_APP_CONSTRUCT, NULL, len);
- b += ASNDerWriteOID(b, spnego_mech_oid_Kerberos_V5);
- memcpy(b, krbapreq, sizeof (krbapreq));
- b += sizeof (krbapreq);
- failure = dgettext(TEXT_DOMAIN, "smb_ctx_tkt2gtok insanity check");
- if (b + tktlen != blob + bloblen)
- goto out;
- memcpy(b, tkt, tktlen);
- *gtoklenp = bloblen;
- *gtokp = blob;
- failure = NULL;
-out:;
- if (blob && failure)
- free(blob);
- return (failure);
-}
-
-
-/*
- * Initialization for Kerberos, pulled out of smb_ctx_principal2tkt.
- * This just gets our cached credentials, if we have any.
- * Based on the "klist" command.
- */
-char *
-smb_ctx_krb5init(struct smb_ctx *ctx)
+int
+smb_ctx_get_ssn(struct smb_ctx *ctx)
{
- char *failure;
- krb5_error_code kerr;
- krb5_context kctx = NULL;
- krb5_ccache kcc = NULL;
- krb5_principal kprin = NULL;
-
- kerr = krb5_init_context(&kctx);
- if (kerr) {
- failure = "krb5_init_context";
- goto out;
- }
- ctx->ct_krb5ctx = kctx;
-
- /* non-default would instead use krb5_cc_resolve */
- kerr = krb5_cc_default(kctx, &kcc);
- if (kerr) {
- failure = "krb5_cc_default";
- goto out;
- }
- ctx->ct_krb5cc = kcc;
+ int err = 0;
- /*
- * Get the client principal (ticket),
- * or find out if we don't have one.
- */
- kerr = krb5_cc_get_principal(kctx, kcc, &kprin);
- if (kerr) {
- failure = "krb5_cc_get_principal";
- goto out;
- }
- ctx->ct_krb5cp = kprin;
-
- if (smb_verbose) {
- fprintf(stderr, gettext("Ticket cache: %s:%s\n"),
- krb5_cc_get_type(kctx, kcc),
- krb5_cc_get_name(kctx, kcc));
- }
- failure = NULL;
-
-out:
- return (failure);
-}
-
-
-/*
- * See "Windows 2000 Kerberos Interoperability" paper by
- * Christopher Nebergall. RC4 HMAC is the W2K default but
- * Samba support lagged (not due to Samba itself, but due to OS'
- * Kerberos implementations.)
- *
- * Only session enc type should matter, not ticket enc type,
- * per Sam Hartman on krbdev.
- *
- * Preauthentication failure topics in krb-protocol may help here...
- * try "John Brezak" and/or "Clifford Neuman" too.
- */
-static krb5_enctype kenctypes[] = {
- ENCTYPE_ARCFOUR_HMAC, /* defined in Tiger krb5.h */
- ENCTYPE_DES_CBC_MD5,
- ENCTYPE_DES_CBC_CRC,
- ENCTYPE_NULL
-};
+ if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
+ return (EINVAL);
-/*
- * Obtain a kerberos ticket...
- * (if TLD != "gov" then pray first)
- */
-char *
-smb_ctx_principal2tkt(
- struct smb_ctx *ctx, char *prin,
- uchar_t **tktp, ulong_t *tktlenp)
-{
- char *failure;
- krb5_context kctx = NULL;
- krb5_error_code kerr;
- krb5_ccache kcc = NULL;
- krb5_principal kprin = NULL, cprn = NULL;
- krb5_creds kcreds, *kcredsp = NULL;
- krb5_auth_context kauth = NULL;
- krb5_data kdata, kdata0;
- uchar_t *tkt;
-
- memset((char *)&kcreds, 0, sizeof (kcreds));
- kdata0.length = 0;
-
- /* These shoud have been done in smb_ctx_krb5init() */
- if (ctx->ct_krb5ctx == NULL ||
- ctx->ct_krb5cc == NULL ||
- ctx->ct_krb5cp == NULL) {
- failure = "smb_ctx_krb5init";
- goto out;
+ if (ctx->ct_dev_fd < 0) {
+ if ((err = smb_ctx_gethandle(ctx)))
+ return (err);
}
- kctx = ctx->ct_krb5ctx;
- kcc = ctx->ct_krb5cc;
- cprn = ctx->ct_krb5cp;
- failure = "krb5_set_default_tgs_enctypes";
- if ((kerr = krb5_set_default_tgs_enctypes(kctx, kenctypes)))
- goto out;
/*
- * The following is an unrolling of krb5_mk_req. Something like:
- * krb5_mk_req(kctx, &kauth, 0, service(prin), hostname(prin),
- * &kdata0, kcc, &kdata);)
- * ...except we needed krb5_parse_name not krb5_sname_to_principal.
+ * Check whether the driver already has a VC
+ * we can use. If so, we're done!
*/
- failure = "krb5_parse_name";
- if ((kerr = krb5_parse_name(kctx, prin, &kprin)))
- goto out;
- failure = "krb5_copy_principal(server)";
- if ((kerr = krb5_copy_principal(kctx, kprin, &kcreds.server)))
- goto out;
- failure = "krb5_copy_principal(client)";
- if ((kerr = krb5_copy_principal(kctx, cprn, &kcreds.client)))
- goto out;
- failure = "krb5_get_credentials";
- if ((kerr = krb5_get_credentials(kctx, 0, kcc, &kcreds, &kcredsp)))
- goto out;
- failure = "krb5_mk_req_extended";
- if ((kerr = krb5_mk_req_extended(kctx, &kauth, 0, &kdata0, kcredsp,
- &kdata)))
- goto out;
- failure = "malloc";
- if (!(tkt = malloc(kdata.length))) {
- krb5_free_data_contents(kctx, &kdata);
- goto out;
- }
- *tktlenp = kdata.length;
- memcpy(tkt, kdata.data, kdata.length);
- krb5_free_data_contents(kctx, &kdata);
- *tktp = tkt;
- failure = NULL;
-out:;
- if (kerr) {
- if (!failure)
- failure = "smb_ctx_principal2tkt";
+ err = smb_ctx_findvc(ctx);
+ if (err == 0) {
+ DPRINT("found an existing VC");
+ } else {
/*
- * Avoid logging the typical "No credentials cache found"
+ * This calls the IOD to create a new session.
*/
- if (kerr != KRB5_FCC_NOFILE ||
- strcmp(failure, "krb5_cc_get_principal"))
- com_err(__progname, kerr, failure);
- }
- if (kauth)
- krb5_auth_con_free(kctx, kauth);
- if (kcredsp)
- krb5_free_creds(kctx, kcredsp);
- if (kcreds.server || kcreds.client)
- krb5_free_cred_contents(kctx, &kcreds);
- if (kprin)
- krb5_free_principal(kctx, kprin);
-
- /* Free kctx in smb_ctx_done */
-
- return (failure);
-}
+ DPRINT("setup a new VC");
+ err = smb_ctx_newvc(ctx);
+ if (err != 0)
+ return (err);
-char *
-smb_ctx_principal2blob(
- struct smb_ctx *ctx,
- smbioc_ossn_t *ssn,
- char *prin)
-{
- int rc = 0;
- char *failure;
- uchar_t *tkt = NULL;
- ulong_t tktlen;
- uchar_t *gtok = NULL; /* gssapi token */
- ulong_t gtoklen; /* gssapi token length */
- SPNEGO_TOKEN_HANDLE stok = NULL; /* spnego token */
- void *blob = NULL; /* result */
- ulong_t bloblen; /* result length */
-
- if ((failure = smb_ctx_principal2tkt(ctx, prin, &tkt, &tktlen)))
- goto out;
- if ((failure = smb_ctx_tkt2gtok(tkt, tktlen, &gtok, &gtoklen)))
- goto out;
- /*
- * RFC says to send NegTokenTarg now. So does MS docs. But
- * win2k gives ERRbaduid if we do... we must send
- * another NegTokenInit now!
- */
- failure = "spnegoCreateNegTokenInit";
- if ((rc = spnegoCreateNegTokenInit(spnego_mech_oid_Kerberos_V5_Legacy,
- 0, gtok, gtoklen, NULL, 0, &stok)))
- goto out;
- failure = "spnegoTokenGetBinary(NULL)";
- rc = spnegoTokenGetBinary(stok, NULL, &bloblen);
- if (rc != SPNEGO_E_BUFFER_TOO_SMALL)
- goto out;
- failure = "malloc";
- if (!(blob = malloc((size_t)bloblen)))
- goto out;
- /* No longer store length at start of blob. */
- /* *blob = bloblen; */
- failure = "spnegoTokenGetBinary";
- if ((rc = spnegoTokenGetBinary(stok, blob, &bloblen)))
- goto out;
- ssn->ioc_intoklen = bloblen;
- ssn->ioc_intok = blob;
- failure = NULL;
-out:;
- if (rc) {
- /* XXX better is to embed rc in failure */
- smb_error(dgettext(TEXT_DOMAIN,
- "spnego principal2blob error %d"), 0, -rc);
- if (!failure)
- failure = "spnego";
+ /*
+ * Call findvc again. The new VC sould be
+ * found in the driver this time.
+ */
+ err = smb_ctx_findvc(ctx);
}
- if (blob && failure)
- free(blob);
- if (stok)
- spnegoFreeData(stok);
- if (gtok)
- free(gtok);
- if (tkt)
- free(tkt);
- return (failure);
-}
-
-#if 0
-void
-prblob(uchar_t *b, size_t len)
-{
- while (len--)
- fprintf(stderr, "%02x", *b++);
- fprintf(stderr, "\n");
+ return (err);
}
-#endif
-
/*
- * We navigate the SPNEGO & ASN1 encoding to find a kerberos principal
- * Note: driver no longer puts length at start of blob.
+ * Get the string representation of a share "use" type,
+ * as needed for the "service" in tree connect.
*/
-char *
-smb_ctx_blob2principal(
- struct smb_ctx *ctx,
- smbioc_ossn_t *ssn,
- char **prinp)
+static const char *
+smb_use_type_str(smb_use_shtype_t stype)
{
- uchar_t *blob = ssn->ioc_outtok;
- size_t len = ssn->ioc_outtoklen;
- int rc = 0;
- SPNEGO_TOKEN_HANDLE stok = NULL;
- int indx = 0;
- char *failure;
- uchar_t flags = 0;
- unsigned long plen = 0;
- uchar_t *prin;
-
-#if 0
- fprintf(stderr, "blob from negotiate:\n");
- prblob(blob, len);
-#endif
+ const char *pp;
- /* Skip the GUID */
- assert(len >= SMB_GUIDLEN);
- blob += SMB_GUIDLEN;
- len -= SMB_GUIDLEN;
-
- failure = "spnegoInitFromBinary";
- if ((rc = spnegoInitFromBinary(blob, len, &stok)))
- goto out;
- /*
- * Needn't use new Kerberos OID - the Legacy one is fine.
- */
- failure = "spnegoIsMechTypeAvailable";
- if (spnegoIsMechTypeAvailable(stok, spnego_mech_oid_Kerberos_V5_Legacy,
- &indx))
- goto out;
- /*
- * Ignoring optional context flags for now. May want to pass
- * them to krb5 layer. XXX
- */
- if (!spnegoGetContextFlags(stok, &flags))
- fprintf(stderr, dgettext(TEXT_DOMAIN,
- "spnego context flags 0x%x\n"), flags);
- failure = "spnegoGetMechListMIC(NULL)";
- rc = spnegoGetMechListMIC(stok, NULL, &plen);
- if (rc != SPNEGO_E_BUFFER_TOO_SMALL)
- goto out;
- failure = "malloc";
- if (!(prin = malloc(plen + 1)))
- goto out;
- failure = "spnegoGetMechListMIC";
- if ((rc = spnegoGetMechListMIC(stok, prin, &plen))) {
- free(prin);
- goto out;
- }
- prin[plen] = '\0';
- *prinp = (char *)prin;
- failure = NULL;
-out:;
- if (stok)
- spnegoFreeData(stok);
- if (rc) {
- /* XXX better is to embed rc in failure */
- smb_error(dgettext(TEXT_DOMAIN,
- "spnego blob2principal error %d"), 0, -rc);
- if (!failure)
- failure = "spnego";
+ switch (stype) {
+ default:
+ case USE_WILDCARD:
+ pp = "?????";
+ break;
+ case USE_DISKDEV:
+ pp = "A:";
+ break;
+ case USE_SPOOLDEV:
+ pp = "LPT1:";
+ break;
+ case USE_CHARDEV:
+ pp = "COMM";
+ break;
+ case USE_IPC:
+ pp = "IPC";
+ break;
}
- return (failure);
+ return (pp);
}
-
+/*
+ * Find or create a tree connection
+ */
int
-smb_ctx_negotiate(struct smb_ctx *ctx, int level, int flags, char *workgroup)
+smb_ctx_get_tree(struct smb_ctx *ctx)
{
- struct smbioc_lookup rq;
- int error = 0;
- char *failure = NULL;
- char *principal = NULL;
- char c;
- int i;
- ssize_t *outtoklen;
- uchar_t *blob;
+ smbioc_tcon_t *tcon = NULL;
+ const char *stype;
+ int cmd, err = 0;
- /*
- * We leave ct_secblob set iff extended security
- * negotiation succeeds.
- */
- if (ctx->ct_secblob) {
- free(ctx->ct_secblob);
- ctx->ct_secblob = NULL;
- }
-#ifdef XXX
- if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
- smb_error(dgettext(TEXT_DOMAIN,
- "smb_ctx_lookup() data is not resolved"), 0);
+ if (ctx->ct_dev_fd < 0 ||
+ ctx->ct_origshare == NULL) {
return (EINVAL);
}
-#endif
- if ((error = smb_ctx_gethandle(ctx)))
- return (error);
-
- bzero(&rq, sizeof (rq));
- bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn));
- bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare));
-
- /*
- * Find out if we have a Kerberos ticket,
- * and only offer SPNEGO if we have one.
- */
- failure = smb_ctx_krb5init(ctx);
- if (failure) {
- if (smb_verbose)
- smb_error(failure, 0);
- goto out;
- }
-
- rq.ioc_flags = flags;
- rq.ioc_level = level;
- rq.ioc_ssn.ioc_opt |= SMBVOPT_EXT_SEC;
- error = smb_ctx_ioctl(ctx, SMBIOC_NEGOTIATE, &rq);
- if (error) {
- failure = dgettext(TEXT_DOMAIN, "negotiate failed");
- smb_error(failure, error);
- if (error == ETIMEDOUT)
- return (error);
- goto out;
- }
- /*
- * If the server capabilities did not include
- * SMB_CAP_EXT_SECURITY then the driver clears
- * the flag SMBVOPT_EXT_SEC for us.
- * XXX: should add the capabilities to ioc_ssn
- * XXX: see comment in driver - smb_usr.c
- */
- failure = dgettext(TEXT_DOMAIN, "SPNEGO unsupported");
- if ((rq.ioc_ssn.ioc_opt & SMBVOPT_EXT_SEC) == 0) {
- if (smb_verbose)
- smb_error(failure, 0);
- /*
- * Do regular (old style) NTLM or NTLMv2
- * Nothing more to do here in negotiate.
- */
- return (0);
- }
-
- /*
- * Capabilities DO include SMB_CAP_EXT_SECURITY,
- * so this should be an SPNEGO security blob.
- * Parse the ASN.1/DER, prepare response(s).
- * XXX: Handle STATUS_MORE_PROCESSING_REQUIRED?
- * XXX: Requires additional session setup calls.
- */
- if (rq.ioc_ssn.ioc_outtoklen <= SMB_GUIDLEN)
- goto out;
- /* some servers send padding junk */
- blob = rq.ioc_ssn.ioc_outtok;
- if (blob[0] == 0)
- goto out;
- failure = smb_ctx_blob2principal(
- ctx, &rq.ioc_ssn, &principal);
- if (failure)
- goto out;
- failure = smb_ctx_principal2blob(
- ctx, &rq.ioc_ssn, principal);
- if (failure)
- goto out;
+ cmd = SMBIOC_TREE_CONNECT;
+ tcon = malloc(sizeof (*tcon));
+ if (tcon == NULL)
+ return (ENOMEM);
+ bzero(tcon, sizeof (*tcon));
+ tcon->tc_flags = SMBLK_CREATE;
+ tcon->tc_opt = 0;
- /* Success! Save the blob to send next. */
- ctx->ct_secblob = rq.ioc_ssn.ioc_intok;
- ctx->ct_secbloblen = rq.ioc_ssn.ioc_intoklen;
- rq.ioc_ssn.ioc_intok = NULL;
+ /* The share name */
+ strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare,
+ sizeof (tcon->tc_sh.sh_name));
-out:
- if (principal)
- free(principal);
- if (rq.ioc_ssn.ioc_intok)
- free(rq.ioc_ssn.ioc_intok);
- if (rq.ioc_ssn.ioc_outtok)
- free(rq.ioc_ssn.ioc_outtok);
- if (!failure)
- return (0); /* Success! */
+ /* The share "use" type. */
+ stype = smb_use_type_str(ctx->ct_shtype_req);
+ strlcpy(tcon->tc_sh.sh_type_req, stype,
+ sizeof (tcon->tc_sh.sh_type_req));
/*
- * Negotiate failed with "extended security".
+ * Todo: share passwords for share-level security.
*
- * XXX: If we are doing SPNEGO correctly,
- * we should never get here unless the user
- * supplied invalid authentication data,
- * or we saw some kind of protocol error.
- *
- * XXX: The error message below should be
- * XXX: unconditional (remove "if verbose")
- * XXX: but not until we have "NTLMSSP"
- * Avoid spew for anticipated failure modes
- * but enable this with the verbose flag
+ * The driver does the actual TCON call.
*/
- if (smb_verbose) {
- smb_error(dgettext(TEXT_DOMAIN,
- "%s (extended security negotiate)"), error, failure);
+ if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
+ err = errno;
+ goto out;
}
/*
- * XXX: Try again using NTLM (or NTLMv2)
- * XXX: Normal clients don't do this.
- * XXX: Should just return an error, but
- * keep the fall-back to NTLM for now.
- *
- * Start over with a new connection.
+ * Check the returned share type
*/
- if ((error = smb_ctx_gethandle(ctx)))
- return (error);
- bzero(&rq, sizeof (rq));
- bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn));
- bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare));
- rq.ioc_flags = flags;
- rq.ioc_level = level;
- /* Note: NO SMBVOPT_EXT_SEC */
- error = smb_ctx_ioctl(ctx, SMBIOC_NEGOTIATE, &rq);
- if (error) {
- failure = dgettext(TEXT_DOMAIN, "negotiate failed");
- smb_error(failure, error);
- rpc_cleanup_smbctx(ctx);
- close(ctx->ct_fd);
- ctx->ct_fd = -1;
- return (error);
+ DPRINT("ret. sh_type: \"%s\"", tcon->tc_sh.sh_type_ret);
+ if (ctx->ct_shtype_req != USE_WILDCARD &&
+ 0 != strcmp(stype, tcon->tc_sh.sh_type_ret)) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: incompatible share type"),
+ 0, ctx->ct_origshare);
+ err = EINVAL;
}
- /*
- * Used to copy the workgroup out of the SMB_NEGOTIATE response
- * here, to default our domain name to be the same as the server.
- * Not a good idea: Unnecessary at best, and sometimes wrong, i.e.
- * when our account is in a trusted domain.
- */
+out:
+ if (tcon != NULL)
+ free(tcon);
- return (error);
+ return (err);
}
-
+/*
+ * Return the hflags2 word for an smb_ctx.
+ */
int
-smb_ctx_tdis(struct smb_ctx *ctx)
+smb_ctx_flags2(struct smb_ctx *ctx)
{
- struct smbioc_lookup rq; /* XXX may be used, someday */
- int error = 0;
+ uint16_t flags2;
- if (ctx->ct_fd < 0) {
+ if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
smb_error(dgettext(TEXT_DOMAIN,
- "tree disconnect without handle?!"), 0);
- return (EINVAL);
- }
- if (!(ctx->ct_flags & SMBCF_SSNACTIVE)) {
- smb_error(dgettext(TEXT_DOMAIN,
- "tree disconnect without session?!"), 0);
- return (EINVAL);
- }
- bzero(&rq, sizeof (rq));
- bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn));
- bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare));
- if (ioctl(ctx->ct_fd, SMBIOC_TDIS, &rq) == -1) {
- error = errno;
- smb_error(dgettext(TEXT_DOMAIN,
- "tree disconnect failed"), error);
+ "can't get flags2 for a session"), errno);
+ return (-1);
}
- return (error);
+ return (flags2);
}
-
+/*
+ * Get the transport level session key.
+ * Must already have an active SMB session.
+ */
int
-smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags)
+smb_ctx_get_ssnkey(struct smb_ctx *ctx, uchar_t *key, size_t len)
{
- struct smbioc_lookup rq;
- int error = 0;
- char *failure = NULL;
-
- if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
- smb_error(dgettext(TEXT_DOMAIN,
- "smb_ctx_lookup() data is not resolved"), 0);
- return (EINVAL);
- }
- if (ctx->ct_fd < 0) {
- smb_error(dgettext(TEXT_DOMAIN,
- "handle from smb_ctx_nego() gone?!"), 0);
+ if (len < SMBIOC_HASH_SZ)
return (EINVAL);
- }
- if (!(flags & SMBLK_CREATE))
- return (0);
- bzero(&rq, sizeof (rq));
- bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn));
- bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare));
- rq.ioc_flags = flags;
- rq.ioc_level = level;
-
- /*
- * Iff we have a security blob, we're using
- * extended security...
- */
- if (ctx->ct_secblob) {
- rq.ioc_ssn.ioc_opt |= SMBVOPT_EXT_SEC;
- if (!(ctx->ct_flags & SMBCF_SSNACTIVE)) {
- rq.ioc_ssn.ioc_intok = ctx->ct_secblob;
- rq.ioc_ssn.ioc_intoklen = ctx->ct_secbloblen;
- error = smb_ctx_ioctl(ctx, SMBIOC_SSNSETUP, &rq);
- }
- rq.ioc_ssn.ioc_intok = NULL;
- if (error) {
- failure = dgettext(TEXT_DOMAIN,
- "session setup failed");
- } else {
- ctx->ct_flags |= SMBCF_SSNACTIVE;
- if ((error = smb_ctx_ioctl(ctx, SMBIOC_TCON, &rq)))
- failure = dgettext(TEXT_DOMAIN,
- "tree connect failed");
- }
- if (rq.ioc_ssn.ioc_intok)
- free(rq.ioc_ssn.ioc_intok);
- if (rq.ioc_ssn.ioc_outtok)
- free(rq.ioc_ssn.ioc_outtok);
- if (!failure)
- return (0);
- smb_error(dgettext(TEXT_DOMAIN,
- "%s (extended security lookup2)"), error, failure);
- /* unwise to failback to NTLM now */
- return (error);
- }
- /*
- * Otherwise we're doing plain old NTLM
- */
- if ((ctx->ct_flags & SMBCF_SSNACTIVE) == 0) {
- /*
- * This is the magic that tells the driver to
- * copy the password from the keychain, and
- * whether to use the system name or the
- * account domain to lookup the keychain.
- */
- if (ctx->ct_flags & SMBCF_KCFOUND)
- rq.ioc_ssn.ioc_opt |= SMBVOPT_USE_KEYCHAIN;
- if (ctx->ct_flags & SMBCF_KCDOMAIN)
- rq.ioc_ssn.ioc_opt |= SMBVOPT_KC_DOMAIN;
- if (ioctl(ctx->ct_fd, SMBIOC_SSNSETUP, &rq) < 0) {
- error = errno;
- failure = dgettext(TEXT_DOMAIN, "session setup");
- goto out;
- }
- ctx->ct_flags |= SMBCF_SSNACTIVE;
- }
- if (ioctl(ctx->ct_fd, SMBIOC_TCON, &rq) == -1) {
- error = errno;
- failure = dgettext(TEXT_DOMAIN, "tree connect");
- }
+ if (ioctl(ctx->ct_dev_fd, SMBIOC_GETSSNKEY, key) == -1)
+ return (errno);
-out:
- if (failure) {
- error = errno;
- smb_error(dgettext(TEXT_DOMAIN,
- "%s phase failed"), error, failure);
- }
- return (error);
+ return (0);
}
+
/*
- * Return the hflags2 word for an smb_ctx.
+ * RC file parsing stuff
*/
-int
-smb_ctx_flags2(struct smb_ctx *ctx)
-{
- uint16_t flags2;
- if (ioctl(ctx->ct_fd, SMBIOC_FLAGS2, &flags2) == -1) {
- smb_error(dgettext(TEXT_DOMAIN,
- "can't get flags2 for a session"), errno);
- return (-1);
- }
- return (flags2);
-}
+struct nv {
+ char *name;
+ int value;
+} minauth_table[] = {
+ /* Allowed auth. types */
+ { "kerberos", SMB_AT_KRB5 },
+ { "ntlmv2", SMB_AT_KRB5|SMB_AT_NTLM2 },
+ { "ntlm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 },
+ { "lm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 },
+ { "none", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1|
+ SMB_AT_ANON },
+ { NULL }
+};
+
/*
* level values:
@@ -1954,7 +1319,7 @@ smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
char *p;
int error;
-#ifdef NOT_DEFINED
+#ifdef KICONV_SUPPORT
if (level > 0) {
rc_getstringptr(smb_rc, sname, "charsets", &p);
if (p) {
@@ -1970,56 +1335,19 @@ smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
if (level <= 1) {
/* Section is: [default] or [server] */
- rc_getint(smb_rc, sname, "timeout",
- &ctx->ct_ssn.ioc_timeout);
-
-#ifdef NOT_DEFINED
- rc_getint(smb_rc, sname, "retry_count",
- &ctx->ct_ssn.ioc_retrycount);
- rc_getstringptr(smb_rc, sname, "use_negprot_domain", &p);
- if (p && strcmp(p, "NO") == 0)
- ctx->ct_flags |= SMBCF_NONEGDOM;
-#endif
-
rc_getstringptr(smb_rc, sname, "minauth", &p);
if (p) {
/*
* "minauth" was set in this section; override
* the current minimum authentication setting.
*/
- ctx->ct_ssn.ioc_opt &= ~SMBVOPT_MINAUTH;
- if (strcmp(p, "kerberos") == 0) {
- /*
- * Don't fall back to NTLMv2, NTLMv1, or
- * a clear text password.
- */
- ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_KERBEROS;
- } else if (strcmp(p, "ntlmv2") == 0) {
- /*
- * Don't fall back to NTLMv1 or a clear
- * text password.
- */
- ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NTLMV2;
- } else if (strcmp(p, "ntlm") == 0) {
- /*
- * Don't send the LM response over the wire.
- */
- ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NTLM;
- } else if (strcmp(p, "lm") == 0) {
- /*
- * Fail if the server doesn't do encrypted
- * passwords.
- */
- ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_LM;
- } else if (strcmp(p, "none") == 0) {
- /*
- * Anything goes.
- * (The following statement should be
- * optimized away.)
- */
- /* LINTED */
- ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NONE;
- } else {
+ struct nv *nvp;
+ for (nvp = minauth_table; nvp->name; nvp++)
+ if (strcmp(p, nvp->name) == 0)
+ break;
+ if (nvp->name)
+ ctx->ct_minauth = nvp->value;
+ else {
/*
* Unknown minimum authentication level.
*/
@@ -2036,15 +1364,15 @@ smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
* "signing" was set in this section; override
* the current signing settings.
*/
- ctx->ct_ssn.ioc_opt &= ~SMBVOPT_SIGNING_MASK;
+ ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK;
if (strcmp(p, "disabled") == 0) {
/* leave flags zero (expr for lint) */
- (void) ctx->ct_ssn.ioc_opt;
+ (void) ctx->ct_vopt;
} else if (strcmp(p, "enabled") == 0) {
- ctx->ct_ssn.ioc_opt |=
+ ctx->ct_vopt |=
SMBVOPT_SIGNING_ENABLED;
} else if (strcmp(p, "required") == 0) {
- ctx->ct_ssn.ioc_opt |=
+ ctx->ct_vopt |=
SMBVOPT_SIGNING_ENABLED |
SMBVOPT_SIGNING_REQUIRED;
} else {
@@ -2068,7 +1396,7 @@ smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
rc_getstringptr(smb_rc, sname, "workgroup", &p);
if (p) {
nls_str_upper(p, p);
- error = smb_ctx_setworkgroup(ctx, p, 0);
+ error = smb_ctx_setdomain(ctx, p, 0);
if (error)
smb_error(dgettext(TEXT_DOMAIN,
"workgroup specification in the "
@@ -2077,7 +1405,7 @@ smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
rc_getstringptr(smb_rc, sname, "domain", &p);
if (p) {
nls_str_upper(p, p);
- error = smb_ctx_setworkgroup(ctx, p, 0);
+ error = smb_ctx_setdomain(ctx, p, 0);
if (error)
smb_error(dgettext(TEXT_DOMAIN,
"domain specification in the "
@@ -2132,11 +1460,25 @@ smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
int
smb_ctx_readrc(struct smb_ctx *ctx)
{
- char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN +
- SMB_MAXSHARENAMELEN + 4];
+ char *home;
+ char *sname = NULL;
+ int sname_max;
+ int err = 0;
+
+ if ((home = getenv("HOME")) == NULL)
+ home = ctx->ct_home;
+ if ((err = smb_open_rcfile(home)) != 0) {
+ DPRINT("smb_open_rcfile, err=%d", err);
+ /* ignore any error here */
+ return (0);
+ }
- if (smb_open_rcfile(ctx) != 0)
+ sname_max = 3 * SMBIOC_MAX_NAME + 4;
+ sname = malloc(sname_max);
+ if (sname == NULL) {
+ err = ENOMEM;
goto done;
+ }
/*
* default parameters (level=0)
@@ -2148,47 +1490,51 @@ smb_ctx_readrc(struct smb_ctx *ctx)
* If we don't have a server name, we can't read any of the
* [server...] sections.
*/
- if (ctx->ct_ssn.ioc_srvname[0] == 0)
+ if (ctx->ct_fullserver == NULL)
goto done;
-
/*
* SERVER parameters.
*/
- smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1);
+ smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1);
/*
* If we don't have a user name, we can't read any of the
* [server:user...] sections.
*/
- if (ctx->ct_ssn.ioc_user[0] == 0)
+ if (ctx->ct_user[0] == 0)
goto done;
-
/*
* SERVER:USER parameters
*/
- snprintf(sname, sizeof (sname), "%s:%s",
- ctx->ct_ssn.ioc_srvname,
- ctx->ct_ssn.ioc_user);
+ snprintf(sname, sname_max, "%s:%s",
+ ctx->ct_fullserver,
+ ctx->ct_user);
smb_ctx_readrcsection(ctx, sname, 2);
+
/*
* If we don't have a share name, we can't read any of the
* [server:user:share] sections.
*/
- if (ctx->ct_sh.ioc_share[0] != 0) {
- /*
- * SERVER:USER:SHARE parameters
- */
- snprintf(sname, sizeof (sname), "%s:%s:%s",
- ctx->ct_ssn.ioc_srvname,
- ctx->ct_ssn.ioc_user,
- ctx->ct_sh.ioc_share);
- smb_ctx_readrcsection(ctx, sname, 3);
- }
+ if (ctx->ct_origshare == NULL)
+ goto done;
+ /*
+ * SERVER:USER:SHARE parameters
+ */
+ snprintf(sname, sname_max, "%s:%s:%s",
+ ctx->ct_fullserver,
+ ctx->ct_user,
+ ctx->ct_origshare);
+ smb_ctx_readrcsection(ctx, sname, 3);
done:
+ if (sname)
+ free(sname);
+ smb_close_rcfile();
if (smb_debug)
dump_ctx("after smb_ctx_readrc", ctx);
+ if (err)
+ DPRINT("err=%d\n", err);
- return (0);
+ return (err);
}
diff --git a/usr/src/lib/libsmbfs/smb/derparse.c b/usr/src/lib/libsmbfs/smb/derparse.c
index cc7d61c6bd..0180e064ed 100644
--- a/usr/src/lib/libsmbfs/smb/derparse.c
+++ b/usr/src/lib/libsmbfs/smb/derparse.c
@@ -1,4 +1,3 @@
-/*
// Copyright (C) 2002 Microsoft Corporation
// All rights reserved.
//
@@ -23,10 +22,6 @@
//
/////////////////////////////////////////////////////////////
-*/
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
@@ -34,12 +29,11 @@
#include "spnego.h"
#include "derparse.h"
-/*
//
// The GSS Mechanism OID enumeration values (SPNEGO_MECH_OID) control which offset in
// the array below, that a mechanism can be found.
//
-*/
+
#pragma error_messages (off,E_INITIALIZATION_TYPE_MISMATCH)
MECH_OID g_stcMechOIDList [] =
{
@@ -55,7 +49,6 @@ MECH_OID g_stcMechOIDList [] =
};
#pragma error_messages (default,E_INITIALIZATION_TYPE_MISMATCH)
-/*
/////////////////////////////////////////////////////////////////////////////
//
// Function:
@@ -78,7 +71,6 @@ MECH_OID g_stcMechOIDList [] =
// process lengths that take more than 4 bytes.
//
////////////////////////////////////////////////////////////////////////////
-*/
int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength,
long* pnNumLengthBytes )
@@ -180,7 +172,6 @@ int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pn
}
-/*
/////////////////////////////////////////////////////////////////////////////
//
// Function:
@@ -206,7 +197,6 @@ int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pn
// length must also not exceed the specified boundary length .
//
////////////////////////////////////////////////////////////////////////////
-*/
int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken,
long nLengthWithToken, long nBoundaryLength,
@@ -271,7 +261,6 @@ int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken,
return nReturn;
}
-/*
/////////////////////////////////////////////////////////////////////////////
//
// Function:
@@ -292,7 +281,6 @@ int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken,
// Checks the data pointed to by pbTokenData for the specified OID.
//
////////////////////////////////////////////////////////////////////////////
-*/
int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength,
long* pnTokenLength )
@@ -327,7 +315,6 @@ int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long n
return nReturn;
}
-/*
/////////////////////////////////////////////////////////////////////////////
//
// Function:
@@ -345,7 +332,6 @@ int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long n
// enough to describea length.
//
////////////////////////////////////////////////////////////////////////////
-*/
int ASNDerCalcNumLengthBytes( long nLength )
{
diff --git a/usr/src/lib/libsmbfs/smb/file.c b/usr/src/lib/libsmbfs/smb/file.c
index e7a02e77df..74630fdd91 100644
--- a/usr/src/lib/libsmbfs/smb/file.c
+++ b/usr/src/lib/libsmbfs/smb/file.c
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -56,35 +56,32 @@
#include <sys/types.h>
#include <sys/file.h>
+#include <netsmb/smb.h>
#include <netsmb/smb_lib.h>
-#include <cflib.h>
-#include "charsets.h"
#include "private.h"
int
-smb_fh_close(struct smb_ctx *ctx, smbfh fh)
+smb_fh_close(struct smb_ctx *ctx, int fh)
{
struct smb_rq *rqp;
struct mbdata *mbp;
- int serr;
+ int error;
- serr = smb_rq_init(ctx, SMB_COM_CLOSE, 0, &rqp);
- if (serr != 0)
- return (serr);
+ error = smb_rq_init(ctx, SMB_COM_CLOSE, &rqp);
+ if (error != 0)
+ return (error);
mbp = smb_rq_getrequest(rqp);
- mb_put_uint16le(mbp, fh);
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, (uint16_t)fh);
mb_put_uint32le(mbp, 0); /* time stamp */
smb_rq_wend(rqp);
- serr = smb_rq_simple(rqp);
- if (serr != 0) {
- smb_rq_done(rqp);
- return (serr);
- }
- mbp = smb_rq_getreply(rqp);
+ mb_put_uint16le(mbp, 0); /* byte count */
+
+ error = smb_rq_simple(rqp);
smb_rq_done(rqp);
- return (serr);
+ return (error);
}
int
@@ -93,45 +90,32 @@ smb_fh_ntcreate(
int flags, int req_acc, int efattr,
int share_acc, int open_disp,
int create_opts, int impersonation,
- smbfh *fhp, uint32_t *action_taken)
+ int *fhp, uint32_t *action_taken)
{
struct smb_rq *rqp;
struct mbdata *mbp;
+ char *pathsizep;
+ int pathstart, pathsize;
+ int error, flags2, uc;
+ uint16_t fh;
uint8_t wc;
- size_t pathlen, pathsize;
- int error, flags2;
- uint16_t *upath = NULL;
flags2 = smb_ctx_flags2(ctx);
if (flags2 == -1)
return (EIO);
+ uc = flags2 & SMB_FLAGS2_UNICODE;
- error = smb_rq_init(ctx, SMB_COM_NT_CREATE_ANDX, 42, &rqp);
+ error = smb_rq_init(ctx, SMB_COM_NT_CREATE_ANDX, &rqp);
if (error != 0)
return (error);
- if (flags2 & SMB_FLAGS2_UNICODE) {
- upath = convert_utf8_to_leunicode(path);
- if (upath == NULL) {
- smb_error(dgettext(TEXT_DOMAIN,
- "%s: failed converting to UCS-2"), 0, path);
- error = EINVAL;
- goto out;
- }
- pathlen = unicode_strlen(upath);
- pathsize = (pathlen + 1) * 2;
- } else {
- pathlen = strlen(path);
- pathsize = pathlen + 1;
- }
-
mbp = smb_rq_getrequest(rqp);
- mb_put_uint8(mbp, 0xff); /* secondary command */
- mb_put_uint8(mbp, 0); /* MBZ */
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, 0xff); /* secondary command */
mb_put_uint16le(mbp, 0); /* offset to next command (none) */
- mb_put_uint8(mbp, 0); /* MBZ */
- mb_put_uint16le(mbp, pathsize); /* path size (bytes) */
- mb_put_uint32le(mbp, 0); /* create flags (oplock) */
+ mb_put_uint8(mbp, 0); /* MBZ (pad?) */
+ mb_fit(mbp, 2, &pathsizep); /* path size - fill in below */
+ mb_put_uint32le(mbp, flags); /* create flags (oplock) */
mb_put_uint32le(mbp, 0); /* FID - basis for path if not root */
mb_put_uint32le(mbp, req_acc);
mb_put_uint64le(mbp, 0); /* initial alloc. size */
@@ -139,16 +123,28 @@ smb_fh_ntcreate(
mb_put_uint32le(mbp, share_acc); /* share access mode */
mb_put_uint32le(mbp, open_disp); /* open disposition */
mb_put_uint32le(mbp, create_opts); /* create_options */
- mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */
+ mb_put_uint32le(mbp, impersonation);
mb_put_uint8(mbp, 0); /* security flags (?) */
smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ if (uc) {
+ /*
+ * We're about to put a unicode string. We know
+ * we're misaligned at this point, and need to
+ * save the mb_count at the start of the string,
+ * not at the alignment padding placed before it.
+ * So add the algnment padding by hand here.
+ */
+ mb_put_uint8(mbp, 0);
+ }
+ pathstart = mbp->mb_count;
+ mb_put_dstring(mbp, path, uc);
+ smb_rq_bend(rqp);
- /* XXX: Need a "put string" function. */
- if (flags2 & SMB_FLAGS2_UNICODE) {
- mb_put_uint8(mbp, 0); /* pad byte - align(2) for Unicode */
- mb_put_mem(mbp, (char *)upath, pathsize);
- } else
- mb_put_mem(mbp, path, pathsize);
+ /* Now go back and fill in pathsizep */
+ pathsize = mbp->mb_count - pathstart;
+ pathsizep[0] = pathsize & 0xFF;
+ pathsizep[1] = (pathsize >> 8);
error = smb_rq_simple(rqp);
if (error)
@@ -159,8 +155,8 @@ smb_fh_ntcreate(
* spec says 26 for word count, but 34 words are defined
* and observed from win2000
*/
- wc = rqp->rq_wcount;
- if (wc < 26) {
+ error = mb_get_uint8(mbp, &wc);
+ if (error || wc < 26) {
smb_error(dgettext(TEXT_DOMAIN,
"%s: open failed, bad word count"), 0, path);
error = EBADRPC;
@@ -170,7 +166,7 @@ smb_fh_ntcreate(
mb_get_uint8(mbp, NULL); /* mbz */
mb_get_uint16le(mbp, NULL); /* andxoffset */
mb_get_uint8(mbp, NULL); /* oplock lvl granted */
- mb_get_uint16le(mbp, fhp); /* FID */
+ mb_get_uint16le(mbp, &fh); /* FID */
mb_get_uint32le(mbp, action_taken);
#if 0 /* skip decoding the rest */
mb_get_uint64le(mbp, NULL); /* creation time */
@@ -183,14 +179,16 @@ smb_fh_ntcreate(
mb_get_uint16le(mbp, NULL); /* file type */
mb_get_uint16le(mbp, NULL); /* device state */
mb_get_uint8(mbp, NULL); /* directory (boolean) */
-#endif /* skip decoding */
+#endif
+
+ /* success! */
+ *fhp = fh;
+ error = 0;
out:
- if (upath)
- free(upath);
smb_rq_done(rqp);
- return (0);
+ return (error);
}
/*
@@ -198,7 +196,7 @@ out:
* Converts Unix-style open call to NTCreate.
*/
int
-smb_fh_open(struct smb_ctx *ctx, const char *path, int oflag, smbfh *fhp)
+smb_fh_open(struct smb_ctx *ctx, const char *path, int oflag, int *fhp)
{
int error, mode, open_disp, req_acc, share_acc;
char *p, *ntpath = NULL;
@@ -273,7 +271,7 @@ smb_fh_open(struct smb_ctx *ctx, const char *path, int oflag, smbfh *fhp)
}
int
-smb_fh_read(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
+smb_fh_read(struct smb_ctx *ctx, int fh, off_t offset, size_t count,
char *dst)
{
struct smbioc_rw rwrq;
@@ -283,14 +281,14 @@ smb_fh_read(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
rwrq.ioc_base = dst;
rwrq.ioc_cnt = count;
rwrq.ioc_offset = offset;
- if (ioctl(ctx->ct_fd, SMBIOC_READ, &rwrq) == -1) {
+ if (ioctl(ctx->ct_dev_fd, SMBIOC_READ, &rwrq) == -1) {
return (-1);
}
return (rwrq.ioc_cnt);
}
int
-smb_fh_write(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
+smb_fh_write(struct smb_ctx *ctx, int fh, off_t offset, size_t count,
const char *src)
{
struct smbioc_rw rwrq;
@@ -300,7 +298,7 @@ smb_fh_write(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
rwrq.ioc_base = (char *)src;
rwrq.ioc_cnt = count;
rwrq.ioc_offset = offset;
- if (ioctl(ctx->ct_fd, SMBIOC_WRITE, &rwrq) == -1) {
+ if (ioctl(ctx->ct_dev_fd, SMBIOC_WRITE, &rwrq) == -1) {
return (-1);
}
return (rwrq.ioc_cnt);
@@ -315,7 +313,7 @@ smb_fh_write(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
* and on output *rdlen is the received length.
*/
int
-smb_fh_xactnp(struct smb_ctx *ctx, smbfh fh,
+smb_fh_xactnp(struct smb_ctx *ctx, int fh,
int tdlen, const char *tdata, /* transmit */
int *rdlen, char *rdata, /* receive */
int *more)
diff --git a/usr/src/lib/libsmbfs/smb/findvc.c b/usr/src/lib/libsmbfs/smb/findvc.c
new file mode 100644
index 0000000000..cfe2cad9e7
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/findvc.c
@@ -0,0 +1,139 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Find existing an VC given a list of addresses.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "charsets.h"
+#include "private.h"
+
+/*
+ * Ask the driver if it has a VC with this IP address.
+ */
+static int
+findvc(struct smb_ctx *ctx, struct addrinfo *ai)
+{
+ smbioc_ossn_t *ssn = &ctx->ct_ssn;
+
+ /*
+ * Copy the passed address into ssn_srvaddr,
+ * but first sanity-check lengths. Also,
+ * zero it first to avoid trailing junk.
+ */
+ if (ai->ai_addrlen > sizeof (ssn->ssn_srvaddr))
+ return (EINVAL);
+ bzero(&ssn->ssn_srvaddr, sizeof (ssn->ssn_srvaddr));
+ bcopy(ai->ai_addr, &ssn->ssn_srvaddr, ai->ai_addrlen);
+
+ if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_FIND, ssn) == -1)
+ return (errno);
+
+ return (0);
+}
+
+/*
+ * Find (and reuse) an existing VC.
+ * See also: newvc.c
+ */
+int
+smb_ctx_findvc(struct smb_ctx *ctx)
+{
+ struct addrinfo *ai;
+ int err;
+
+ /* Should already have the address list. */
+ if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
+ return (EINVAL);
+
+ for (ai = ctx->ct_addrinfo; ai; ai = ai->ai_next) {
+
+ switch (ai->ai_family) {
+
+ case AF_INET:
+ case AF_INET6:
+ case AF_NETBIOS:
+ err = findvc(ctx, ai);
+ break;
+
+ default:
+ DPRINT("skipped family %d", ai->ai_family);
+ err = EPROTONOSUPPORT;
+ break;
+ }
+
+ if (err == 0) {
+ /* re-use an existing VC */
+ ctx->ct_flags |= SMBCF_SSNACTIVE;
+ return (0);
+ }
+ }
+
+ return (ENOENT);
+}
+
+/*
+ * Forcibly disconnect the current session, even if
+ * there are others using it! This is used by the
+ * SMB server netlogon when it wants to setup a new
+ * logon session and does not want any re-use.
+ */
+int
+smb_ctx_kill(struct smb_ctx *ctx)
+{
+
+ if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_KILL, NULL) == -1)
+ return (errno);
+
+ return (0);
+}
diff --git a/usr/src/lib/libsmbfs/smb/getaddr.c b/usr/src/lib/libsmbfs/smb/getaddr.c
new file mode 100644
index 0000000000..2847d858cb
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/getaddr.c
@@ -0,0 +1,215 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Functions to get list of addresses (TCP and/or NetBIOS)
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "charsets.h"
+#include "private.h"
+
+void
+dump_addrinfo(struct addrinfo *ai)
+{
+ int i;
+
+ if (ai == NULL) {
+ printf("ai==NULL\n");
+ return;
+ }
+
+ for (i = 0; ai; i++, ai = ai->ai_next) {
+ printf("ai[%d]: af=%d, len=%d", i,
+ ai->ai_family, ai->ai_addrlen);
+ dump_sockaddr(ai->ai_addr);
+ if (ai->ai_canonname) {
+ printf("ai[%d]: cname=\"%s\"\n",
+ i, ai->ai_canonname);
+ }
+ }
+}
+
+void
+dump_sockaddr(struct sockaddr *sa)
+{
+ char paddrbuf[INET6_ADDRSTRLEN];
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ int af = sa->sa_family;
+ const char *ip;
+
+ printf(" saf=%d,", af);
+ switch (af) {
+ case AF_NETBIOS: /* see nbns_rq.c */
+ case AF_INET:
+ sin = (void *)sa;
+ ip = inet_ntop(AF_INET, &sin->sin_addr,
+ paddrbuf, sizeof (paddrbuf));
+ break;
+ case AF_INET6:
+ sin6 = (void *)sa;
+ ip = inet_ntop(AF_INET6, &sin6->sin6_addr,
+ paddrbuf, sizeof (paddrbuf));
+ break;
+ default:
+ ip = "?";
+ break;
+ }
+ printf(" IP=%s\n", ip);
+}
+
+
+/*
+ * SMB client name resolution - normal, and/or NetBIOS.
+ * Returns an EAI_xxx error number like getaddrinfo(3)
+ */
+int
+smb_ctx_getaddr(struct smb_ctx *ctx)
+{
+ struct nb_ctx *nbc = ctx->ct_nb;
+ struct addrinfo hints, *res;
+ char *srvaddr_str;
+ int gaierr, gaierr2;
+
+ if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == '\0')
+ return (EAI_NONAME);
+
+ if (ctx->ct_addrinfo != NULL) {
+ freeaddrinfo(ctx->ct_addrinfo);
+ ctx->ct_addrinfo = NULL;
+ }
+
+ /*
+ * If the user specified an address, use it,
+ * and don't do NetBIOS lookup.
+ */
+ if (ctx->ct_srvaddr_s) {
+ srvaddr_str = ctx->ct_srvaddr_s;
+ nbc->nb_flags &= ~NBCF_NS_ENABLE;
+ } else
+ srvaddr_str = ctx->ct_fullserver;
+
+ /*
+ * Default the server name we'll use in the
+ * protocol (i.e. NTLM, tree connect).
+ * If we get a canonical name, we'll
+ * overwrite this below.
+ */
+ strlcpy(ctx->ct_srvname, ctx->ct_fullserver,
+ sizeof (ctx->ct_srvname));
+
+ /*
+ * Try to lookup the host address using the
+ * normal name-to-IP address mechanisms.
+ * If that fails, we MAY try NetBIOS.
+ */
+ memset(&hints, 0, sizeof (hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ gaierr = getaddrinfo(srvaddr_str, NULL, &hints, &res);
+ if (gaierr == 0) {
+#if 1
+ /*
+ * XXX Temporarily work-around CR 6831339:
+ * getaddrinfo() sets ai_canonname incorrectly
+ */
+ char tmphost[256];
+ gaierr2 = getnameinfo(res->ai_addr, res->ai_addrlen,
+ tmphost, sizeof (tmphost),
+ NULL, 0, NI_NAMEREQD);
+ if (gaierr2 == 0) {
+ DPRINT("cname: %s", tmphost);
+ strlcpy(ctx->ct_srvname, tmphost,
+ sizeof (ctx->ct_srvname));
+ }
+#else
+ if (res->ai_canonname)
+ strlcpy(ctx->ct_srvname, res->ai_canonname,
+ sizeof (ctx->ct_srvname));
+#endif
+ ctx->ct_addrinfo = res;
+ return (0);
+ }
+
+ /*
+ * If regular IP name lookup failed, try NetBIOS,
+ * but only if given a valid NetBIOS name and if
+ * NetBIOS name lookup is enabled.
+ *
+ * Note: we only have ssn_srvname if the full name
+ * was also a valid NetBIOS name.
+ */
+ if (nbc->nb_flags & NBCF_NS_ENABLE) {
+ gaierr2 = nbns_getaddrinfo(ctx->ct_fullserver, nbc, &res);
+ if (gaierr2 == 0) {
+ if (res->ai_canonname)
+ strlcpy(ctx->ct_srvname,
+ res->ai_canonname,
+ sizeof (ctx->ct_srvname));
+ ctx->ct_addrinfo = res;
+ return (0);
+ }
+ }
+
+ /*
+ * Return the original error from getaddrinfo
+ */
+ if (smb_verbose) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "getaddrinfo: %s: %s"), 0,
+ ctx->ct_fullserver,
+ gai_strerror(gaierr));
+ }
+ return (gaierr);
+}
diff --git a/usr/src/lib/libsmbfs/smb/iod_cl.c b/usr/src/lib/libsmbfs/smb/iod_cl.c
new file mode 100644
index 0000000000..b28ffdb39a
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/iod_cl.c
@@ -0,0 +1,195 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Client-side interface to the IO Daemon (IOD)
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <door.h>
+
+#include <sys/byteorder.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "charsets.h"
+#include "private.h"
+
+static const char smbiod_path[] = "/usr/lib/smbfs/smbiod";
+
+/*
+ * This is constant for the life of a process,
+ * and initialized at startup, so no locks.
+ */
+static char door_path[40];
+
+char *
+smb_iod_door_path(void)
+{
+ static const char fmtR[] = "/var/run/smbiod-%d";
+ static const char fmtU[] = "/tmp/.smbiod-%d";
+ const char *fmt;
+ uid_t uid;
+
+ if (door_path[0] == '\0') {
+ uid = getuid();
+ fmt = (uid == 0) ? fmtR : fmtU;
+ snprintf(door_path, sizeof (door_path), fmt, uid);
+ }
+
+ return (door_path);
+}
+
+/*
+ * Open the door (client side) and
+ * find out if the service is there.
+ */
+int
+smb_iod_open_door(int *fdp)
+{
+ door_arg_t da;
+ char *path;
+ int fd, rc;
+ int err = 0;
+
+ path = smb_iod_door_path();
+ fd = open(path, O_RDONLY, 0);
+ if (fd < 0)
+ return (errno);
+
+ /*
+ * Make sure the IOD is running.
+ * Pass NULL args.
+ */
+ memset(&da, 0, sizeof (da));
+ da.rbuf = (void *) &err;
+ da.rsize = sizeof (err);
+ rc = door_call(fd, &da);
+ if (rc < 0) {
+ err = errno;
+ close(fd);
+ return (err);
+ }
+ if (err != 0) {
+ close(fd);
+ return (err);
+ }
+
+ /* This handle controls per-process resources. */
+ (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ *fdp = fd;
+ return (0);
+}
+
+/*
+ * Start the IOD and wait until we can
+ * open its client-side door.
+ */
+static int
+start_iod(int *fdp)
+{
+ int err, pid, t;
+
+ pid = vfork();
+ if (pid < 0)
+ return (errno);
+
+ /*
+ * child: start smbiod
+ */
+ if (pid == 0) {
+ char *argv[2];
+ argv[0] = "smbiod";
+ argv[1] = NULL;
+ execv(smbiod_path, argv);
+ return (errno);
+ }
+
+ /*
+ * parent: wait for smbiod to start
+ */
+ for (t = 0; t < 10; t++) {
+ sleep(1);
+ err = smb_iod_open_door(fdp);
+ if (err == 0)
+ break;
+ }
+
+ return (err);
+}
+
+
+/*
+ * Start smbiod if necessary, and then
+ * ask it to connect using the info in ctx.
+ */
+int
+smb_iod_cl_newvc(smb_ctx_t *ctx)
+{
+ door_arg_t da;
+ int fd, err = 0;
+
+ err = smb_iod_open_door(&fd);
+ if (err != 0) {
+ err = start_iod(&fd);
+ if (err)
+ return (err);
+ }
+
+ da.data_ptr = (void *) &ctx->ct_iod_ssn;
+ da.data_size = sizeof (ctx->ct_iod_ssn);
+ da.desc_ptr = NULL;
+ da.desc_num = 0;
+ da.rbuf = (void *) &err;
+ da.rsize = sizeof (err);
+ if (door_call(fd, &da) < 0) {
+ err = errno;
+ DPRINT("door_call, err=%d", err);
+ }
+ close(fd);
+
+ return (err);
+}
diff --git a/usr/src/lib/libsmbfs/smb/iod_wk.c b/usr/src/lib/libsmbfs/smb/iod_wk.c
new file mode 100644
index 0000000000..89f3eb3fa0
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/iod_wk.c
@@ -0,0 +1,176 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Functions called by the IO deamon (IOD).
+ * Here in the library to simplify testing.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libintl.h>
+
+#include <sys/byteorder.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "charsets.h"
+#include "private.h"
+
+/*
+ * Be the reader thread for this VC.
+ */
+int
+smb_iod_work(smb_ctx_t *ctx)
+{
+ smbioc_ssn_work_t *work = &ctx->ct_work;
+ int vcst, err = 0;
+
+ DPRINT("server: %s", ctx->ct_srvname);
+
+ /* Calle should have opened these */
+ if (ctx->ct_tran_fd == -1 || ctx->ct_dev_fd == -1) {
+ err = EINVAL;
+ goto out;
+ }
+
+ /*
+ * This is the reader / reconnect loop.
+ *
+ * We could start with state "idle", but
+ * we know someone wants a connection to
+ * this server, so start in "vcactive".
+ *
+ * XXX: Add some syslog calls in here?
+ */
+ vcst = SMBIOD_ST_VCACTIVE;
+
+ for (;;) {
+
+ switch (vcst) {
+ case SMBIOD_ST_IDLE:
+ /*
+ * Wait for driver requests to arrive
+ * for this VC, then return here.
+ * Next state is normally RECONNECT.
+ */
+ DPRINT("state: idle");
+ if (ioctl(ctx->ct_dev_fd,
+ SMBIOC_IOD_IDLE, &vcst) == -1) {
+ err = errno;
+ DPRINT("ioc_idle: err %d", err);
+ goto out;
+ }
+ continue;
+
+ case SMBIOD_ST_RECONNECT:
+ DPRINT("state: reconnect");
+ err = smb_iod_connect(ctx);
+ if (err == 0) {
+ vcst = SMBIOD_ST_VCACTIVE;
+ continue;
+ }
+ DPRINT("_iod_connect: err %d", err);
+ /*
+ * If the error was EAUTH, retry is
+ * not likely to succeed either, so
+ * just exit this thread. The user
+ * will need to run smbutil to get
+ * a new thread with new auth info.
+ */
+ if (err == EAUTH)
+ goto out;
+ vcst = SMBIOD_ST_RCFAILED;
+ continue;
+
+ case SMBIOD_ST_RCFAILED:
+ DPRINT("state: rcfailed");
+ /*
+ * Reconnect failed. Kill off any
+ * requests waiting in the driver,
+ * then get ready to try again.
+ * Next state is normally IDLE.
+ */
+ if (ioctl(ctx->ct_dev_fd,
+ SMBIOC_IOD_RCFAIL, &vcst) == -1) {
+ err = errno;
+ DPRINT("ioc_rcfail: err %d", err);
+ goto out;
+ }
+ continue;
+
+ case SMBIOD_ST_VCACTIVE:
+ DPRINT("state: active");
+ if (ioctl(ctx->ct_dev_fd,
+ SMBIOC_IOD_WORK, work) == -1) {
+ err = errno;
+ DPRINT("ioc_work: err %d", err);
+ goto out;
+ }
+ vcst = work->wk_out_state;
+ continue;
+
+ case SMBIOD_ST_DEAD:
+ DPRINT("state: dead");
+ err = 0;
+ goto out;
+
+ default:
+ DPRINT("state: BAD(%d)", vcst);
+ err = EFAULT;
+ goto out;
+ }
+ }
+
+out:
+ if (ctx->ct_tran_fd != -1) {
+ close(ctx->ct_tran_fd);
+ ctx->ct_tran_fd = -1;
+ }
+ if (ctx->ct_dev_fd != -1) {
+ close(ctx->ct_dev_fd);
+ ctx->ct_dev_fd = -1;
+ }
+
+ return (err);
+}
diff --git a/usr/src/lib/libsmbfs/smb/keychain.c b/usr/src/lib/libsmbfs/smb/keychain.c
index 72a979022f..da19fd4d0b 100644
--- a/usr/src/lib/libsmbfs/smb/keychain.c
+++ b/usr/src/lib/libsmbfs/smb/keychain.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* External interface to the libsmbfs/netsmb keychain
* storage mechanism. This interface is consumed by
@@ -37,15 +35,19 @@
#include <errno.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libintl.h>
+#include <cflib.h>
#include <netsmb/smb_dev.h>
#include <netsmb/smb_lib.h>
#include <netsmb/smb_keychain.h>
-#include <cflib.h>
+#include "charsets.h"
+#include "private.h"
+#include "ntlm.h"
/* common func. for add/del/chk */
static int
@@ -54,50 +56,68 @@ smbfs_keychain_cmn(
uid_t uid,
const char *dom,
const char *usr,
- const char *pass)
+ uchar_t *lmhash,
+ uchar_t *nthash)
{
smbioc_pk_t pk;
- int err, fd;
+ int err, fd, sz;
memset(&pk, 0, sizeof (pk));
-
pk.pk_uid = uid;
+ err = 0;
+ fd = -1;
switch (cmd) {
case SMBIOC_PK_ADD:
- if (pass == NULL)
- return (SMB_KEYCHAIN_BADPASSWD);
- if (strlcpy(pk.pk_pass, pass, sizeof (pk.pk_pass)) >=
- sizeof (pk.pk_pass))
- return (SMB_KEYCHAIN_BADPASSWD);
+ /*
+ * Add password hashes to the keychain.
+ */
+ if (lmhash == NULL || nthash == NULL) {
+ err = SMB_KEYCHAIN_BADPASSWD;
+ goto out;
+ }
+ memcpy(pk.pk_lmhash, lmhash, SMBIOC_HASH_SZ);
+ memcpy(pk.pk_nthash, nthash, SMBIOC_HASH_SZ);
/* FALLTHROUGH */
case SMBIOC_PK_CHK:
case SMBIOC_PK_DEL:
- if (dom == NULL)
- return (SMB_KEYCHAIN_BADDOMAIN);
- if (strlcpy(pk.pk_dom, dom, sizeof (pk.pk_dom)) >=
- sizeof (pk.pk_dom))
- return (SMB_KEYCHAIN_BADDOMAIN);
- if (usr == NULL)
- return (SMB_KEYCHAIN_BADUSER);
- if (strlcpy(pk.pk_usr, usr, sizeof (pk.pk_usr)) >=
- sizeof (pk.pk_usr))
- return (SMB_KEYCHAIN_BADUSER);
+ /*
+ * Copy domain and user.
+ */
+ if (dom == NULL) {
+ err = SMB_KEYCHAIN_BADDOMAIN;
+ goto out;
+ }
+ sz = sizeof (pk.pk_dom);
+ if (strlcpy(pk.pk_dom, dom, sz) >= sz) {
+ err = SMB_KEYCHAIN_BADDOMAIN;
+ goto out;
+ }
+ if (usr == NULL) {
+ err = SMB_KEYCHAIN_BADUSER;
+ goto out;
+ }
+ sz = sizeof (pk.pk_usr);
+ if (strlcpy(pk.pk_usr, usr, sz) >= sz) {
+ err = SMB_KEYCHAIN_BADUSER;
+ goto out;
+ }
break;
case SMBIOC_PK_DEL_OWNER: /* all owned by the caller */
case SMBIOC_PK_DEL_EVERYONE: /* all owned by everyone */
/*
* These two do not copyin any args, but we'll
- * pass &pk here anyway just so we can use the
+ * pass pk here anyway just so we can use the
* common code path below.
*/
break;
default:
- return (SMB_KEYCHAIN_UNKNOWN);
+ err = SMB_KEYCHAIN_UNKNOWN;
+ goto out;
}
fd = smb_open_driver();
@@ -107,28 +127,57 @@ smbfs_keychain_cmn(
}
err = 0;
- if (ioctl(fd, cmd, &pk) < 0)
+ if (ioctl(fd, cmd, &pk) < 0) {
err = errno;
+ goto out;
+ }
+
+ if (cmd == SMBIOC_PK_CHK) {
+ if (lmhash != NULL)
+ memcpy(lmhash, pk.pk_lmhash, SMBIOC_HASH_SZ);
+ if (nthash != NULL)
+ memcpy(nthash, pk.pk_nthash, SMBIOC_HASH_SZ);
+ }
- close(fd);
out:
- memset(&pk, 0, sizeof (pk));
+ if (fd != -1)
+ close(fd);
+
return (err);
}
-/* Add a password to the keychain. */
+/*
+ * Add a password to the keychain.
+ *
+ * Note: pass is a cleartext password.
+ * We use it here to compute the LM hash and NT hash,
+ * and then store ONLY the hashes.
+ */
int
smbfs_keychain_add(uid_t uid, const char *dom, const char *usr,
const char *pass)
{
- return (smbfs_keychain_cmn(SMBIOC_PK_ADD, uid, dom, usr, pass));
+ uchar_t lmhash[SMBIOC_HASH_SZ];
+ uchar_t nthash[SMBIOC_HASH_SZ];
+ int err, cmd = SMBIOC_PK_ADD;
+
+ if (pass == NULL)
+ return (SMB_KEYCHAIN_BADPASSWD);
+
+ if ((err = ntlm_compute_lm_hash(lmhash, pass)) != 0)
+ return (err);
+ if ((err = ntlm_compute_nt_hash(nthash, pass)) != 0)
+ return (err);
+
+ err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash);
+ return (err);
}
/* Delete a password from the keychain. */
int
smbfs_keychain_del(uid_t uid, const char *dom, const char *usr)
{
- return (smbfs_keychain_cmn(SMBIOC_PK_DEL, uid, dom, usr, NULL));
+ return (smbfs_keychain_cmn(SMBIOC_PK_DEL, uid, dom, usr, NULL, NULL));
}
/*
@@ -138,7 +187,22 @@ smbfs_keychain_del(uid_t uid, const char *dom, const char *usr)
int
smbfs_keychain_chk(const char *dom, const char *usr)
{
- return (smbfs_keychain_cmn(SMBIOC_PK_CHK, (uid_t)-1, dom, usr, NULL));
+ uid_t uid = (uid_t)-1;
+ return (smbfs_keychain_cmn(SMBIOC_PK_CHK, uid, dom, usr, NULL, NULL));
+}
+
+/*
+ * Get the stored hashes
+ */
+int
+smbfs_keychain_get(const char *dom, const char *usr,
+ uchar_t *lmhash, uchar_t *nthash)
+{
+ uid_t uid = (uid_t)-1;
+ int err, cmd = SMBIOC_PK_CHK;
+
+ err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash);
+ return (err);
}
/*
@@ -147,7 +211,9 @@ smbfs_keychain_chk(const char *dom, const char *usr)
int
smbfs_keychain_del_owner()
{
- return (smbfs_keychain_cmn(SMBIOC_PK_DEL_OWNER, getuid(), 0, 0, 0));
+ int cmd = SMBIOC_PK_DEL_OWNER;
+ uid_t uid = getuid();
+ return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL));
}
/*
@@ -157,7 +223,51 @@ smbfs_keychain_del_owner()
int
smbfs_keychain_del_everyone()
{
- return (smbfs_keychain_cmn(SMBIOC_PK_DEL_EVERYONE, getuid(), 0, 0, 0));
+ int cmd = SMBIOC_PK_DEL_EVERYONE;
+ uid_t uid = getuid();
+ return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL));
+}
+
+/*
+ * Private function to get keychain p/w hashes.
+ */
+int
+smb_get_keychain(struct smb_ctx *ctx)
+{
+ int err;
+
+ if (ctx->ct_fullserver == NULL) {
+ DPRINT("ct_fullserver == NULL");
+ return (EINVAL);
+ }
+
+ /*
+ * 1st: try lookup using system name
+ */
+ err = smbfs_keychain_get(ctx->ct_fullserver, ctx->ct_user,
+ ctx->ct_lmhash, ctx->ct_nthash);
+ if (!err) {
+ ctx->ct_flags |= SMBCF_KCFOUND;
+ DPRINT("found keychain entry for"
+ " server/user: %s/%s\n",
+ ctx->ct_fullserver, ctx->ct_user);
+ return (0);
+ }
+
+ /*
+ * 2nd: try lookup using domain name
+ */
+ err = smbfs_keychain_get(ctx->ct_domain, ctx->ct_user,
+ ctx->ct_lmhash, ctx->ct_nthash);
+ if (!err) {
+ ctx->ct_flags |= (SMBCF_KCFOUND | SMBCF_KCDOMAIN);
+ DPRINT("found keychain entry for"
+ " domain/user: %s/%s\n",
+ ctx->ct_domain, ctx->ct_user);
+ return (0);
+ }
+
+ return (err);
}
@@ -173,27 +283,33 @@ int
smbfs_default_dom_usr(const char *home, const char *server,
char *dom, int maxdom, char *usr, int maxusr)
{
- struct smb_ctx sctx, *ctx = &sctx;
+ struct smb_ctx *ctx;
int err;
- err = smb_ctx_init(ctx, 0, NULL, SMBL_VC, SMBL_VC, SMB_ST_ANY);
+ err = smb_ctx_alloc(&ctx);
if (err)
return (err);
+
if (server)
- smb_ctx_setserver(ctx, server);
- if (home && *home)
- ctx->ct_home = (char *)home;
+ smb_ctx_setfullserver(ctx, server);
+
+ if (home && *home) {
+ if (ctx->ct_home)
+ free(ctx->ct_home);
+ ctx->ct_home = strdup(home);
+ }
+
err = smb_ctx_readrc(ctx);
if (err)
- return (err);
- if (smb_rc)
- rc_close(smb_rc);
+ goto out;
if (dom)
- strlcpy(dom, ctx->ct_ssn.ioc_workgroup, maxdom);
+ strlcpy(dom, ctx->ct_domain, maxdom);
if (usr)
- strlcpy(usr, ctx->ct_ssn.ioc_user, maxusr);
+ strlcpy(usr, ctx->ct_user, maxusr);
- return (0);
+out:
+ smb_ctx_free(ctx);
+ return (err);
}
diff --git a/usr/src/lib/libsmbfs/smb/krb5ssp.c b/usr/src/lib/libsmbfs/smb/krb5ssp.c
new file mode 100644
index 0000000000..fbbd08398b
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/krb5ssp.c
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) 2000, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Kerberos V Security Support Provider
+ *
+ * Based on code previously in ctx.c (from Boris Popov?)
+ * but then mostly rewritten at Sun.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/mchain.h>
+
+#include "private.h"
+#include "charsets.h"
+#include "spnego.h"
+#include "derparse.h"
+#include "ssp.h"
+
+#include <kerberosv5/krb5.h>
+#include <kerberosv5/com_err.h>
+
+/* RFC 1964 token ID codes */
+#define KRB_AP_REQ 1
+#define KRB_AP_REP 2
+#define KRB_ERROR 3
+
+extern MECH_OID g_stcMechOIDList [];
+
+typedef struct krb5ssp_state {
+ /* Filled in by krb5ssp_init_client */
+ krb5_context ss_krb5ctx; /* krb5 context (ptr) */
+ krb5_ccache ss_krb5cc; /* credentials cache (ptr) */
+ krb5_principal ss_krb5clp; /* client principal (ptr) */
+ /* Filled in by krb5ssp_get_tkt */
+ krb5_auth_context ss_auth; /* auth ctx. w/ server (ptr) */
+} krb5ssp_state_t;
+
+
+/*
+ * adds a GSSAPI wrapper
+ */
+int
+krb5ssp_tkt2gtok(uchar_t *tkt, ulong_t tktlen,
+ uchar_t **gtokp, ulong_t *gtoklenp)
+{
+ ulong_t len;
+ ulong_t bloblen = tktlen;
+ uchar_t krbapreq[2] = { KRB_AP_REQ, 0 };
+ uchar_t *blob = NULL; /* result */
+ uchar_t *b;
+
+ bloblen += sizeof (krbapreq);
+ bloblen += g_stcMechOIDList[spnego_mech_oid_Kerberos_V5].iLen;
+ len = bloblen;
+ bloblen = ASNDerCalcTokenLength(bloblen, bloblen);
+ if ((blob = malloc(bloblen)) == NULL) {
+ DPRINT("malloc");
+ return (ENOMEM);
+ }
+
+ b = blob;
+ b += ASNDerWriteToken(b, SPNEGO_NEGINIT_APP_CONSTRUCT, NULL, len);
+ b += ASNDerWriteOID(b, spnego_mech_oid_Kerberos_V5);
+ memcpy(b, krbapreq, sizeof (krbapreq));
+ b += sizeof (krbapreq);
+
+ assert(b + tktlen == blob + bloblen);
+ memcpy(b, tkt, tktlen);
+ *gtoklenp = bloblen;
+ *gtokp = blob;
+ return (0);
+}
+
+/*
+ * See "Windows 2000 Kerberos Interoperability" paper by
+ * Christopher Nebergall. RC4 HMAC is the W2K default but
+ * Samba support lagged (not due to Samba itself, but due to OS'
+ * Kerberos implementations.)
+ *
+ * Only session enc type should matter, not ticket enc type,
+ * per Sam Hartman on krbdev.
+ *
+ * Preauthentication failure topics in krb-protocol may help here...
+ * try "John Brezak" and/or "Clifford Neuman" too.
+ */
+static krb5_enctype kenctypes[] = {
+ ENCTYPE_ARCFOUR_HMAC, /* defined in krb5.h */
+ ENCTYPE_DES_CBC_MD5,
+ ENCTYPE_DES_CBC_CRC,
+ ENCTYPE_NULL
+};
+
+static const int rq_opts =
+ AP_OPTS_USE_SUBKEY | AP_OPTS_MUTUAL_REQUIRED;
+
+/*
+ * Obtain a kerberos ticket for the host we're connecting to.
+ * (This does the KRB_TGS exchange.)
+ */
+static int
+krb5ssp_get_tkt(krb5ssp_state_t *ss, char *server,
+ uchar_t **tktp, ulong_t *tktlenp)
+{
+ krb5_context kctx = ss->ss_krb5ctx;
+ krb5_ccache kcc = ss->ss_krb5cc;
+ krb5_data indata = {0};
+ krb5_data outdata = {0};
+ krb5_error_code kerr = 0;
+ const char *fn = NULL;
+ uchar_t *tkt;
+
+ /* Should have these from krb5ssp_init_client. */
+ if (kctx == NULL || kcc == NULL) {
+ fn = "null kctx or kcc";
+ kerr = EINVAL;
+ goto out;
+ }
+
+ kerr = krb5_set_default_tgs_enctypes(kctx, kenctypes);
+ if (kerr != 0) {
+ fn = "krb5_set_default_tgs_enctypes";
+ goto out;
+ }
+
+ /* Override the krb5 library default. */
+ indata.data = "";
+
+ kerr = krb5_mk_req(kctx, &ss->ss_auth, rq_opts, "cifs", server,
+ &indata, kcc, &outdata);
+ if (kerr != 0) {
+ fn = "krb5_mk_req";
+ goto out;
+ }
+ if ((tkt = malloc(outdata.length)) == NULL) {
+ kerr = ENOMEM;
+ fn = "malloc signing key";
+ goto out;
+ }
+ memcpy(tkt, outdata.data, outdata.length);
+ *tktp = tkt;
+ *tktlenp = outdata.length;
+ kerr = 0;
+
+out:
+ if (kerr) {
+ if (fn == NULL)
+ fn = "?";
+ DPRINT("%s err 0x%x: %s", fn, kerr, error_message(kerr));
+ if (kerr <= 0 || kerr > ESTALE)
+ kerr = EAUTH;
+ }
+
+ if (outdata.data)
+ krb5_free_data_contents(kctx, &outdata);
+
+ /* Free kctx in krb5ssp_destroy */
+ return (kerr);
+}
+
+
+/*
+ * Build an RFC 1964 KRB_AP_REQ message
+ * The caller puts on the SPNEGO wrapper.
+ */
+int
+krb5ssp_put_request(struct ssp_ctx *sp, struct mbdata *out_mb)
+{
+ int err;
+ struct smb_ctx *ctx = sp->smb_ctx;
+ krb5ssp_state_t *ss = sp->sp_private;
+ uchar_t *tkt = NULL;
+ ulong_t tktlen;
+ uchar_t *gtok = NULL; /* gssapi token */
+ ulong_t gtoklen; /* gssapi token length */
+ char *prin = ctx->ct_srvname;
+
+ if ((err = krb5ssp_get_tkt(ss, prin, &tkt, &tktlen)) != 0)
+ goto out;
+ if ((err = krb5ssp_tkt2gtok(tkt, tktlen, &gtok, &gtoklen)) != 0)
+ goto out;
+
+ if ((err = mb_init(out_mb, gtoklen)) != 0)
+ goto out;
+ if ((err = mb_put_mem(out_mb, gtok, gtoklen)) != 0)
+ goto out;
+
+ if (ctx->ct_vcflags & SMBV_WILL_SIGN)
+ ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
+
+out:
+ if (gtok)
+ free(gtok);
+ if (tkt)
+ free(tkt);
+
+ return (err);
+}
+
+/*
+ * Unwrap a GSS-API encapsulated RFC 1964 reply message,
+ * i.e. type KRB_AP_REP or KRB_ERROR.
+ */
+int
+krb5ssp_get_reply(struct ssp_ctx *sp, struct mbdata *in_mb)
+{
+ krb5ssp_state_t *ss = sp->sp_private;
+ mbuf_t *m = in_mb->mb_top;
+ int err = EBADRPC;
+ int dlen, rc;
+ long actual_len, token_len;
+ uchar_t *data;
+ krb5_data ap = {0};
+ krb5_ap_rep_enc_part *reply = NULL;
+
+ /* cheating: this mbuf is contiguous */
+ assert(m->m_data == in_mb->mb_pos);
+ data = (uchar_t *)m->m_data;
+ dlen = m->m_len;
+
+ /*
+ * Peel off the GSS-API wrapper. Looks like:
+ * AppToken: 60 81 83
+ * OID(KRB5): 06 09 2a 86 48 86 f7 12 01 02 02
+ * KRB_AP_REP: 02 00
+ */
+ rc = ASNDerCheckToken(data, SPNEGO_NEGINIT_APP_CONSTRUCT,
+ 0, dlen, &token_len, &actual_len);
+ if (rc != SPNEGO_E_SUCCESS) {
+ DPRINT("no AppToken? rc=0x%x", rc);
+ goto out;
+ }
+ if (dlen < actual_len)
+ goto out;
+ data += actual_len;
+ dlen -= actual_len;
+
+ /* OID (KRB5) */
+ rc = ASNDerCheckOID(data, spnego_mech_oid_Kerberos_V5,
+ dlen, &actual_len);
+ if (rc != SPNEGO_E_SUCCESS) {
+ DPRINT("no OID? rc=0x%x", rc);
+ goto out;
+ }
+ if (dlen < actual_len)
+ goto out;
+ data += actual_len;
+ dlen -= actual_len;
+
+ /* KRB_AP_REP or KRB_ERROR */
+ if (data[0] != KRB_AP_REP) {
+ DPRINT("KRB5 type: %d", data[1]);
+ goto out;
+ }
+ if (dlen < 2)
+ goto out;
+ data += 2;
+ dlen -= 2;
+
+ /*
+ * Now what's left should be a krb5 reply
+ * NB: ap is NOT allocated, so don't free it.
+ */
+ ap.length = dlen;
+ ap.data = (char *)data;
+ rc = krb5_rd_rep(ss->ss_krb5ctx, ss->ss_auth, &ap, &reply);
+ if (rc != 0) {
+ DPRINT("krb5_rd_rep: err 0x%x (%s)",
+ rc, error_message(rc));
+ err = EAUTH;
+ goto out;
+ }
+
+ /*
+ * Have the decoded reply. Save anything?
+ *
+ * NB: If this returns an error, we will get
+ * no more calls into this back-end module.
+ */
+ err = 0;
+
+out:
+ if (reply != NULL)
+ krb5_free_ap_rep_enc_part(ss->ss_krb5ctx, reply);
+ if (err)
+ DPRINT("ret %d", err);
+
+ return (err);
+}
+
+/*
+ * krb5ssp_final
+ *
+ * Called after successful authentication.
+ * Setup the MAC key for signing.
+ */
+int
+krb5ssp_final(struct ssp_ctx *sp)
+{
+ struct smb_ctx *ctx = sp->smb_ctx;
+ krb5ssp_state_t *ss = sp->sp_private;
+ krb5_keyblock *ssn_key = NULL;
+ int err, len;
+
+ /*
+ * Save the session key, used for SMB signing
+ * and possibly other consumers (RPC).
+ */
+ err = krb5_auth_con_getlocalsubkey(
+ ss->ss_krb5ctx, ss->ss_auth, &ssn_key);
+ if (err != 0) {
+ DPRINT("_getlocalsubkey, err=0x%x (%s)",
+ err, error_message(err));
+ if (err <= 0 || err > ESTALE)
+ err = EAUTH;
+ goto out;
+ }
+ memset(ctx->ct_ssn_key, 0, SMBIOC_HASH_SZ);
+ if ((len = ssn_key->length) > SMBIOC_HASH_SZ)
+ len = SMBIOC_HASH_SZ;
+ memcpy(ctx->ct_ssn_key, ssn_key->contents, len);
+
+ /*
+ * Set the MAC key on the first successful auth.
+ */
+ if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
+ (ctx->ct_mackey == NULL)) {
+ ctx->ct_mackeylen = ssn_key->length;
+ ctx->ct_mackey = malloc(ctx->ct_mackeylen);
+ if (ctx->ct_mackey == NULL) {
+ ctx->ct_mackeylen = 0;
+ err = ENOMEM;
+ goto out;
+ }
+ memcpy(ctx->ct_mackey, ssn_key->contents,
+ ctx->ct_mackeylen);
+ /*
+ * Apparently, the server used seq. no. zero
+ * for our previous message, so next is two.
+ */
+ ctx->ct_mac_seqno = 2;
+ }
+ err = 0;
+
+out:
+ if (ssn_key)
+ krb5_free_keyblock(ss->ss_krb5ctx, ssn_key);
+
+ return (err);
+}
+
+/*
+ * krb5ssp_next_token
+ *
+ * See ssp.c: ssp_ctx_next_token
+ */
+int
+krb5ssp_next_token(struct ssp_ctx *sp, struct mbdata *in_mb,
+ struct mbdata *out_mb)
+{
+ int err;
+
+ /*
+ * Note: in_mb == NULL on the first call.
+ */
+ if (in_mb) {
+ err = krb5ssp_get_reply(sp, in_mb);
+ if (err)
+ goto out;
+ }
+
+ if (out_mb) {
+ err = krb5ssp_put_request(sp, out_mb);
+ } else
+ err = krb5ssp_final(sp);
+
+out:
+ if (err)
+ DPRINT("ret: %d", err);
+ return (err);
+}
+
+/*
+ * krb5ssp_ctx_destroy
+ *
+ * Destroy mechanism-specific data.
+ */
+void
+krb5ssp_destroy(struct ssp_ctx *sp)
+{
+ krb5ssp_state_t *ss;
+ krb5_context kctx;
+
+ ss = sp->sp_private;
+ if (ss == NULL)
+ return;
+ sp->sp_private = NULL;
+
+ if ((kctx = ss->ss_krb5ctx) != NULL) {
+ /* from krb5ssp_get_tkt */
+ if (ss->ss_auth)
+ krb5_auth_con_free(kctx, ss->ss_auth);
+ /* from krb5ssp_init_client */
+ if (ss->ss_krb5clp)
+ krb5_free_principal(kctx, ss->ss_krb5clp);
+ if (ss->ss_krb5cc)
+ krb5_cc_close(kctx, ss->ss_krb5cc);
+ krb5_free_context(kctx);
+ }
+
+ free(ss);
+}
+
+/*
+ * krb5ssp_init_clnt
+ *
+ * Initialize a new Kerberos SSP client context.
+ *
+ * The user must already have a TGT in their credential cache,
+ * as shown by the "klist" command.
+ */
+int
+krb5ssp_init_client(struct ssp_ctx *sp)
+{
+ krb5ssp_state_t *ss;
+ krb5_error_code kerr;
+ krb5_context kctx = NULL;
+ krb5_ccache kcc = NULL;
+ krb5_principal kprin = NULL;
+
+ if ((sp->smb_ctx->ct_authflags & SMB_AT_KRB5) == 0) {
+ DPRINT("KRB5 not in authflags");
+ return (ENOTSUP);
+ }
+
+ ss = calloc(1, sizeof (*ss));
+ if (ss == NULL)
+ return (ENOMEM);
+
+ sp->sp_nexttok = krb5ssp_next_token;
+ sp->sp_destroy = krb5ssp_destroy;
+ sp->sp_private = ss;
+
+ kerr = krb5_init_context(&kctx);
+ if (kerr) {
+ DPRINT("krb5_init_context, kerr 0x%x", kerr);
+ goto errout;
+ }
+ ss->ss_krb5ctx = kctx;
+
+ /* non-default would instead use krb5_cc_resolve */
+ kerr = krb5_cc_default(kctx, &kcc);
+ if (kerr) {
+ DPRINT("krb5_cc_default, kerr 0x%x", kerr);
+ goto errout;
+ }
+ ss->ss_krb5cc = kcc;
+
+ /*
+ * Get the client principal (ticket),
+ * or discover that we don't have one.
+ */
+ kerr = krb5_cc_get_principal(kctx, kcc, &kprin);
+ if (kerr) {
+ DPRINT("krb5_cc_get_principal, kerr 0x%x", kerr);
+ goto errout;
+ }
+ ss->ss_krb5clp = kprin;
+
+ /* Success! */
+ DPRINT("Ticket cache: %s:%s",
+ krb5_cc_get_type(kctx, kcc),
+ krb5_cc_get_name(kctx, kcc));
+ return (0);
+
+errout:
+ krb5ssp_destroy(sp);
+ return (ENOTSUP);
+}
diff --git a/usr/src/lib/libsmbfs/smb/llib-lsmbfs b/usr/src/lib/libsmbfs/smb/llib-lsmbfs
index 05e1967055..e8e05e4272 100644
--- a/usr/src/lib/libsmbfs/smb/llib-lsmbfs
+++ b/usr/src/lib/libsmbfs/smb/llib-lsmbfs
@@ -20,13 +20,18 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*LINTLIBRARY*/
/*PROTOLIB1*/
+#include <netsmb/smbfs_api.h>
+#include <netsmb/smbfs_acl.h>
+
#include <netsmb/smb_lib.h>
+#include <netsmb/smb_keychain.h>
+#include <netsmb/smb_netshareenum.h>
+#include <netsmb/smb_rap.h>
+
diff --git a/usr/src/lib/libsmbfs/smb/mapfile-vers b/usr/src/lib/libsmbfs/smb/mapfile-vers
index f927c7bcb8..3486333120 100644
--- a/usr/src/lib/libsmbfs/smb/mapfile-vers
+++ b/usr/src/lib/libsmbfs/smb/mapfile-vers
@@ -36,7 +36,7 @@
# MAPFILE HEADER END
#
-SUNWprivate_1.0 {
+SUNWprivate {
global:
convert_leunicode_to_utf8;
convert_unicode_to_utf8;
@@ -58,27 +58,37 @@ SUNWprivate_1.0 {
nls_str_toloc;
nls_str_upper;
- rc_close;
- rc_open;
+ smb_close_rcfile;
+ smb_ctx_alloc;
smb_ctx_done;
smb_ctx_flags2;
+ smb_ctx_free;
+ smb_ctx_get_ssn;
+ smb_ctx_get_ssnkey;
+ smb_ctx_get_tree;
+ smb_ctx_gethandle;
smb_ctx_init;
- smb_ctx_lookup;
+ smb_ctx_kill;
smb_ctx_opt;
+ smb_ctx_parseunc;
smb_ctx_readrc;
smb_ctx_resolve;
+ smb_ctx_scan_argv;
smb_ctx_set_close_hook;
+ smb_ctx_setauthflags;
+ smb_ctx_setdomain;
smb_ctx_setfullserver;
smb_ctx_setpassword;
+ smb_ctx_setpwhash;
+ smb_ctx_setscope;
smb_ctx_setserver;
smb_ctx_setshare;
smb_ctx_setsrvaddr;
smb_ctx_setuser;
- smb_ctx_setworkgroup;
+ smb_ctx_setwins;
- smb_ctx_tdis;
smb_debug = NODIRECT; # data
smb_error;
#
@@ -89,14 +99,20 @@ SUNWprivate_1.0 {
smb_fh_write;
smb_fh_xactnp;
#
+ smb_get_authentication;
smb_getprogname;
+ smb_iod_connect;
+ smb_iod_door_path;
+ smb_iod_open_door;
+ smb_iod_work;
smb_lib_init;
smb_netshareenum; # will move to libnetapi
smb_open_rcfile;
+ smb_printer_open;
+ smb_printer_close;
smb_simplecrypt;
smb_simpledecrypt;
smb_strerror;
- smb_rc = NODIRECT; # data
#
# Functions to support the Remote Access Protocol (RAP)
smb_rap_create;
@@ -126,7 +142,7 @@ SUNWprivate_1.0 {
smbfs_keychain_del_everyone;
smbfs_keychain_del_owner;
- unpercent;
+ smbutil_std_opts;
local:
*;
};
diff --git a/usr/src/lib/libsmbfs/smb/mbuf.c b/usr/src/lib/libsmbfs/smb/mbuf.c
index 2e995dad50..9380ec12e9 100644
--- a/usr/src/lib/libsmbfs/smb/mbuf.c
+++ b/usr/src/lib/libsmbfs/smb/mbuf.c
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -47,17 +47,11 @@
#include <libintl.h>
#include <assert.h>
-#include <netsmb/smb.h>
#include <netsmb/smb_lib.h>
#include <netsmb/mchain.h>
#include "private.h"
-
-#ifdef APPLE
-#define __func__ ""
-#define MBERROR(format, args...) \
- printf("%s(%d): "format, __func__, __LINE__, ## args)
-#endif
+#include "charsets.h"
static int
m_get(size_t len, struct mbuf **mpp)
@@ -85,7 +79,7 @@ m_free(struct mbuf *m)
free(m);
}
-static void
+void
m_freem(struct mbuf *m0)
{
struct mbuf *m;
@@ -97,7 +91,7 @@ m_freem(struct mbuf *m0)
}
}
-static size_t
+size_t
m_totlen(struct mbuf *m0)
{
struct mbuf *m = m0;
@@ -226,61 +220,64 @@ int
mb_put_uint8(struct mbdata *mbp, uint8_t x)
{
uint8_t y = x;
- return (mb_put_mem(mbp, (char *)&y, sizeof (y)));
+ return (mb_put_mem(mbp, &y, sizeof (y)));
}
int
mb_put_uint16be(struct mbdata *mbp, uint16_t x)
{
uint16_t y = htobes(x);
- return (mb_put_mem(mbp, (char *)&y, sizeof (y)));
+ return (mb_put_mem(mbp, &y, sizeof (y)));
}
int
mb_put_uint16le(struct mbdata *mbp, uint16_t x)
{
uint16_t y = htoles(x);
- return (mb_put_mem(mbp, (char *)&y, sizeof (y)));
+ return (mb_put_mem(mbp, &y, sizeof (y)));
}
int
mb_put_uint32be(struct mbdata *mbp, uint32_t x)
{
uint32_t y = htobel(x);
- return (mb_put_mem(mbp, (char *)&y, sizeof (y)));
+ return (mb_put_mem(mbp, &y, sizeof (y)));
}
int
mb_put_uint32le(struct mbdata *mbp, uint32_t x)
{
uint32_t y = htolel(x);
- return (mb_put_mem(mbp, (char *)&y, sizeof (y)));
+ return (mb_put_mem(mbp, &y, sizeof (y)));
}
int
mb_put_uint64be(struct mbdata *mbp, uint64_t x)
{
uint64_t y = htobeq(x);
- return (mb_put_mem(mbp, (char *)&y, sizeof (y)));
+ return (mb_put_mem(mbp, &y, sizeof (y)));
}
int
mb_put_uint64le(struct mbdata *mbp, uint64_t x)
{
uint64_t y = htoleq(x);
- return (mb_put_mem(mbp, (char *)&y, sizeof (y)));
+ return (mb_put_mem(mbp, &y, sizeof (y)));
}
int
-mb_put_mem(struct mbdata *mbp, const char *source, size_t size)
+mb_put_mem(struct mbdata *mbp, const void *vmem, size_t size)
{
struct mbuf *m;
+ const char *src;
char *dst;
size_t cplen;
int error;
if (size == 0)
return (0);
+
+ src = vmem;
m = mbp->mb_cur;
if ((error = m_getm(m, size, &m)) != 0)
return (error);
@@ -293,9 +290,9 @@ mb_put_mem(struct mbdata *mbp, const char *source, size_t size)
if (cplen > size)
cplen = size;
dst = mtod(m, char *) + m->m_len;
- if (source) {
- bcopy(source, dst, cplen);
- source += cplen;
+ if (src) {
+ bcopy(src, dst, cplen);
+ src += cplen;
} else
bzero(dst, cplen);
size -= cplen;
@@ -307,10 +304,26 @@ mb_put_mem(struct mbdata *mbp, const char *source, size_t size)
return (0);
}
+/*
+ * Append another mbuf to the mbuf chain.
+ * If what we're appending is smaller than
+ * the current trailing space, just copy.
+ * This always consumes the passed mbuf.
+ */
int
mb_put_mbuf(struct mbdata *mbp, struct mbuf *m)
{
- mbp->mb_cur->m_next = m;
+ struct mbuf *cm = mbp->mb_cur;
+ int ts = M_TRAILINGSPACE(cm);
+
+ if (m->m_next == NULL && m->m_len <= ts) {
+ /* just copy */
+ mb_put_mem(mbp, m->m_data, m->m_len);
+ m_freem(m);
+ return (0);
+ }
+
+ cm->m_next = m;
while (m) {
mbp->mb_count += m->m_len;
if (m->m_next == NULL)
@@ -322,17 +335,62 @@ mb_put_mbuf(struct mbdata *mbp, struct mbuf *m)
return (0);
}
+/*
+ * Convenience function to put an OEM or Unicode string,
+ * null terminated, and aligned if necessary.
+ */
int
-mb_put_pstring(struct mbdata *mbp, const char *s)
+mb_put_dstring(struct mbdata *mbp, const char *s, int uc)
{
- int error, len = strlen(s);
-
- if (len > 255) {
- len = 255;
+ int err;
+
+ if (uc) {
+ /* Put Unicode. align(2) first. */
+ if (mbp->mb_count & 1)
+ mb_put_uint8(mbp, 0);
+ err = mb_put_ustring(mbp, s);
+ } else {
+ /* Put ASCII (really OEM) */
+ err = mb_put_astring(mbp, s);
}
- if ((error = mb_put_uint8(mbp, len)) != 0)
- return (error);
- return (mb_put_mem(mbp, s, len));
+
+ return (err);
+}
+
+/*
+ * Put an ASCII string (really OEM), given a UTF-8 string.
+ */
+int
+mb_put_astring(struct mbdata *mbp, const char *s)
+{
+ char *abuf;
+ int err, len;
+
+ abuf = convert_utf8_to_wincs(s);
+ if (abuf == NULL)
+ return (ENOMEM);
+ len = strlen(abuf) + 1;
+ err = mb_put_mem(mbp, abuf, len);
+ free(abuf);
+ return (err);
+}
+
+/*
+ * Put UCS-2LE, given a UTF-8 string.
+ */
+int
+mb_put_ustring(struct mbdata *mbp, const char *s)
+{
+ uint16_t *ubuf;
+ int err, len;
+
+ ubuf = convert_utf8_to_leunicode(s);
+ if (ubuf == NULL)
+ return (ENOMEM);
+ len = unicode_strlen(ubuf) + 1;
+ err = mb_put_mem(mbp, ubuf, (len << 1));
+ free(ubuf);
+ return (err);
}
/*
@@ -343,111 +401,114 @@ mb_put_pstring(struct mbdata *mbp, const char *s)
int
mb_get_uint8(struct mbdata *mbp, uint8_t *x)
{
- return (mb_get_mem(mbp, (char *)x, 1));
+ return (mb_get_mem(mbp, x, 1));
}
int
mb_get_uint16(struct mbdata *mbp, uint16_t *x)
{
- return (mb_get_mem(mbp, (char *)x, 2));
+ return (mb_get_mem(mbp, x, 2));
}
int
mb_get_uint16le(struct mbdata *mbp, uint16_t *x)
{
uint16_t v;
- int error = mb_get_uint16(mbp, &v);
+ int err;
+ if ((err = mb_get_mem(mbp, &v, 2)) != 0)
+ return (err);
if (x != NULL)
*x = letohs(v);
- return (error);
+ return (0);
}
int
mb_get_uint16be(struct mbdata *mbp, uint16_t *x) {
uint16_t v;
- int error = mb_get_uint16(mbp, &v);
+ int err;
+ if ((err = mb_get_mem(mbp, &v, 2)) != 0)
+ return (err);
if (x != NULL)
*x = betohs(v);
- return (error);
+ return (0);
}
int
mb_get_uint32(struct mbdata *mbp, uint32_t *x)
{
- return (mb_get_mem(mbp, (char *)x, 4));
+ return (mb_get_mem(mbp, x, 4));
}
int
mb_get_uint32be(struct mbdata *mbp, uint32_t *x)
{
uint32_t v;
- int error;
+ int err;
- error = mb_get_uint32(mbp, &v);
+ if ((err = mb_get_mem(mbp, &v, 4)) != 0)
+ return (err);
if (x != NULL)
*x = betohl(v);
- return (error);
+ return (0);
}
int
mb_get_uint32le(struct mbdata *mbp, uint32_t *x)
{
uint32_t v;
- int error;
+ int err;
- error = mb_get_uint32(mbp, &v);
+ if ((err = mb_get_mem(mbp, &v, 4)) != 0)
+ return (err);
if (x != NULL)
*x = letohl(v);
- return (error);
+ return (0);
}
int
mb_get_uint64(struct mbdata *mbp, uint64_t *x)
{
- return (mb_get_mem(mbp, (char *)x, 8));
+ return (mb_get_mem(mbp, x, 8));
}
int
mb_get_uint64be(struct mbdata *mbp, uint64_t *x)
{
uint64_t v;
- int error;
+ int err;
- error = mb_get_uint64(mbp, &v);
+ if ((err = mb_get_mem(mbp, &v, 8)) != 0)
+ return (err);
if (x != NULL)
*x = betohq(v);
- return (error);
+ return (0);
}
int
mb_get_uint64le(struct mbdata *mbp, uint64_t *x)
{
uint64_t v;
- int error;
+ int err;
- error = mb_get_uint64(mbp, &v);
+ if ((err = mb_get_mem(mbp, &v, 8)) != 0)
+ return (err);
if (x != NULL)
*x = letohq(v);
- return (error);
+ return (0);
}
int
-mb_get_mem(struct mbdata *mbp, char *target, size_t size)
+mb_get_mem(struct mbdata *mbp, void *vmem, size_t size)
{
struct mbuf *m = mbp->mb_cur;
+ char *dst = vmem;
uint_t count;
while (size > 0) {
if (m == NULL) {
-#ifdef DEBUG
- printf(
- dgettext(TEXT_DOMAIN, "incomplete copy\n"));
-#endif
-#ifdef APPLE
- MBERROR("incomplete copy\n");
-#endif
+ /* DPRINT("incomplete copy"); */
return (EBADRPC);
}
count = mb_left(m, mbp->mb_pos);
@@ -460,15 +521,181 @@ mb_get_mem(struct mbdata *mbp, char *target, size_t size)
if (count > size)
count = size;
size -= count;
- if (target) {
+ if (dst) {
if (count == 1) {
- *target++ = *mbp->mb_pos;
+ *dst++ = *mbp->mb_pos;
} else {
- bcopy(mbp->mb_pos, target, count);
- target += count;
+ bcopy(mbp->mb_pos, dst, count);
+ dst += count;
}
}
mbp->mb_pos += count;
}
return (0);
}
+
+/*
+ * Get the next SIZE bytes as a separate mblk.
+ * Nothing fancy here - just copy.
+ */
+int
+mb_get_mbuf(struct mbdata *mbp, int size, struct mbuf **ret)
+{
+ mbuf_t *m;
+ int err;
+
+ err = m_get(size, &m);
+ if (err)
+ return (err);
+
+ err = mb_get_mem(mbp, m->m_data, size);
+ if (err) {
+ m_freem(m);
+ return (err);
+ }
+ m->m_len = size;
+ *ret = m;
+
+ return (0);
+}
+
+/*
+ * Get a string from the mbuf chain,
+ * either Unicode or OEM chars.
+ */
+int
+mb_get_string(struct mbdata *mbp, char **str_pp, int uc)
+{
+ int err;
+
+ if (uc)
+ err = mb_get_ustring(mbp, str_pp);
+ else
+ err = mb_get_astring(mbp, str_pp);
+ return (err);
+}
+
+/*
+ * Get an ASCII (really OEM) string from the mbuf chain
+ * and convert it to UTF-8
+ * Similar to mb_get_ustring below.
+ */
+int
+mb_get_astring(struct mbdata *real_mbp, char **str_pp)
+{
+ struct mbdata tmp_mb, *mbp;
+ char *tstr, *ostr;
+ int err, i, slen;
+ uint8_t ch;
+
+ /*
+ * First, figure out the string length.
+ * Use a copy of the real_mbp so we don't
+ * actually consume it here, then search for
+ * the null (or end of data).
+ */
+ bcopy(real_mbp, &tmp_mb, sizeof (tmp_mb));
+ mbp = &tmp_mb;
+ slen = 0;
+ for (;;) {
+ err = mb_get_uint8(mbp, &ch);
+ if (err)
+ break;
+ if (ch == 0)
+ break;
+ slen++;
+ }
+
+ /*
+ * Now read the (OEM) string for real.
+ * No need to re-check errors.
+ */
+ tstr = malloc(slen + 1);
+ if (tstr == NULL)
+ return (ENOMEM);
+ mbp = real_mbp;
+ for (i = 0; i < slen; i++) {
+ mb_get_uint8(mbp, &ch);
+ tstr[i] = ch;
+ }
+ tstr[i] = 0;
+ mb_get_uint8(mbp, NULL);
+
+ /*
+ * Convert OEM to UTF-8
+ */
+ ostr = convert_wincs_to_utf8(tstr);
+ free(tstr);
+ if (ostr == NULL)
+ return (ENOMEM);
+
+ *str_pp = ostr;
+ return (0);
+}
+
+/*
+ * Get a UCS-2LE string from the mbuf chain, and
+ * convert it to UTF-8.
+ *
+ * Similar to mb_get_astring below.
+ */
+int
+mb_get_ustring(struct mbdata *real_mbp, char **str_pp)
+{
+ struct mbdata tmp_mb, *mbp;
+ uint16_t *tstr;
+ char *ostr;
+ int err, i, slen;
+ uint16_t ch;
+
+ /*
+ * First, align(2) on the real_mbp
+ */
+ if (((uintptr_t)real_mbp->mb_pos) & 1)
+ mb_get_uint8(real_mbp, NULL);
+
+ /*
+ * Next, figure out the string length.
+ * Use a copy of the real_mbp so we don't
+ * actually consume it here, then search for
+ * the null (or end of data).
+ */
+ bcopy(real_mbp, &tmp_mb, sizeof (tmp_mb));
+ mbp = &tmp_mb;
+ slen = 0;
+ for (;;) {
+ err = mb_get_uint16le(mbp, &ch);
+ if (err)
+ break;
+ if (ch == 0)
+ break;
+ slen++;
+ }
+
+ /*
+ * Now read the (UCS-2) string for real.
+ * No need to re-check errors. Note:
+ * This puts the UCS-2 in NATIVE order!
+ */
+ tstr = calloc(slen + 1, 2);
+ if (tstr == NULL)
+ return (ENOMEM);
+ mbp = real_mbp;
+ for (i = 0; i < slen; i++) {
+ mb_get_uint16le(mbp, &ch);
+ tstr[i] = ch;
+ }
+ tstr[i] = 0;
+ mb_get_uint16le(mbp, NULL);
+
+ /*
+ * Convert UCS-2 (native!) to UTF-8
+ */
+ ostr = convert_unicode_to_utf8(tstr);
+ free(tstr);
+ if (ostr == NULL)
+ return (ENOMEM);
+
+ *str_pp = ostr;
+ return (0);
+}
diff --git a/usr/src/lib/libsmbfs/smb/nb.c b/usr/src/lib/libsmbfs/smb/nb.c
index f60ae0b314..f280420c54 100644
--- a/usr/src/lib/libsmbfs/smb/nb.c
+++ b/usr/src/lib/libsmbfs/smb/nb.c
@@ -32,29 +32,61 @@
* $Id: nb.c,v 1.1.1.2 2001/07/06 22:38:42 conrad Exp $
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
#include <sys/param.h>
#include <sys/socket.h>
-#include <ctype.h>
-#include <netdb.h>
#include <errno.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
-#include <stdio.h>
#include <unistd.h>
#include <libintl.h>
+#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <cflib.h>
#include <netsmb/netbios.h>
#include <netsmb/smb_lib.h>
#include <netsmb/nb_lib.h>
-#include <cflib.h>
+int nb_ctx_setwins(struct nb_ctx *, const char *, const char *);
+
+
+/*
+ * API for library consumer to set wins1, wins2
+ */
+int
+smb_ctx_setwins(struct smb_ctx *ctx, const char *wins1, const char *wins2)
+{
+ struct nb_ctx *nb = ctx->ct_nb;
+
+ if (nb == NULL)
+ return (EINVAL);
+
+ return (nb_ctx_setwins(nb, wins1, wins2));
+}
+
+/*
+ * API for library consumer to set NB scope.
+ */
+int
+smb_ctx_setscope(struct smb_ctx *ctx, const char *scope)
+{
+ struct nb_ctx *nb = ctx->ct_nb;
+
+ if (nb == NULL)
+ return (EINVAL);
+
+ return (nb_ctx_setscope(nb, scope));
+}
int
nb_ctx_create(struct nb_ctx **ctxpp)
@@ -81,36 +113,37 @@ nb_ctx_done(struct nb_ctx *ctx)
free(ctx);
}
-static int
-nb_ctx_setwins(in_addr_t *ina_p, const char *str)
+int
+nb_ctx_setwins(struct nb_ctx *ctx, const char *wins1, const char *wins2)
{
struct in_addr ina;
- struct sockaddr *sap;
int error;
- if (str == NULL || str[0] == 0)
- return (EINVAL);
+ if (wins1 == NULL) {
+ ctx->nb_wins1 = 0;
+ ctx->nb_wins2 = 0;
+ return (0);
+ }
- if (inet_aton(str, &ina)) {
- *ina_p = ina.s_addr;
- } else {
- error = nb_resolvehost_in(str, &sap);
+ error = nb_resolvehost_in(wins1, &ina);
+ if (error) {
+ smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
+ error, wins1);
+ return (error);
+ }
+ ctx->nb_wins1 = ina.s_addr;
+
+ if (wins2 == NULL)
+ ctx->nb_wins2 = 0;
+ else {
+ error = nb_resolvehost_in(wins2, &ina);
if (error) {
smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
- error, str);
+ error, wins2);
return (error);
}
- if (sap->sa_family != AF_INET) {
- smb_error(dgettext(TEXT_DOMAIN,
- "unsupported address family %d"), 0,
- sap->sa_family);
- return (EINVAL);
- }
- /*LINTED*/
- *ina_p = ((struct sockaddr_in *)sap)->sin_addr.s_addr;
- free(sap);
+ ctx->nb_wins2 = ina.s_addr;
}
-
return (0);
}
@@ -126,10 +159,9 @@ nb_ctx_setns(struct nb_ctx *ctx, const char *addr)
{
int error;
- error = nb_ctx_setwins(&ctx->nb_wins1, addr);
+ error = nb_ctx_setwins(ctx, addr, NULL);
if (error)
return (error);
- ctx->nb_wins2 = 0;
/* Deal with explicit request for broadcast. */
if (ctx->nb_wins1 == INADDR_BROADCAST) {
@@ -182,23 +214,35 @@ int
nb_ctx_readrcsection(struct rcfile *rcfile, struct nb_ctx *ctx,
const char *sname, int level)
{
- char *p;
+ char *wins1, *wins2;
int error;
int nbns_enable;
int nbns_broadcast;
if (level > 1)
return (EINVAL);
+
+ /* External callers pass NULL to get the default. */
+ if (rcfile == NULL)
+ rcfile = smb_rc;
+
#ifdef NOT_DEFINED
rc_getint(rcfile, sname, "nbtimeout", &ctx->nb_timo);
rc_getstringptr(rcfile, sname, "nbscope", &p);
if (p)
nb_ctx_setscope(ctx, p);
#endif
- /* "nbns" will be "wins1" some day, and we'll have a "wins2" also */
- rc_getstringptr(rcfile, sname, "nbns", &p);
- if (p) {
- error = nb_ctx_setwins(&ctx->nb_wins1, p);
+ /*
+ * Get "wins1", "wins2" config strings.
+ * Also support legacy "nbns".
+ */
+ rc_getstringptr(rcfile, sname, "wins1", &wins1);
+ if (wins1 == NULL)
+ rc_getstringptr(rcfile, sname, "nbns", &wins1);
+ rc_getstringptr(rcfile, sname, "wins2", &wins2);
+
+ if (wins1 != NULL) {
+ error = nb_ctx_setwins(ctx, wins1, wins2);
if (error) {
smb_error(dgettext(TEXT_DOMAIN,
"invalid address specified in the section %s"),
diff --git a/usr/src/lib/libsmbfs/smb/nb_name.c b/usr/src/lib/libsmbfs/smb/nb_name.c
index af13efa7b4..604d9142cd 100644
--- a/usr/src/lib/libsmbfs/smb/nb_name.c
+++ b/usr/src/lib/libsmbfs/smb/nb_name.c
@@ -50,7 +50,7 @@
#include "private.h"
int
-nb_snballoc(int namelen, struct sockaddr_nb **dst)
+nb_snballoc(struct sockaddr_nb **dst)
{
struct sockaddr_nb *snb;
int slen;
@@ -73,6 +73,9 @@ nb_snbfree(struct sockaddr *snb)
/*
* Create a full NETBIOS address
+ * Passed names should already be upper case.
+ * Stores the names truncated or blank padded.
+ * NetBIOS name encoding happens later.
*/
int
nb_sockaddr(struct sockaddr *peer, struct nb_name *np,
@@ -81,53 +84,23 @@ nb_sockaddr(struct sockaddr *peer, struct nb_name *np,
{
struct sockaddr_nb *snb;
struct sockaddr_in *sin;
- struct hostent *hst;
- int nmlen, error;
+ int error;
if (peer && (peer->sa_family != AF_INET))
return (EPROTONOSUPPORT);
-#if NOT_DEFINED /* moved encoding into kernel */
- nmlen = nb_name_len(np);
- if (nmlen < NB_ENCNAMELEN)
- return (EINVAL);
-#else
- nmlen = NB_NAMELEN;
-#endif
- error = nb_snballoc(nmlen, &snb);
+ error = nb_snballoc(&snb);
if (error)
return (error);
- /*
- * Moved toupper() work to callers.
- *
- * Moved NetBIOS name encoding into the driver
- * so we have readable names right up until the
- * point where we marshall them in to a message.
- * Just makes debugging easier.
- */
-#if NOT_DEFINED
- if (nmlen != nb_name_encode(np, snb->snb_name))
- printf(dgettext(TEXT_DOMAIN,
- "a bug somewhere in the nb_name* code\n"));
- /* XXX */
-#else
- /*
- * OK, nb_snballoc() did bzero, set snb_family.
- * Hacks for "*" moved here from nb_name_encode(),
- * but belongs where nn_name is filled in...
- * XXX fix later
- */
if (strcmp(np->nn_name, "*") == 0) {
/* Star is special: No blanks, type, etc. */
snb->snb_name[0] = '*';
} else {
/* Normal name: pad with blanks, add type. */
- assert(NB_NAMELEN == 16);
snprintf(snb->snb_name, NB_NAMELEN,
"%-15.15s", np->nn_name);
snb->snb_name[15] = (char)np->nn_type;
}
-#endif
if (peer) {
/*LINTED*/
@@ -182,38 +155,20 @@ nb_encname_len(const uchar_t *str)
}
int
-nb_name_encode(struct nb_name *np, uchar_t *dst)
+nb_name_encode(struct mbdata *mbp, struct nb_name *nn)
{
- char *name;
- uchar_t *plen;
- uchar_t ch, *cp = dst;
- char *p, buf1[NB_NAMELEN+1];
+ char *plen;
+ uchar_t ch;
+ char *p, namebuf[NB_NAMELEN+1];
int i, lblen;
- /*
- * XXX: I'd rather see this part moved into
- * callers of this function, leaving just
- * the pure NB encoding here. -GWR
- */
- name = np->nn_name;
- if (name[0] == '*') {
- /* Star is special: No blanks, type, etc. */
- bzero(buf1, NB_NAMELEN);
- buf1[0] = '*';
- } else {
- /* Normal name: pad with blanks, add type. */
- assert(NB_NAMELEN == 16);
- snprintf(buf1, NB_NAMELEN,
- "%-15.15s", name);
- buf1[15] = (char)np->nn_type;
- }
- name = buf1;
+ bcopy(nn->nn_name, namebuf, NB_NAMELEN);
+ namebuf[NB_NAMELEN-1] = (char)nn->nn_type;
+ namebuf[NB_NAMELEN] = '\0'; /* for debug */
/*
* Do the NetBIOS "first-level encoding" here.
- * (RFC1002 explains this wierdness...)
- * See similar code in kernel nsmb module:
- * uts/common/fs/smbclnt/netsmb/smb_trantcp.c
+ * (RFC1002 explains this weirdness...)
*
* Here is what we marshall:
* uint8_t NAME_LENGTH (always 32)
@@ -223,13 +178,13 @@ nb_name_encode(struct nb_name *np, uchar_t *dst)
*/
/* NAME_LENGTH */
- *cp++ = (2 * NB_NAMELEN);
+ mb_put_uint8(mbp, (2 * NB_NAMELEN));
/* ENCODED_NAME */
for (i = 0; i < NB_NAMELEN; i++) {
- ch = name[i];
- *cp++ = 'A' + ((ch >> 4) & 0xF);
- *cp++ = 'A' + ((ch) & 0xF);
+ ch = namebuf[i];
+ mb_put_uint8(mbp, 'A' + ((ch >> 4) & 0xF));
+ mb_put_uint8(mbp, 'A' + ((ch) & 0xF));
}
/*
@@ -241,32 +196,38 @@ nb_name_encode(struct nb_name *np, uchar_t *dst)
* start of each string. This keeps a pointer
* to the location and fills it in after the
* length of the string is determined.
+ *
+ * One string of length zero terminates.
+ * With no scope string, the zero-length
+ * string is the only thing there.
*/
-#if NOT_DEFINED /* XXX: not yet */
- if (np->nn_scope) {
- plen = cp++;
- *plen = 0; /* fill in later */
- lblen = 0;
- for (p = np->nn_scope; ; p++) {
- if (*p == '.' || *p == 0) {
- *plen = lblen;
- if (*p == 0)
- break;
- plen = cp++;
- *plen = 0;
- lblen = 0;
- } else {
- if (lblen < NB_MAXLABLEN) {
- *cp++ = *p;
- lblen++;
- }
+ if (nn->nn_scope == NULL) {
+ mb_put_uint8(mbp, 0);
+ return (0);
+ }
+
+ mb_fit(mbp, 1, &plen);
+ *plen = 0; /* will update below */
+ lblen = 0;
+ for (p = nn->nn_scope; ; p++) {
+ if (*p == '\0') {
+ *plen = lblen;
+ if (lblen)
+ mb_put_uint8(mbp, 0);
+ break;
+ }
+ if (*p == '.') {
+ *plen = lblen;
+ mb_fit(mbp, 1, &plen);
+ *plen = 0;
+ lblen = 0;
+ } else {
+ if (lblen < NB_MAXLABLEN) {
+ mb_put_uint8(mbp, *p);
+ lblen++;
}
}
- } else
-#endif /* XXX: not yet */
- {
- *cp++ = 0;
}
- return (cp - dst);
+ return (0);
}
diff --git a/usr/src/lib/libsmbfs/smb/nb_net.c b/usr/src/lib/libsmbfs/smb/nb_net.c
index 29109c3093..ec0db6cffc 100644
--- a/usr/src/lib/libsmbfs/smb/nb_net.c
+++ b/usr/src/lib/libsmbfs/smb/nb_net.c
@@ -38,13 +38,14 @@
#include <sys/sockio.h>
#include <net/if.h>
#include <ctype.h>
-#include <netdb.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <unistd.h>
+#include <netdb.h>
+#include <nss_dbdefs.h>
#include <err.h>
@@ -59,32 +60,14 @@
*/
int
-nb_getlocalname(char *name, size_t maxlen)
-{
- char buf[1024], *cp;
-
- if (gethostname(buf, sizeof (buf)) != 0)
- return (errno);
- cp = strchr(buf, '.');
- if (cp)
- *cp = 0;
- strlcpy(name, buf, maxlen);
- return (0);
-}
-
-int
-nb_resolvehost_in(const char *name, struct sockaddr **dest)
+nb_resolvehost_in(const char *name, struct in_addr *ia)
{
- struct hostent *h;
- struct sockaddr_in *sinp;
- in_addr_t addr;
- struct in_addr in;
- int len;
- char **p;
+ char he_buf[NSS_BUFLEN_HOSTS];
+ struct hostent he, *h;
+ int err;
-
- h = gethostbyname(name);
- if (!h) {
+ h = gethostbyname_r(name, &he, he_buf, sizeof (he_buf), &err);
+ if (h == NULL) {
#ifdef DEBUG
warnx("can't get server address `%s': ", name);
#endif
@@ -102,19 +85,7 @@ nb_resolvehost_in(const char *name, struct sockaddr **dest)
#endif
return (EAFNOSUPPORT);
}
- len = sizeof (struct sockaddr_in);
- sinp = malloc(len);
- if (sinp == NULL)
- return (ENOMEM);
- bzero(sinp, len);
- /*
- * There is no sin_len in sockaddr_in structure on Solaris.
- * sinp->sin_len = len;
- */
- sinp->sin_family = h->h_addrtype;
- memcpy(&sinp->sin_addr.s_addr, *h->h_addr_list,\
- sizeof (sinp->sin_addr.s_addr));
- sinp->sin_port = htons(SMB_TCP_PORT);
- *dest = (struct sockaddr *)sinp;
+
+ memcpy(ia, h->h_addr, sizeof (*ia));
return (0);
}
diff --git a/usr/src/lib/libsmbfs/smb/nb_ssn.c b/usr/src/lib/libsmbfs/smb/nb_ssn.c
new file mode 100644
index 0000000000..bd53ce6fce
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/nb_ssn.c
@@ -0,0 +1,330 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * NetBIOS session service functions
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/mchain.h>
+
+#include "private.h"
+#include "charsets.h"
+
+static int nb_ssn_send(struct smb_ctx *, struct mbdata *, int, int);
+static int nb_ssn_recv(struct smb_ctx *, struct mbdata *, int *, int *);
+static int nb_ssn_pollin(struct smb_ctx *, int);
+
+/*
+ * Send a data message.
+ */
+int
+smb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp)
+{
+ return (nb_ssn_send(ctx, mbp, 0, mbp->mb_count));
+}
+
+/*
+ * Send a NetBIOS message, after
+ * prepending the 4-byte header.
+ */
+static int
+nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp,
+ int mtype, int mlen)
+{
+ mbuf_t *m = mbp->mb_top;
+ int fd = ctx->ct_tran_fd;
+ int err, flags;
+ uint32_t hdr, hdrbuf;
+
+ if (m == NULL)
+ return (EINVAL);
+
+ /*
+ * Prepend the NetBIOS header.
+ * Using mbuf trickery to ensure it's
+ * not separated from the body.
+ */
+ hdr = (mtype << 24) | mlen;
+ hdrbuf = htonl(hdr);
+ m->m_data -= 4;
+ m->m_len += 4;
+ bcopy(&hdrbuf, m->m_data, 4);
+
+ /* Send it. */
+ while (m) {
+ flags = (m->m_next) ? T_MORE : T_PUSH;
+ if (t_snd(fd, m->m_data, m->m_len, flags) < 0) {
+ if (t_errno == TSYSERR)
+ err = errno;
+ else
+ err = EPROTO;
+ DPRINT("t_snd: t_errno %d, err %d", t_errno, err);
+ return (err);
+ }
+ m = m->m_next;
+ }
+ return (0);
+}
+
+/*
+ * Receive a data message. Discard anything else.
+ * Caller must deal with EAGAIN, EINTR.
+ */
+int
+smb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mbp)
+{
+ int err, mtype, mlen;
+ err = nb_ssn_recv(ctx, mbp, &mtype, &mlen);
+ if (err)
+ return (err);
+ if (mtype != NB_SSN_MESSAGE) {
+ DPRINT("discard type 0x%x", mtype);
+ mb_done(mbp);
+ return (EAGAIN);
+ }
+ if (mlen == 0) {
+ DPRINT("zero length");
+ mb_done(mbp);
+ return (EAGAIN);
+ }
+
+ return (0);
+}
+
+/*
+ * Receive a NetBIOS message, any type.
+ * Give caller type and length.
+ */
+static int
+nb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mb,
+ int *mtype, int *mlen)
+{
+ char *buf;
+ uint32_t hdr, hdrbuf;
+ int cnt, len, err, moreflag;
+ int fd = ctx->ct_tran_fd;
+ int tmo = smb_recv_timeout * 1000;
+
+ /*
+ * Start by getting the header
+ * (four bytes)
+ */
+ if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
+ DPRINT("pollin err %d", err);
+ return (err);
+ }
+ moreflag = 0;
+ cnt = t_rcv(fd, &hdrbuf, sizeof (hdrbuf), &moreflag);
+ if (cnt < 0) {
+ err = get_xti_err(fd);
+ DPRINT("t_errno %d err %d", t_errno, err);
+ return (err);
+ }
+
+ if (cnt != sizeof (hdrbuf)) {
+ DPRINT("hdr cnt %d", cnt);
+ return (EPROTO);
+ }
+
+ /*
+ * Decode the header, get the length.
+ */
+ hdr = ntohl(hdrbuf);
+ *mtype = (hdr >> 24) & 0xff;
+ *mlen = hdr & 0xffffff;
+
+ if (mlen == 0)
+ return (0);
+
+ /*
+ * Get a message buffer, read the payload
+ */
+ if ((err = mb_init(mb, *mlen)) != 0)
+ return (err);
+ buf = mb->mb_top->m_data;
+ len = *mlen;
+ while (len > 0) {
+ if (!moreflag) {
+ if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
+ DPRINT("pollin err %d", err);
+ return (err);
+ }
+ }
+
+ moreflag = 0;
+ cnt = t_rcv(fd, buf, len, &moreflag);
+ if (cnt < 0) {
+ err = get_xti_err(fd);
+ DPRINT("t_errno %d err %d", t_errno, err);
+ return (err);
+ }
+ buf += cnt;
+ len -= cnt;
+ }
+ mb->mb_top->m_len = *mlen;
+ mb->mb_count = *mlen;
+
+ return (0);
+}
+
+int
+get_xti_err(int fd)
+{
+ int look;
+ if (t_errno == TSYSERR)
+ return (errno);
+
+ if (t_errno == TLOOK) {
+ look = t_look(fd);
+ switch (look) {
+ case T_DISCONNECT:
+ (void) t_rcvdis(fd, NULL);
+ (void) t_snddis(fd, NULL);
+ return (ECONNRESET);
+ case T_ORDREL:
+ /* Received orderly release indication */
+ (void) t_rcvrel(fd);
+ /* Send orderly release indicator */
+ (void) t_sndrel(fd);
+ return (ECONNRESET);
+ }
+ }
+ return (EPROTO);
+}
+
+/*
+ * Wait for data we can receive.
+ * Timeout is mSec., as for poll(2)
+ */
+static int
+nb_ssn_pollin(struct smb_ctx *ctx, int tmo)
+{
+ struct pollfd pfd[1];
+ int cnt, err;
+
+ pfd[0].fd = ctx->ct_tran_fd;
+ pfd[0].events = POLLIN | POLLPRI;
+ pfd[0].revents = 0;
+ cnt = poll(pfd, 1, tmo);
+ switch (cnt) {
+ case 0:
+ err = ETIME;
+ break;
+ case -1:
+ err = errno;
+ break;
+ default:
+ err = 0;
+ break;
+ }
+ return (err);
+}
+
+/*
+ * Send a NetBIOS session request and
+ * wait for the response.
+ */
+int
+nb_ssn_request(struct smb_ctx *ctx, char *srvname)
+{
+ struct mbdata req, res;
+ struct nb_name lcl, srv;
+ int err, mtype, mlen;
+ char *ucwks;
+
+ bzero(&req, sizeof (req));
+ bzero(&res, sizeof (res));
+
+ if ((err = mb_init(&req, M_MINSIZE)) != 0)
+ goto errout;
+
+ ucwks = utf8_str_toupper(ctx->ct_locname);
+ if (ucwks == NULL) {
+ err = ENOMEM;
+ goto errout;
+ }
+
+ /* Local NB name. */
+ snprintf(lcl.nn_name, NB_NAMELEN, "%-15.15s", ucwks);
+ lcl.nn_type = NBT_WKSTA;
+ lcl.nn_scope = ctx->ct_nb->nb_scope;
+
+ /* Server NB name */
+ snprintf(srv.nn_name, NB_NAMELEN, "%-15.15s", srvname);
+ srv.nn_type = NBT_SERVER;
+ srv.nn_scope = ctx->ct_nb->nb_scope;
+
+ /*
+ * Build the request. Header is prepended later.
+ */
+ if ((err = nb_name_encode(&req, &srv)) != 0)
+ goto errout;
+ if ((err = nb_name_encode(&req, &lcl)) != 0)
+ goto errout;
+
+ /*
+ * Send it, wait for the reply.
+ */
+ err = nb_ssn_send(ctx, &req, NB_SSN_REQUEST, req.mb_count);
+ if (err) {
+ DPRINT("send, err %d", err);
+ goto errout;
+ }
+ err = nb_ssn_recv(ctx, &res, &mtype, &mlen);
+ if (err) {
+ DPRINT("recv, err %d", err);
+ goto errout;
+ }
+
+ if (mtype != NB_SSN_POSRESP) {
+ DPRINT("recv, mtype 0x%x", mtype);
+ err = ECONNREFUSED;
+ goto errout;
+ }
+
+ return (0);
+
+errout:
+ mb_done(&res);
+ mb_done(&req);
+ return (err);
+}
diff --git a/usr/src/lib/libsmbfs/smb/nbns_rq.c b/usr/src/lib/libsmbfs/smb/nbns_rq.c
index 773466b7fa..d0e85209e7 100644
--- a/usr/src/lib/libsmbfs/smb/nbns_rq.c
+++ b/usr/src/lib/libsmbfs/smb/nbns_rq.c
@@ -55,6 +55,7 @@
#include <netsmb/nb_lib.h>
#include <netsmb/mchain.h>
+#include "charsets.h"
#include "private.h"
/*
@@ -96,7 +97,80 @@ static int nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp);
static int nbns_rq_prepare(struct nbns_rq *rqp);
static int nbns_rq(struct nbns_rq *rqp);
-static struct nb_ifdesc *nb_iflist = NULL;
+/*
+ * Call NetBIOS name lookup and return a result in the
+ * same form as getaddrinfo(3) returns. Return code is
+ * zero or one of the EAI_xxx codes like getaddrinfo.
+ */
+int
+nbns_getaddrinfo(const char *name, struct nb_ctx *nbc, struct addrinfo **res)
+{
+ struct addrinfo *nai = NULL;
+ struct sockaddr *sap = NULL;
+ char *ucname = NULL;
+ int err;
+
+ /*
+ * Try NetBIOS name lookup.
+ */
+ if (strlen(name) >= NB_NAMELEN) {
+ err = EAI_OVERFLOW;
+ goto out;
+ }
+ ucname = utf8_str_toupper(name);
+ if (ucname == NULL)
+ goto nomem;
+
+ /* Note: this returns an NBERROR value. */
+ err = nbns_resolvename(ucname, nbc, &sap);
+ if (err) {
+ if (smb_verbose)
+ smb_error(dgettext(TEXT_DOMAIN,
+ "nbns_resolvename: %s"),
+ err, name);
+ err = EAI_NODATA;
+ goto out;
+ }
+ /* Note: sap allocated */
+
+ /*
+ * Build the addrinfo struct to return.
+ */
+ nai = malloc(sizeof (*nai));
+ if (nai == NULL)
+ goto nomem;
+ bzero(nai, sizeof (*nai));
+
+ nai->ai_flags = AI_CANONNAME;
+ nai->ai_family = sap->sa_family;
+ nai->ai_socktype = SOCK_STREAM;
+ nai->ai_canonname = ucname;
+ ucname = NULL;
+
+ /*
+ * The type of this is really sockaddr_in,
+ * but is returned in the generic form.
+ * See nbns_resolvename.
+ */
+ nai->ai_addrlen = sizeof (struct sockaddr_in);
+ nai->ai_addr = sap;
+
+ *res = nai;
+ return (0);
+
+nomem:
+ err = EAI_MEMORY;
+out:
+ if (nai != NULL)
+ free(nai);
+ if (sap)
+ free(sap);
+ if (ucname)
+ free(ucname);
+ *res = NULL;
+
+ return (err);
+}
int
nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
@@ -107,7 +181,7 @@ nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
struct sockaddr_in *dest;
int error, rdrcount, len;
- if (strlen(name) > NB_NAMELEN)
+ if (strlen(name) >= NB_NAMELEN)
return (NBERROR(NBERR_NAMETOOLONG));
error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
if (error)
@@ -169,12 +243,11 @@ nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
return (ENOMEM);
bzero(dest, len);
/*
- * Solaris sockaddr_in doesn't have this field.
+ * Solaris sockaddr_in doesn't a sin_len field.
* dest->sin_len = len;
*/
- dest->sin_family = AF_INET;
+ dest->sin_family = AF_NETBIOS; /* nb_lib.h */
bcopy(rr.rr_data + 2, &dest->sin_addr.s_addr, 4);
- dest->sin_port = htons(SMB_TCP_PORT);
*adpp = (struct sockaddr *)dest;
ctx->nb_lastns = rqp->nr_sender;
break;
@@ -183,20 +256,12 @@ nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
return (error);
}
-static char *
-smb_optstrncpy(char *d, char *s, unsigned maxlen)
-{
- if (d && s) {
- strncpy(d, s, maxlen);
- d[maxlen] = (char)0;
- }
- return (d);
-}
-
-
+/*
+ * NB: system, workgroup are both NB_NAMELEN
+ */
int
-nbns_getnodestatus(struct sockaddr *targethost,
- struct nb_ctx *ctx, char *system, char *workgroup)
+nbns_getnodestatus(struct nb_ctx *ctx,
+ struct in_addr *targethost, char *system, char *workgroup)
{
struct nbns_rq *rqp;
struct nbns_rr rr;
@@ -204,12 +269,9 @@ nbns_getnodestatus(struct sockaddr *targethost,
struct nbns_nr *nrp;
char nrtype;
char *cp, *retname = NULL;
- struct sockaddr_in *dest;
unsigned char nrcount;
- int error, rdrcount, i, foundserver = 0, foundgroup = 0;
+ int error, i, foundserver = 0, foundgroup = 0;
- if (targethost->sa_family != AF_INET)
- return (EINVAL);
error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
if (error)
return (error);
@@ -224,10 +286,7 @@ nbns_getnodestatus(struct sockaddr *targethost,
rqp->nr_qdcount = 1;
rqp->nr_maxretry = 2;
- /* LINTED */
- dest = (struct sockaddr_in *)targethost;
- rqp->nr_dest = dest->sin_addr;
-
+ rqp->nr_dest = *targethost;
error = nbns_rq_prepare(rqp);
if (error) {
nbns_rq_done(rqp);
@@ -266,12 +325,14 @@ nbns_getnodestatus(struct sockaddr *targethost,
*cp = (char)0;
}
nrp->ns_flags = ntohs(nrp->ns_flags);
+ DPRINT(" %s[%02x] Flags 0x%x",
+ nrp->ns_name, nrtype, nrp->ns_flags);
if (nrp->ns_flags & NBNS_GROUPFLG) {
if (!foundgroup ||
(foundgroup != NBT_WKSTA+1 &&
nrtype == NBT_WKSTA)) {
- smb_optstrncpy(workgroup, nrp->ns_name,
- SMB_MAXUSERNAMELEN);
+ strlcpy(workgroup, nrp->ns_name,
+ NB_NAMELEN);
foundgroup = nrtype+1;
}
} else {
@@ -281,14 +342,17 @@ nbns_getnodestatus(struct sockaddr *targethost,
*/
retname = nrp->ns_name;
}
- if (nrtype == NBT_SERVER) {
- smb_optstrncpy(system, nrp->ns_name,
- SMB_MAXSRVNAMELEN);
+ /*
+ * Keep the first NBT_SERVER name.
+ */
+ if (nrtype == NBT_SERVER && foundserver == 0) {
+ strlcpy(system, nrp->ns_name,
+ NB_NAMELEN);
foundserver = 1;
}
}
if (!foundserver)
- smb_optstrncpy(system, retname, SMB_MAXSRVNAMELEN);
+ strlcpy(system, retname, NB_NAMELEN);
ctx->nb_lastns = rqp->nr_sender;
out:
@@ -370,8 +434,7 @@ nbns_rq_prepare(struct nbns_rq *rqp)
struct nb_ctx *ctx = rqp->nr_nbd;
struct mbdata *mbp = &rqp->nr_rq;
uint16_t ofr; /* opcode, flags, rcode */
- uchar_t *cp;
- int len, error;
+ int error;
/*
* Replacing with one argument.
@@ -396,11 +459,7 @@ nbns_rq_prepare(struct nbns_rq *rqp)
if (rqp->nr_qdcount) {
if (rqp->nr_qdcount > 1)
return (EINVAL);
- len = nb_name_len(rqp->nr_qdname);
- error = mb_fit(mbp, len, (char **)&cp);
- if (error)
- return (error);
- nb_name_encode(rqp->nr_qdname, cp);
+ nb_name_encode(mbp, rqp->nr_qdname);
mb_put_uint16be(mbp, rqp->nr_qdtype);
mb_put_uint16be(mbp, rqp->nr_qdclass);
}
@@ -485,7 +544,7 @@ nbns_rq_send(struct nbns_rq *rqp, in_addr_t ina)
bzero(&dest, sizeof (dest));
dest.sin_family = AF_INET;
- dest.sin_port = htons(NBNS_UDP_PORT);
+ dest.sin_port = htons(IPPORT_NETBIOS_NS);
dest.sin_addr.s_addr = ina;
if (ina == INADDR_BROADCAST) {
@@ -520,7 +579,6 @@ nbns_rq(struct nbns_rq *rqp)
struct nb_ctx *ctx = rqp->nr_nbd;
struct mbdata *mbp = &rqp->nr_rq;
uint16_t ofr, rpid;
- uint8_t nmflags;
int error, tries, maxretry;
error = nbns_rq_opensocket(rqp);
@@ -599,6 +657,8 @@ do_recv:
return (NBERROR(NBERR_INVALIDRESPONSE));
break;
}
+ if (tries == maxretry)
+ return (NBERROR(NBERR_HOSTNOTFOUND));
mb_get_uint16be(mbp, &ofr);
rqp->nr_rpnmflags = (ofr >> 4) & 0x7F;
diff --git a/usr/src/lib/libsmbfs/smb/negprot.c b/usr/src/lib/libsmbfs/smb/negprot.c
new file mode 100644
index 0000000000..6c1649f1bb
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/negprot.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * SMB Negotiate Protocol, and related.
+ * Copied from the driver: smb_smb.c
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "charsets.h"
+#include "private.h"
+
+/*
+ * SMB dialects that we know about.
+ */
+struct smb_dialect {
+ int d_id;
+ const char *d_name;
+};
+static struct smb_dialect smb_dialects[] = {
+ {SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"},
+ {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"},
+ {SMB_DIALECT_LANMAN2_0, "LM1.2X002"},
+ {SMB_DIALECT_LANMAN2_1, "LANMAN2.1"},
+ {SMB_DIALECT_NTLM0_12, "NT LM 0.12"},
+ {-1, NULL}
+};
+
+#define SMB_DIALECT_MAX \
+ (sizeof (smb_dialects) / sizeof (struct smb_dialect) - 2)
+
+/*
+ * SMB Negotiate Protocol
+ * Based on code from the driver: smb_smb.c
+ *
+ * If using Extended Security, oblob (output)
+ * will hold the initial security "hint".
+ */
+int
+smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob)
+{
+ struct smb_sopt *sv = &ctx->ct_sopt;
+ struct smb_iods *is = &ctx->ct_iods;
+ struct smb_rq *rqp;
+ struct mbdata *mbp;
+ struct smb_dialect *dp;
+ int err, len;
+ uint8_t wc, stime[8], eklen;
+ uint16_t dindex, bc;
+ int will_sign = 0;
+
+ /*
+ * Initialize: vc_hflags and vc_hflags2.
+ * Note: ctx->ct_hflags* are copied into the
+ * (per request) rqp->rq_hflags* by smb_rq_init,
+ * so changing them after that call will not
+ * affect THIS request.
+ */
+ ctx->ct_hflags = SMB_FLAGS_CASELESS;
+ ctx->ct_hflags2 = (SMB_FLAGS2_ERR_STATUS |
+ SMB_FLAGS2_KNOWS_LONG_NAMES);
+
+ /*
+ * Sould we offer extended security?
+ * We'll turn this back off below if
+ * the server doesn't support it.
+ */
+ if (ctx->ct_vopt & SMBVOPT_EXT_SEC)
+ ctx->ct_hflags2 |= SMB_FLAGS2_EXT_SEC;
+
+ /*
+ * The initial UID needs to be zero,
+ * or Windows XP says "bad user".
+ * The initial TID is all ones, but
+ * we don't use it or store it here
+ * because the driver handles that.
+ */
+ is->is_smbuid = 0;
+
+ /*
+ * In case we're reconnecting,
+ * free previous stuff.
+ */
+ ctx->ct_mac_seqno = 0;
+ if (ctx->ct_mackey != NULL) {
+ free(ctx->ct_mackey);
+ ctx->ct_mackey = NULL;
+ ctx->ct_mackeylen = 0;
+ }
+
+ sv = &ctx->ct_sopt;
+ bzero(sv, sizeof (struct smb_sopt));
+
+ err = smb_rq_init(ctx, SMB_COM_NEGOTIATE, &rqp);
+ if (err)
+ return (err);
+
+ /*
+ * Build the SMB request.
+ */
+ mbp = &rqp->rq_rq;
+ mb_put_uint8(mbp, 0); /* word count */
+ smb_rq_bstart(rqp);
+ for (dp = smb_dialects; dp->d_id != -1; dp++) {
+ mb_put_uint8(mbp, SMB_DT_DIALECT);
+ mb_put_astring(mbp, dp->d_name);
+ }
+ smb_rq_bend(rqp);
+
+ /*
+ * This does the OTW call
+ */
+ err = smb_rq_internal(ctx, rqp);
+ if (err) {
+ DPRINT("call failed, err %d", err);
+ goto errout;
+ }
+ if (rqp->rq_status != 0) {
+ DPRINT("nt status 0x%x", rqp->rq_status);
+ err = EBADRPC;
+ goto errout;
+ }
+
+ /*
+ * Decode the response
+ *
+ * Comments to right show names as described in
+ * The Microsoft SMB Protocol spec. [MS-SMB]
+ * section 2.2.3
+ */
+ mbp = &rqp->rq_rp;
+ (void) mb_get_uint8(mbp, &wc);
+ err = mb_get_uint16le(mbp, &dindex);
+ if (err || dindex > SMB_DIALECT_MAX) {
+ DPRINT("err %d dindex %d", err, (int)dindex);
+ goto errout;
+ }
+ dp = smb_dialects + dindex;
+ sv->sv_proto = dp->d_id;
+ DPRINT("Dialect %s", dp->d_name);
+ if (dp->d_id < SMB_DIALECT_NTLM0_12) {
+ /* XXX: User-visible warning too? */
+ DPRINT("old dialect %s", dp->d_name);
+ goto errout;
+ }
+ if (wc != 17) {
+ DPRINT("bad wc %d", (int)wc);
+ goto errout;
+ }
+ mb_get_uint8(mbp, &sv->sv_sm); /* SecurityMode */
+ mb_get_uint16le(mbp, &sv->sv_maxmux); /* MaxMpxCount */
+ mb_get_uint16le(mbp, &sv->sv_maxvcs); /* MaxCountVCs */
+ mb_get_uint32le(mbp, &sv->sv_maxtx); /* MaxBufferSize */
+ mb_get_uint32le(mbp, &sv->sv_maxraw); /* MaxRawSize */
+ mb_get_uint32le(mbp, &sv->sv_skey); /* SessionKey */
+ mb_get_uint32le(mbp, &sv->sv_caps); /* Capabilities */
+ mb_get_mem(mbp, (char *)stime, 8); /* SystemTime(s) */
+ mb_get_uint16le(mbp, (uint16_t *)&sv->sv_tz);
+ mb_get_uint8(mbp, &eklen); /* EncryptionKeyLength */
+ err = mb_get_uint16le(mbp, &bc); /* ByteCount */
+ if (err)
+ goto errout;
+
+ /* BEGIN CSTYLED */
+ /*
+ * Will we do SMB signing? Or block the connection?
+ * The table below describes this logic. References:
+ * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3]
+ * http://msdn.microsoft.com/en-us/library/cc212511.aspx
+ * http://msdn.microsoft.com/en-us/library/cc212929.aspx
+ *
+ * Srv/Cli | Required | Enabled | If Required | Disabled
+ * ------------+----------+------------+-------------+-----------
+ * Required | Signed | Signed | Signed | Blocked [1]
+ * ------------+----------+------------+-------------+-----------
+ * Enabled | Signed | Signed | Not Signed | Not Signed
+ * ------------+----------+------------+-------------+-----------
+ * If Required | Signed | Not Signed | Not Signed | Not Signed
+ * ------------+----------+------------+-------------+-----------
+ * Disabled | Blocked | Not Signed | Not Signed | Not Signed
+ *
+ * [1] Like Windows 2003 and later, we don't really implement
+ * the "Disabled" setting. Instead we implement "If Required",
+ * so we always sign if the server requires signing.
+ */
+ /* END CSTYLED */
+
+ if (sv->sv_sm & SMB_SM_SIGS_REQUIRE) {
+ /*
+ * Server requires signing. We will sign,
+ * even if local setting is "disabled".
+ */
+ will_sign = 1;
+ } else if (sv->sv_sm & SMB_SM_SIGS) {
+ /*
+ * Server enables signing (client's option).
+ * If enabled locally, do signing.
+ */
+ if (ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED)
+ will_sign = 1;
+ /* else not signing. */
+ } else {
+ /*
+ * Server does not support signing.
+ * If we "require" it, bail now.
+ */
+ if (ctx->ct_vopt & SMBVOPT_SIGNING_REQUIRED) {
+ DPRINT("Client requires signing "
+ "but server has it disabled.");
+ err = EBADRPC;
+ goto errout;
+ }
+ }
+
+ if (will_sign) {
+ ctx->ct_vcflags |= SMBV_WILL_SIGN;
+ }
+ DPRINT("Security signatures: %d", will_sign);
+
+ if (sv->sv_caps & SMB_CAP_UNICODE) {
+ ctx->ct_vcflags |= SMBV_UNICODE;
+ ctx->ct_hflags2 |= SMB_FLAGS2_UNICODE;
+
+ }
+ if ((sv->sv_caps & SMB_CAP_STATUS32) == 0) {
+ /*
+ * They don't do NT error codes.
+ *
+ * If we send requests with
+ * SMB_FLAGS2_ERR_STATUS set in
+ * Flags2, Windows 98, at least,
+ * appears to send replies with that
+ * bit set even though it sends back
+ * DOS error codes. (They probably
+ * just use the request header as
+ * a template for the reply header,
+ * and don't bother clearing that bit.)
+ *
+ * Therefore, we clear that bit in
+ * our vc_hflags2 field.
+ */
+ ctx->ct_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
+ }
+ if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
+ sv->sv_maxtx < 4096 &&
+ (sv->sv_caps & SMB_CAP_NT_SMBS) == 0) {
+ ctx->ct_vcflags |= SMBV_WIN95;
+ DPRINT("Win95 detected");
+ }
+
+ /*
+ * The rest of the message varies depending on
+ * whether we've negotiated "extended security".
+ *
+ * With extended security, we have:
+ * Server_GUID (length 16)
+ * Security_BLOB
+ * Otherwise we have:
+ * EncryptionKey (length is eklen)
+ * PrimaryDomain
+ */
+ if (sv->sv_caps & SMB_CAP_EXT_SECURITY) {
+ struct mbuf *m;
+ DPRINT("Ext.Security: yes");
+
+ /*
+ * Skip the server GUID.
+ */
+ err = mb_get_mem(mbp, NULL, SMB_GUIDLEN);
+ if (err)
+ goto errout;
+ /*
+ * Remainder is the security blob.
+ * Note: eklen "must be ignored" [MS-SMB]
+ */
+ len = (int)bc - SMB_GUIDLEN;
+ if (len < 0)
+ goto errout;
+
+ /*
+ * Get the (optional) SPNEGO "hint".
+ */
+ err = mb_get_mbuf(mbp, len, &m);
+ if (err)
+ goto errout;
+ mb_initm(oblob, m);
+ oblob->mb_count = len;
+ } else {
+ DPRINT("Ext.Security: no");
+ ctx->ct_hflags2 &= ~SMB_FLAGS2_EXT_SEC;
+
+ /*
+ * Save the "Encryption Key" (the challenge).
+ *
+ * Sanity check: make sure the sec. blob length
+ * isn't bigger than the byte count.
+ */
+ if (bc < eklen || eklen < NTLM_CHAL_SZ) {
+ err = EBADRPC;
+ goto errout;
+ }
+ err = mb_get_mem(mbp, (char *)ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
+ /*
+ * Server domain follows (ignored)
+ * Note: NOT aligned(2) - unusual!
+ */
+ }
+
+ smb_rq_done(rqp);
+
+ /*
+ * A few sanity checks on what we received,
+ * becuse we will send these in ssnsetup.
+ *
+ * Maximum outstanding requests (we care),
+ * and Max. VCs (we only use one). Also,
+ * MaxBufferSize lower limit per spec.
+ */
+ if (sv->sv_maxmux < 1)
+ sv->sv_maxmux = 1;
+ if (sv->sv_maxvcs < 1)
+ sv->sv_maxvcs = 1;
+ if (sv->sv_maxtx < 1024)
+ sv->sv_maxtx = 1024;
+
+ /*
+ * Maximum transfer size.
+ * Sanity checks:
+ *
+ * Let's be conservative about an upper limit here.
+ * Win2k uses 16644 (and others) so 32k should be a
+ * reasonable sanity limit for this value.
+ *
+ * Note that this limit does NOT affect READX/WRITEX
+ * with CAP_LARGE_..., which we nearly always use.
+ */
+ is->is_txmax = sv->sv_maxtx;
+ if (is->is_txmax > 0x8000)
+ is->is_txmax = 0x8000;
+
+ /*
+ * Max read/write sizes, WITHOUT overhead.
+ * This is just the payload size, so we must
+ * leave room for the SMB headers, etc.
+ * This is just the ct_txmax value, but
+ * reduced and rounded down. Tricky bit:
+ *
+ * Servers typically give us a value that's
+ * some nice "round" number, i.e 0x4000 plus
+ * some overhead, i.e. Win2k: 16644==0x4104
+ * Subtract for the SMB header (32) and the
+ * SMB command word and byte vectors (34?),
+ * then round down to a 512 byte multiple.
+ */
+ len = is->is_txmax - 68;
+ len &= 0xFE00;
+ /* XXX: Not sure yet which of these to keep. */
+ is->is_rwmax = len;
+ is->is_rxmax = len;
+ is->is_wxmax = len;
+
+ return (0);
+
+errout:
+ smb_rq_done(rqp);
+ if (err == 0)
+ err = EBADRPC;
+ return (err);
+}
diff --git a/usr/src/lib/libsmbfs/smb/netshareenum.c b/usr/src/lib/libsmbfs/smb/netshareenum.c
index 2d7f9c2c3a..2ee1fd7792 100644
--- a/usr/src/lib/libsmbfs/smb/netshareenum.c
+++ b/usr/src/lib/libsmbfs/smb/netshareenum.c
@@ -37,7 +37,7 @@
/* END CSTYLED */
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -47,6 +47,7 @@
#include <errno.h>
#include <netsmb/mchain.h>
+#include <netsmb/smb.h>
#include <netsmb/smb_lib.h>
#include <netsmb/smb_rap.h>
#include <netsmb/smb_netshareenum.h>
@@ -275,8 +276,6 @@ smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer,
struct smb_rap *rap;
long lval = -1;
int error;
- char *pass;
- int i;
error = smb_rap_create(0, "WrLeh", "B13BWz", &rap);
if (error)
@@ -375,5 +374,6 @@ smb_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
* XXX - do so only if it failed because we couldn't open
* the pipe?
*/
- return (rap_netshareenum(ctx, entriesp, totalp, entry_listp));
+ error = rap_netshareenum(ctx, entriesp, totalp, entry_listp);
+ return (error);
}
diff --git a/usr/src/lib/libsmbfs/smb/newvc.c b/usr/src/lib/libsmbfs/smb/newvc.c
new file mode 100644
index 0000000000..0153ffd437
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/newvc.c
@@ -0,0 +1,118 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Create a new VC given a list of addresses.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "charsets.h"
+#include "private.h"
+
+/*
+ * Ask the IOD to create a VC with this IP address.
+ */
+static int
+newvc(struct smb_ctx *ctx, struct addrinfo *ai)
+{
+ smbioc_ossn_t *ssn = &ctx->ct_ssn;
+
+ /*
+ * Copy the passed address into ssn_srvaddr,
+ * but first sanity-check lengths. Also,
+ * zero it first to avoid trailing junk.
+ */
+ if (ai->ai_addrlen > sizeof (ssn->ssn_srvaddr))
+ return (EINVAL);
+ bzero(&ssn->ssn_srvaddr, sizeof (ssn->ssn_srvaddr));
+ bcopy(ai->ai_addr, &ssn->ssn_srvaddr, ai->ai_addrlen);
+
+ return (smb_iod_cl_newvc(ctx));
+}
+
+/*
+ * Setup a new VC via the IOD.
+ * Similar to findvc.c
+ */
+int
+smb_ctx_newvc(struct smb_ctx *ctx)
+{
+ struct addrinfo *ai;
+ int err = ENOENT;
+
+ /* Should already have the address list. */
+ if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
+ return (EINVAL);
+
+ for (ai = ctx->ct_addrinfo; ai; ai = ai->ai_next) {
+
+ switch (ai->ai_family) {
+
+ case AF_INET:
+ case AF_INET6:
+ case AF_NETBIOS:
+ err = newvc(ctx, ai);
+ break;
+
+ default:
+ DPRINT("skipped family %d", ai->ai_family);
+ break;
+ }
+
+ if (err == 0) {
+ ctx->ct_flags |= SMBCF_SSNACTIVE;
+ return (0);
+ }
+ }
+
+ return (err);
+}
diff --git a/usr/src/lib/libsmbfs/smb/nls.c b/usr/src/lib/libsmbfs/smb/nls.c
index 03fe1bec13..e5b6719716 100644
--- a/usr/src/lib/libsmbfs/smb/nls.c
+++ b/usr/src/lib/libsmbfs/smb/nls.c
@@ -32,8 +32,6 @@
* $Id: nls.c,v 1.10 2004/12/13 00:25:22 lindak Exp $
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
@@ -52,8 +50,8 @@ typedef void *iconv_t;
static size_t(*my_iconv)(iconv_t, const char **, size_t *, char **, size_t *);
-u_char nls_lower[256];
-u_char nls_upper[256];
+uchar_t nls_lower[256];
+uchar_t nls_upper[256];
static iconv_t nls_toext, nls_toloc;
static int iconv_loaded;
@@ -71,13 +69,14 @@ nls_setlocale(const char *name)
nls_lower[i] = tolower(i);
nls_upper[i] = toupper(i);
}
- return 0;
+ return (0);
}
+/*ARGSUSED*/
int
nls_setrecode(const char *local, const char *external)
{
- return ENOENT;
+ return (ENOENT);
}
char *
@@ -87,15 +86,15 @@ nls_str_toloc(char *dst, const char *src)
size_t inlen, outlen;
if (!iconv_loaded)
- return strcpy(dst, src);
+ return (strcpy(dst, src));
if (nls_toloc == (iconv_t)0)
- return strcpy(dst, src);
+ return (strcpy(dst, src));
inlen = outlen = strlen(src);
my_iconv(nls_toloc, NULL, NULL, &p, &outlen);
my_iconv(nls_toloc, &src, &inlen, &p, &outlen);
*p = 0;
- return dst;
+ return (dst);
}
char *
@@ -105,15 +104,15 @@ nls_str_toext(char *dst, const char *src)
size_t inlen, outlen;
if (!iconv_loaded)
- return strcpy(dst, src);
+ return (strcpy(dst, src));
if (nls_toext == (iconv_t)0)
- return strcpy(dst, src);
+ return (strcpy(dst, src));
inlen = outlen = strlen(src);
my_iconv(nls_toext, NULL, NULL, &p, &outlen);
my_iconv(nls_toext, &src, &inlen, &p, &outlen);
*p = 0;
- return dst;
+ return (dst);
}
void *
@@ -124,17 +123,17 @@ nls_mem_toloc(void *dst, const void *src, int size)
size_t inlen, outlen;
if (!iconv_loaded)
- return memcpy(dst, src, size);
+ return (memcpy(dst, src, size));
if (size == 0)
- return NULL;
+ return (NULL);
if (nls_toloc == (iconv_t)0)
- return memcpy(dst, src, size);
+ return (memcpy(dst, src, size));
inlen = outlen = size;
my_iconv(nls_toloc, NULL, NULL, &p, &outlen);
my_iconv(nls_toloc, &s, &inlen, &p, &outlen);
- return dst;
+ return (dst);
}
void *
@@ -145,15 +144,15 @@ nls_mem_toext(void *dst, const void *src, int size)
size_t inlen, outlen;
if (size == 0)
- return NULL;
+ return (NULL);
if (!iconv_loaded || nls_toext == (iconv_t)0)
- return memcpy(dst, src, size);
+ return (memcpy(dst, src, size));
inlen = outlen = size;
my_iconv(nls_toext, NULL, NULL, &p, &outlen);
my_iconv(nls_toext, &s, &inlen, &p, &outlen);
- return dst;
+ return (dst);
}
char *
@@ -164,7 +163,7 @@ nls_str_upper(char *dst, const char *src)
while (*src)
*dst++ = toupper(*src++);
*dst = 0;
- return p;
+ return (p);
}
char *
@@ -175,5 +174,5 @@ nls_str_lower(char *dst, const char *src)
while (*src)
*dst++ = tolower(*src++);
*dst = 0;
- return p;
+ return (p);
}
diff --git a/usr/src/lib/libsmbfs/smb/ntlm.c b/usr/src/lib/libsmbfs/smb/ntlm.c
new file mode 100644
index 0000000000..8119e62b65
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/ntlm.c
@@ -0,0 +1,584 @@
+/*
+ * Copyright (c) 2000-2001, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: smb_crypt.c,v 1.13 2005/01/26 23:50:50 lindak Exp $
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * NTLM support functions
+ *
+ * Some code from the driver: smb_smb.c, smb_crypt.c
+ */
+
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/md4.h>
+#include <sys/md5.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <netsmb/smb_lib.h>
+
+#include "private.h"
+#include "charsets.h"
+#include "smb_crypt.h"
+#include "ntlm.h"
+
+
+/*
+ * ntlm_compute_lm_hash
+ *
+ * Compute an LM hash given a password
+ *
+ * Output:
+ * hash: 16-byte "LanMan" (LM) hash.
+ * Inputs:
+ * ucpw: User's password, upper-case UTF-8 string.
+ *
+ * Source: Implementing CIFS (Chris Hertel)
+ *
+ * P14 = UCPW padded to 14-bytes, or truncated (as needed)
+ * result = Encrypt(Key=P14, Data=MagicString)
+ */
+int
+ntlm_compute_lm_hash(uchar_t *hash, const char *pass)
+{
+ static const uchar_t M8[8] = "KGS!@#$%";
+ uchar_t P14[14 + 1];
+ int err;
+ char *ucpw;
+
+ /* First, convert the p/w to upper case. */
+ ucpw = utf8_str_toupper(pass);
+ if (ucpw == NULL)
+ return (ENOMEM);
+
+ /* Pad or truncate the upper-case P/W as needed. */
+ bzero(P14, sizeof (P14));
+ (void) strncpy((char *)P14, ucpw, 14);
+
+ /* Compute the hash. */
+ err = smb_encrypt_DES(hash, NTLM_HASH_SZ,
+ P14, 14, M8, 8);
+
+ free(ucpw);
+ return (err);
+}
+
+/*
+ * ntlm_compute_nt_hash
+ *
+ * Compute an NT hash given a password in UTF-8.
+ *
+ * Output:
+ * hash: 16-byte "NT" hash.
+ * Inputs:
+ * upw: User's password, mixed-case UCS-2LE.
+ * pwlen: Size (in bytes) of upw
+ */
+int
+ntlm_compute_nt_hash(uchar_t *hash, const char *pass)
+{
+ MD4_CTX ctx;
+ uint16_t *unipw = NULL;
+ int pwsz;
+
+ /* First, convert the password to unicode. */
+ unipw = convert_utf8_to_leunicode(pass);
+ if (unipw == NULL)
+ return (ENOMEM);
+ pwsz = unicode_strlen(unipw) << 1;
+
+ /* Compute the hash. */
+ MD4Init(&ctx);
+ MD4Update(&ctx, unipw, pwsz);
+ MD4Final(hash, &ctx);
+
+ free(unipw);
+ return (0);
+}
+
+/*
+ * ntlm_v1_response
+ *
+ * Create an LM response from the given LM hash and challenge,
+ * or an NTLM repsonse from a given NTLM hash and challenge.
+ * Both response types are 24 bytes (NTLM_V1_RESP_SZ)
+ */
+static int
+ntlm_v1_response(uchar_t *resp,
+ const uchar_t *hash,
+ const uchar_t *chal, int clen)
+{
+ uchar_t S21[21];
+ int err;
+
+ /*
+ * 14-byte LM Hash should be padded with 5 nul bytes to create
+ * a 21-byte string to be used in producing LM response
+ */
+ bzero(&S21, sizeof (S21));
+ bcopy(hash, S21, NTLM_HASH_SZ);
+
+ /* padded LM Hash -> LM Response */
+ err = smb_encrypt_DES(resp, NTLM_V1_RESP_SZ,
+ S21, 21, chal, clen);
+ return (err);
+}
+
+/*
+ * Calculate an NTLMv1 session key (16 bytes).
+ */
+static void
+ntlm_v1_session_key(uchar_t *ssn_key, const uchar_t *nt_hash)
+{
+ MD4_CTX md4;
+
+ MD4Init(&md4);
+ MD4Update(&md4, nt_hash, NTLM_HASH_SZ);
+ MD4Final(ssn_key, &md4);
+}
+
+/*
+ * Compute both the LM(v1) response and the NTLM(v1) response,
+ * and put them in the mbdata chains passed. This allocates
+ * mbuf chains in the output args, which the caller frees.
+ */
+int
+ntlm_put_v1_responses(struct smb_ctx *ctx,
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+{
+ uchar_t *lmresp, *ntresp;
+ int err;
+
+ /* Get mbuf chain for the LM response. */
+ if ((err = mb_init(lm_mbp, NTLM_V1_RESP_SZ)) != 0)
+ return (err);
+
+ /* Get mbuf chain for the NT response. */
+ if ((err = mb_init(nt_mbp, NTLM_V1_RESP_SZ)) != 0)
+ return (err);
+
+ /*
+ * Compute the LM response, derived
+ * from the challenge and the ASCII
+ * password (if authflags allow).
+ */
+ mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp);
+ bzero(lmresp, NTLM_V1_RESP_SZ);
+ if (ctx->ct_authflags & SMB_AT_LM1) {
+ /* They asked to send the LM hash too. */
+ err = ntlm_v1_response(lmresp, ctx->ct_lmhash,
+ ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
+ if (err)
+ return (err);
+ }
+
+ /*
+ * Compute the NTLM response, derived from
+ * the challenge and the NT hash.
+ */
+ mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp);
+ bzero(ntresp, NTLM_V1_RESP_SZ);
+ err = ntlm_v1_response(ntresp, ctx->ct_nthash,
+ ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
+
+ /*
+ * Compute the session key
+ */
+ ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash);
+
+ return (err);
+}
+
+/*
+ * A variation on HMAC-MD5 known as HMACT64 is used by Windows systems.
+ * The HMACT64() function is the same as the HMAC-MD5() except that
+ * it truncates the input key to 64 bytes rather than hashing it down
+ * to 16 bytes using the MD5() function.
+ *
+ * Output: digest (16-bytes)
+ */
+static void
+HMACT64(uchar_t *digest,
+ const uchar_t *key, size_t key_len,
+ const uchar_t *data, size_t data_len)
+{
+ MD5_CTX context;
+ uchar_t k_ipad[64]; /* inner padding - key XORd with ipad */
+ uchar_t k_opad[64]; /* outer padding - key XORd with opad */
+ int i;
+
+ /* if key is longer than 64 bytes use only the first 64 bytes */
+ if (key_len > 64)
+ key_len = 64;
+
+ /*
+ * The HMAC-MD5 (and HMACT64) transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, data))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and data is the data being protected.
+ */
+
+ /* start out by storing key in pads */
+ bzero(k_ipad, sizeof (k_ipad));
+ bzero(k_opad, sizeof (k_opad));
+ bcopy(key, k_ipad, key_len);
+ bcopy(key, k_opad, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i = 0; i < 64; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ /*
+ * perform inner MD5
+ */
+ MD5Init(&context); /* init context for 1st pass */
+ MD5Update(&context, k_ipad, 64); /* start with inner pad */
+ MD5Update(&context, data, data_len); /* then data of datagram */
+ MD5Final(digest, &context); /* finish up 1st pass */
+
+ /*
+ * perform outer MD5
+ */
+ MD5Init(&context); /* init context for 2nd pass */
+ MD5Update(&context, k_opad, 64); /* start with outer pad */
+ MD5Update(&context, digest, 16); /* then results of 1st hash */
+ MD5Final(digest, &context); /* finish up 2nd pass */
+}
+
+
+/*
+ * Compute an NTLMv2 hash given the NTLMv1 hash, the user name,
+ * and the destination (machine or domain name).
+ *
+ * Output:
+ * v2hash: 16-byte NTLMv2 hash.
+ * Inputs:
+ * v1hash: 16-byte NTLMv1 hash.
+ * user: User name, UPPER-case UTF-8 string.
+ * destination: Domain or server, MIXED-case UTF-8 string.
+ */
+static int
+ntlm_v2_hash(uchar_t *v2hash, const uchar_t *v1hash,
+ const char *user, const char *destination)
+{
+ int ulen, dlen;
+ size_t ucs2len;
+ uint16_t *ucs2data = NULL;
+ char *utf8data = NULL;
+ int err = ENOMEM;
+
+ /*
+ * v2hash = HMACT64(v1hash, 16, concat(upcase(user), dest))
+ * where "dest" is the domain or server name ("target name")
+ * Note: user name is converted to upper-case by the caller.
+ */
+
+ /* utf8data = concat(user, dest) */
+ ulen = strlen(user);
+ dlen = strlen(destination);
+ utf8data = malloc(ulen + dlen + 1);
+ if (utf8data == NULL)
+ goto out;
+ bcopy(user, utf8data, ulen);
+ bcopy(destination, utf8data + ulen, dlen + 1);
+
+ /* Convert to UCS-2LE */
+ ucs2data = convert_utf8_to_leunicode(utf8data);
+ if (ucs2data == NULL)
+ goto out;
+ ucs2len = 2 * unicode_strlen(ucs2data);
+
+ HMACT64(v2hash, v1hash, NTLM_HASH_SZ,
+ (uchar_t *)ucs2data, ucs2len);
+ err = 0;
+out:
+ if (ucs2data)
+ free(ucs2data);
+ if (utf8data)
+ free(utf8data);
+ return (err);
+}
+
+/*
+ * Compute a partial LMv2 or NTLMv2 response (first 16-bytes).
+ * The full response is composed by the caller by
+ * appending the client_data to the returned hash.
+ *
+ * Output:
+ * rhash: _partial_ LMv2/NTLMv2 response (first 16-bytes)
+ * Inputs:
+ * v2hash: 16-byte NTLMv2 hash.
+ * C8: Challenge from server (8 bytes)
+ * client_data: client nonce (for LMv2) or the
+ * "blob" from ntlm_build_target_info (NTLMv2)
+ */
+static int
+ntlm_v2_resp_hash(uchar_t *rhash,
+ const uchar_t *v2hash, const uchar_t *C8,
+ const uchar_t *client_data, size_t cdlen)
+{
+ size_t dlen;
+ uchar_t *data = NULL;
+
+ /* data = concat(C8, client_data) */
+ dlen = 8 + cdlen;
+ data = malloc(dlen);
+ if (data == NULL)
+ return (ENOMEM);
+ bcopy(C8, data, 8);
+ bcopy(client_data, data + 8, cdlen);
+
+ HMACT64(rhash, v2hash, NTLM_HASH_SZ, data, dlen);
+
+ free(data);
+ return (0);
+}
+
+/*
+ * Calculate an NTLMv2 session key (16 bytes).
+ */
+static void
+ntlm_v2_session_key(uchar_t *ssn_key,
+ const uchar_t *v2hash,
+ const uchar_t *ntresp)
+{
+
+ /* session key uses only 1st 16 bytes of ntresp */
+ HMACT64(ssn_key, v2hash, NTLM_HASH_SZ, ntresp, NTLM_HASH_SZ);
+}
+
+
+/*
+ * Compute both the LMv2 response and the NTLMv2 response,
+ * and put them in the mbdata chains passed. This allocates
+ * mbuf chains in the output args, which the caller frees.
+ * Also computes the session key.
+ */
+int
+ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+{
+ uchar_t *lmresp, *ntresp;
+ int err;
+ char *ucdom = NULL; /* user's domain */
+ char *ucuser = NULL; /* account name */
+ uchar_t v2hash[NTLM_HASH_SZ];
+ struct mbuf *tim = ti_mbp->mb_top;
+
+ if ((err = mb_init(lm_mbp, M_MINSIZE)) != 0)
+ return (err);
+ if ((err = mb_init(nt_mbp, M_MINSIZE)) != 0)
+ return (err);
+
+ /*
+ * Convert the user name to upper-case, as
+ * that's what's used when computing LMv2
+ * and NTLMv2 responses. Also the domain.
+ */
+ ucdom = utf8_str_toupper(ctx->ct_domain);
+ ucuser = utf8_str_toupper(ctx->ct_user);
+ if (ucdom == NULL || ucuser == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+
+ /*
+ * Compute the NTLMv2 hash (see above)
+ * Needs upper-case user, domain.
+ */
+ err = ntlm_v2_hash(v2hash, ctx->ct_nthash, ucuser, ucdom);
+ if (err)
+ goto out;
+
+ /*
+ * Compute the LMv2 response, derived from
+ * the v2hash, the server challenge, and
+ * the client nonce (random bits).
+ *
+ * We compose it from two parts:
+ * 1: 16-byte response hash
+ * 2: Client nonce
+ */
+ lmresp = (uchar_t *)lm_mbp->mb_pos;
+ mb_put_mem(lm_mbp, NULL, NTLM_HASH_SZ);
+ err = ntlm_v2_resp_hash(lmresp,
+ v2hash, ctx->ct_ntlm_chal,
+ ctx->ct_clnonce, NTLM_CHAL_SZ);
+ if (err)
+ goto out;
+ mb_put_mem(lm_mbp, ctx->ct_clnonce, NTLM_CHAL_SZ);
+
+ /*
+ * Compute the NTLMv2 response, derived
+ * from the server challenge and the
+ * "target info." blob passed in.
+ *
+ * Again composed from two parts:
+ * 1: 16-byte response hash
+ * 2: "target info." blob
+ */
+ ntresp = (uchar_t *)nt_mbp->mb_pos;
+ mb_put_mem(nt_mbp, NULL, NTLM_HASH_SZ);
+ err = ntlm_v2_resp_hash(ntresp,
+ v2hash, ctx->ct_ntlm_chal,
+ (uchar_t *)tim->m_data, tim->m_len);
+ if (err)
+ goto out;
+ mb_put_mem(nt_mbp, tim->m_data, tim->m_len);
+
+ /*
+ * Compute the session key
+ */
+ ntlm_v2_session_key(ctx->ct_ssn_key, v2hash, ntresp);
+
+out:
+ if (err) {
+ mb_done(lm_mbp);
+ mb_done(nt_mbp);
+ }
+ free(ucdom);
+ free(ucuser);
+
+ return (err);
+}
+
+/*
+ * Helper for ntlm_build_target_info below.
+ * Put a name in the NTLMv2 "target info." blob.
+ */
+static void
+smb_put_blob_name(struct mbdata *mbp, char *name, int type)
+{
+ uint16_t *ucs = NULL;
+ int nlen;
+
+ if (name)
+ ucs = convert_utf8_to_leunicode(name);
+ if (ucs)
+ nlen = unicode_strlen(ucs);
+ else
+ nlen = 0;
+
+ nlen <<= 1; /* length in bytes, without null. */
+
+ mb_put_uint16le(mbp, type);
+ mb_put_uint16le(mbp, nlen);
+ mb_put_mem(mbp, (char *)ucs, nlen);
+
+ if (ucs)
+ free(ucs);
+}
+
+/*
+ * Build an NTLMv2 "target info." blob. When called from NTLMSSP,
+ * the list of names comes from the Type 2 message. Otherwise,
+ * we create the name list here.
+ */
+int
+ntlm_build_target_info(struct smb_ctx *ctx, struct mbuf *names,
+ struct mbdata *mbp)
+{
+ struct timeval now;
+ uint64_t nt_time;
+
+ char *ucdom = NULL; /* user's domain */
+ int err;
+
+ /* Get mbuf chain for the "target info". */
+ if ((err = mb_init(mbp, M_MINSIZE)) != 0)
+ return (err);
+
+ /*
+ * Construct the client nonce by getting
+ * some random data from /dev/urandom
+ */
+ err = smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
+ if (err)
+ goto out;
+
+ /*
+ * Get the "NT time" for the target info header.
+ */
+ (void) gettimeofday(&now, 0);
+ smb_time_local2NT(&now, 0, &nt_time);
+
+ /*
+ * Build the "target info." block.
+ *
+ * Based on information at:
+ * http://davenport.sourceforge.net/ntlm.html#theNtlmv2Response
+ *
+ * First the fixed-size part.
+ */
+ mb_put_uint32le(mbp, 0x101); /* Blob signature */
+ mb_put_uint32le(mbp, 0); /* reserved */
+ mb_put_uint64le(mbp, nt_time); /* NT time stamp */
+ mb_put_mem(mbp, ctx->ct_clnonce, NTLM_CHAL_SZ);
+ mb_put_uint32le(mbp, 0); /* unknown */
+
+ /*
+ * Now put the list of names, either from the
+ * NTLMSSP Type 2 message or composed here.
+ */
+ if (names) {
+ err = mb_put_mem(mbp, names->m_data, names->m_len);
+ } else {
+ /* Get upper-case names. */
+ ucdom = utf8_str_toupper(ctx->ct_domain);
+ if (ucdom == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+ smb_put_blob_name(mbp, ucdom, NAMETYPE_DOMAIN_NB);
+ smb_put_blob_name(mbp, NULL, NAMETYPE_EOL);
+ /* OK, that's the whole "target info." blob! */
+ }
+ err = 0;
+
+out:
+ free(ucdom);
+ return (err);
+}
diff --git a/usr/src/lib/libsmbfs/smb/ntlm.h b/usr/src/lib/libsmbfs/smb/ntlm.h
new file mode 100644
index 0000000000..e8eae559e9
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/ntlm.h
@@ -0,0 +1,65 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NTLM_H
+#define _NTLM_H
+
+/*
+ * NTLM support functions
+ * See ntlm.c
+ */
+
+/*
+ * Size of all LM/NTLM hashes, challenge
+ * NTLM_HASH_SZ: 16 bytes (see smb_lib.h)
+ * NTLM_CHAL_SZ: 8 bytes (see smb_lib.h)
+ */
+#define NTLM_V1_RESP_SZ 24 /* response size */
+
+#define NAMETYPE_EOL 0x0000 /* end of list of names */
+#define NAMETYPE_MACHINE_NB 0x0001 /* NetBIOS machine name */
+#define NAMETYPE_DOMAIN_NB 0x0002 /* NetBIOS domain name */
+#define NAMETYPE_MACHINE_DNS 0x0003 /* DNS machine name */
+#define NAMETYPE_DOMAIN_DNS 0x0004 /* DNS (AD) domain name */
+
+int
+ntlm_compute_lm_hash(uchar_t *hash, const char *pw);
+
+int
+ntlm_compute_nt_hash(uchar_t *hash, const char *pw);
+
+int
+ntlm_build_target_info(struct smb_ctx *, struct mbuf *, struct mbdata *);
+
+int
+ntlm_put_v1_responses(struct smb_ctx *ctx,
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+
+int
+ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+
+#endif /* _NTLM_H */
diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.c b/usr/src/lib/libsmbfs/smb/ntlmssp.c
new file mode 100644
index 0000000000..3428fbca36
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/ntlmssp.c
@@ -0,0 +1,634 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * NT Lan Manager Security Support Provider (NTLMSSP)
+ *
+ * Based on information from the "Davenport NTLM" page:
+ * http://davenport.sourceforge.net/ntlm.html
+ */
+
+
+#include <errno.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/mchain.h>
+
+#include "private.h"
+#include "charsets.h"
+#include "spnego.h"
+#include "derparse.h"
+#include "ssp.h"
+#include "ntlm.h"
+#include "ntlmssp.h"
+
+typedef struct ntlmssp_state {
+ uint32_t ss_flags;
+ char *ss_target_name;
+ struct mbuf *ss_target_info;
+} ntlmssp_state_t;
+
+/*
+ * So called "security buffer".
+ * A lot like an RPC string.
+ */
+struct sec_buf {
+ uint16_t sb_length;
+ uint16_t sb_maxlen;
+ uint32_t sb_offset;
+};
+#define ID_SZ 8
+static const char ntlmssp_id[ID_SZ] = "NTLMSSP";
+
+/*
+ * Get a "security buffer" (header part)
+ */
+static int
+mb_get_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
+{
+ int err;
+
+ (void) mb_get_uint16le(mbp, &sb->sb_length);
+ (void) mb_get_uint16le(mbp, &sb->sb_maxlen);
+ err = mb_get_uint32le(mbp, &sb->sb_offset);
+
+ return (err);
+}
+
+/*
+ * Get a "security buffer" (data part), where
+ * the data is delivered as an mbuf.
+ */
+static int
+mb_get_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf **mp)
+{
+ struct mbdata tmp_mb;
+ int err;
+
+ /*
+ * Setup tmp_mb to point to the start of the header.
+ * This is a dup ref - do NOT free it.
+ */
+ mb_initm(&tmp_mb, mbp->mb_top);
+
+ /* Skip data up to the offset. */
+ err = mb_get_mem(&tmp_mb, NULL, sb->sb_offset);
+ if (err)
+ return (err);
+
+ /* Get the data (as an mbuf). */
+ err = mb_get_mbuf(&tmp_mb, sb->sb_maxlen, mp);
+
+ return (err);
+}
+
+/*
+ * Put a "security buffer" (header part)
+ */
+static int
+mb_put_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
+{
+ int err;
+
+ (void) mb_put_uint16le(mbp, sb->sb_length);
+ (void) mb_put_uint16le(mbp, sb->sb_maxlen);
+ err = mb_put_uint32le(mbp, sb->sb_offset);
+
+ return (err);
+}
+
+/*
+ * Put a "security buffer" (data part), where
+ * the data is an mbuf. Note: consumes m.
+ */
+static int
+mb_put_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf *m)
+{
+ int cnt0, err;
+
+ sb->sb_offset = cnt0 = mbp->mb_count;
+ err = mb_put_mbuf(mbp, m);
+ sb->sb_maxlen = sb->sb_length = mbp->mb_count - cnt0;
+
+ return (err);
+}
+
+/*
+ * Put a "security buffer" (data part), where
+ * the data is a string (OEM or unicode).
+ *
+ * The string is NOT null terminated.
+ */
+static int
+mb_put_sb_string(struct mbdata *mbp, struct sec_buf *sb,
+ const char *s, int unicode)
+{
+ int err, trim;
+ struct mbdata tmp_mb;
+
+ /*
+ * Put the string into a temp. mbuf,
+ * then chop off the null terminator
+ * before appending to caller's mbp.
+ */
+ err = mb_init(&tmp_mb, M_MINSIZE);
+ if (err)
+ return (err);
+ err = mb_put_dstring(&tmp_mb, s, unicode);
+ if (err)
+ return (err);
+
+ trim = (unicode) ? 2 : 1;
+ if (tmp_mb.mb_cur->m_len < trim)
+ return (EFAULT);
+ tmp_mb.mb_cur->m_len -= trim;
+
+ err = mb_put_sb_data(mbp, sb, tmp_mb.mb_top);
+ /*
+ * Note: tmp_mb.mb_top is consumed,
+ * so do NOT free it (no mb_done)
+ */
+ return (err);
+}
+
+/*
+ * Build a Type 1 message
+ *
+ * This message has a header section containing offsets to
+ * data later in the message. We use the common trick of
+ * building it in two parts and then concatenatening.
+ */
+int
+ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
+{
+ struct type1hdr {
+ char h_id[ID_SZ];
+ uint32_t h_type;
+ uint32_t h_flags;
+ struct sec_buf h_cldom;
+ struct sec_buf h_wksta;
+ } hdr;
+ struct mbdata mb2; /* 2nd part */
+ int err;
+ struct smb_ctx *ctx = sp->smb_ctx;
+ ntlmssp_state_t *ssp_st = sp->sp_private;
+ char *ucdom = NULL;
+ char *ucwks = NULL;
+
+ if ((err = mb_init(&mb2, M_MINSIZE)) != 0)
+ return (err);
+ mb2.mb_count = sizeof (hdr);
+
+ /*
+ * Initialize the negotiation flags, and
+ * save what we sent. For reference:
+ * [MS-NLMP] spec. (also ntlmssp.h)
+ */
+ ssp_st->ss_flags =
+ NTLMSSP_REQUEST_TARGET |
+ NTLMSSP_NEGOTIATE_NTLM |
+ NTLMSSP_NEGOTIATE_TARGET_INFO |
+ NTLMSSP_NEGOTIATE_128 |
+ NTLMSSP_NEGOTIATE_56;
+
+ if (ctx->ct_hflags2 & SMB_FLAGS2_UNICODE)
+ ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+ else
+ ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_OEM;
+
+ if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
+ ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
+ ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
+ }
+
+ bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
+ hdr.h_type = 1; /* Type 1 */
+ hdr.h_flags = ssp_st->ss_flags;
+
+ /*
+ * Put the client domain, client name strings.
+ * These are always in OEM format, upper-case.
+ */
+ ucdom = utf8_str_toupper(ctx->ct_domain);
+ ucwks = utf8_str_toupper(ctx->ct_locname);
+ if (ucdom == NULL || ucwks == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+ err = mb_put_sb_string(&mb2, &hdr.h_cldom, ucdom, 0);
+ if (err)
+ goto out;
+ err = mb_put_sb_string(&mb2, &hdr.h_wksta, ucwks, 0);
+ if (err)
+ goto out;
+
+ /*
+ * Marshal the header (in LE order)
+ * then concatenate the 2nd part.
+ */
+ (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ);
+ (void) mb_put_uint32le(out_mb, hdr.h_type);
+ (void) mb_put_uint32le(out_mb, hdr.h_flags);
+ (void) mb_put_sb_hdr(out_mb, &hdr.h_cldom);
+ (void) mb_put_sb_hdr(out_mb, &hdr.h_wksta);
+
+ err = mb_put_mbuf(out_mb, mb2.mb_top);
+
+out:
+ free(ucdom);
+ free(ucwks);
+
+ return (err);
+}
+
+/*
+ * Parse a Type 2 message
+ */
+int
+ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb)
+{
+ struct type2hdr {
+ char h_id[ID_SZ];
+ uint32_t h_type;
+ struct sec_buf h_target_name;
+ uint32_t h_flags;
+ uint8_t h_challenge[8];
+ uint32_t h_context[2]; /* optional */
+ struct sec_buf h_target_info; /* optional */
+ } hdr;
+ struct mbdata top_mb, tmp_mb;
+ struct mbuf *m;
+ int err, uc;
+ int min_hdr_sz = offsetof(struct type2hdr, h_context);
+ struct smb_ctx *ctx = sp->smb_ctx;
+ ntlmssp_state_t *ssp_st = sp->sp_private;
+ char *buf = NULL;
+
+ if (m_totlen(in_mb->mb_top) < min_hdr_sz) {
+ err = EBADRPC;
+ goto out;
+ }
+
+ /*
+ * Save the mbdata pointers before we consume anything.
+ * Careful to NOT free this (would be dup. free)
+ * We use this below to find data based on offsets
+ * from the start of the header.
+ */
+ top_mb = *in_mb;
+
+ /* Parse the fixed size header stuff. */
+ bzero(&hdr, sizeof (hdr));
+ (void) mb_get_mem(in_mb, &hdr.h_id, ID_SZ);
+ (void) mb_get_uint32le(in_mb, &hdr.h_type);
+ if (hdr.h_type != 2) {
+ err = EPROTO;
+ goto out;
+ }
+ (void) mb_get_sb_hdr(in_mb, &hdr.h_target_name);
+ (void) mb_get_uint32le(in_mb, &hdr.h_flags);
+ (void) mb_get_mem(in_mb, &hdr.h_challenge, NTLM_CHAL_SZ);
+
+ /*
+ * Save flags, challenge for later.
+ */
+ ssp_st->ss_flags = hdr.h_flags;
+ uc = hdr.h_flags & NTLMSSP_NEGOTIATE_UNICODE;
+ bcopy(&hdr.h_challenge, ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
+
+ /*
+ * Now find out if the optional parts are there.
+ */
+ if ((m_totlen(top_mb.mb_top) > sizeof (hdr)) &&
+ (hdr.h_target_name.sb_offset >= sizeof (hdr))) {
+ (void) mb_get_uint32le(in_mb, &hdr.h_context[0]);
+ (void) mb_get_uint32le(in_mb, &hdr.h_context[1]);
+ (void) mb_get_sb_hdr(in_mb, &hdr.h_target_info);
+ }
+
+ /*
+ * Get the target name string. First get a copy of
+ * the data from the offset/length indicated in the
+ * security buffer header; then parse the string.
+ */
+ err = mb_get_sb_data(&top_mb, &hdr.h_target_name, &m);
+ if (err)
+ goto out;
+ mb_initm(&tmp_mb, m);
+ err = mb_get_string(&tmp_mb, &ssp_st->ss_target_name, uc);
+ mb_done(&tmp_mb);
+
+ /*
+ * Get the target info blob, if present.
+ */
+ if (hdr.h_target_info.sb_offset >= sizeof (hdr)) {
+ err = mb_get_sb_data(&top_mb, &hdr.h_target_info,
+ &ssp_st->ss_target_info);
+ }
+
+out:
+ if (buf != NULL)
+ free(buf);
+
+ return (err);
+}
+
+/*
+ * Build a Type 3 message
+ *
+ * This message has a header section containing offsets to
+ * data later in the message. We use the common trick of
+ * building it in two parts and then concatenatening.
+ */
+int
+ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
+{
+ struct type3hdr {
+ char h_id[ID_SZ];
+ uint32_t h_type;
+ struct sec_buf h_lm_resp;
+ struct sec_buf h_nt_resp;
+ struct sec_buf h_domain;
+ struct sec_buf h_user;
+ struct sec_buf h_wksta;
+ } hdr;
+ struct mbdata lm_mbc, nt_mbc, ti_mbc;
+ struct mbdata mb2; /* 2nd part */
+ int err, uc;
+ char *ucdom = NULL; /* user's domain */
+ char *ucuser = NULL; /* user name */
+ char *ucwksta = NULL; /* workstation */
+ struct smb_ctx *ctx = sp->smb_ctx;
+ ntlmssp_state_t *ssp_st = sp->sp_private;
+
+ bzero(&lm_mbc, sizeof (lm_mbc));
+ bzero(&nt_mbc, sizeof (nt_mbc));
+ bzero(&ti_mbc, sizeof (ti_mbc));
+ bzero(&mb2, sizeof (mb2));
+
+ /*
+ * Convert the user name to upper-case, as that's what's
+ * used when computing LMv2 and NTLMv2 responses. Also
+ * domain, workstation
+ */
+ ucdom = utf8_str_toupper(ctx->ct_domain);
+ ucuser = utf8_str_toupper(ctx->ct_user);
+ ucwksta = utf8_str_toupper(ctx->ct_locname);
+ if (ucdom == NULL || ucuser == NULL || ucwksta == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+
+ if ((err = mb_init(&mb2, M_MINSIZE)) != 0)
+ goto out;
+ mb2.mb_count = sizeof (hdr);
+ uc = ssp_st->ss_flags & NTLMSSP_NEGOTIATE_UNICODE;
+
+ bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
+ hdr.h_type = 3; /* Type 3 */
+
+ /*
+ * Put the LMv2,NTLMv2 responses, or
+ * possibly LM, NTLM (v1) responses.
+ */
+ if (ctx->ct_authflags & SMB_AT_NTLM2) {
+ /* Build the NTLMv2 "target info" blob. */
+ err = ntlm_build_target_info(ctx,
+ ssp_st->ss_target_info, &ti_mbc);
+ if (err)
+ goto out;
+ err = ntlm_put_v2_responses(ctx, &ti_mbc,
+ &lm_mbc, &nt_mbc);
+ } else {
+ err = ntlm_put_v1_responses(ctx,
+ &lm_mbc, &nt_mbc);
+ }
+ if (err)
+ goto out;
+
+ err = mb_put_sb_data(&mb2, &hdr.h_lm_resp, lm_mbc.mb_top);
+ lm_mbc.mb_top = NULL; /* consumed */
+ if (err)
+ goto out;
+ err = mb_put_sb_data(&mb2, &hdr.h_nt_resp, nt_mbc.mb_top);
+ nt_mbc.mb_top = NULL; /* consumed */
+ if (err)
+ goto out;
+
+ /*
+ * Put the "target" (domain), user, workstation
+ */
+ err = mb_put_sb_string(&mb2, &hdr.h_domain, ucdom, uc);
+ if (err)
+ goto out;
+ err = mb_put_sb_string(&mb2, &hdr.h_user, ucuser, uc);
+ if (err)
+ goto out;
+ err = mb_put_sb_string(&mb2, &hdr.h_wksta, ucwksta, uc);
+ if (err)
+ goto out;
+
+ /*
+ * Marshal the header (in LE order)
+ * then concatenate the 2nd part.
+ */
+ (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ);
+ (void) mb_put_uint32le(out_mb, hdr.h_type);
+
+ (void) mb_put_sb_hdr(out_mb, &hdr.h_lm_resp);
+ (void) mb_put_sb_hdr(out_mb, &hdr.h_nt_resp);
+
+ (void) mb_put_sb_hdr(out_mb, &hdr.h_domain);
+ (void) mb_put_sb_hdr(out_mb, &hdr.h_user);
+ (void) mb_put_sb_hdr(out_mb, &hdr.h_wksta);
+
+ err = mb_put_mbuf(out_mb, mb2.mb_top);
+ mb2.mb_top = NULL; /* consumed */
+
+out:
+ free(ucdom);
+ free(ucuser);
+ free(ucwksta);
+
+ mb_done(&mb2);
+ mb_done(&lm_mbc);
+ mb_done(&nt_mbc);
+
+ return (err);
+}
+
+/*
+ * ntlmssp_final
+ *
+ * Called after successful authentication.
+ * Setup the MAC key for signing.
+ */
+int
+ntlmssp_final(struct ssp_ctx *sp)
+{
+ struct smb_ctx *ctx = sp->smb_ctx;
+ int err = 0;
+
+ /*
+ * MAC_key is just the session key, but
+ * Only on the first successful auth.
+ */
+ if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
+ (ctx->ct_mackey == NULL)) {
+ ctx->ct_mackeylen = NTLM_HASH_SZ;
+ ctx->ct_mackey = malloc(ctx->ct_mackeylen);
+ if (ctx->ct_mackey == NULL) {
+ ctx->ct_mackeylen = 0;
+ err = ENOMEM;
+ goto out;
+ }
+ memcpy(ctx->ct_mackey, ctx->ct_ssn_key, NTLM_HASH_SZ);
+ /*
+ * Apparently, the server used seq. no. zero
+ * for our previous message, so next is two.
+ */
+ ctx->ct_mac_seqno = 2;
+ }
+
+out:
+ return (err);
+}
+
+/*
+ * ntlmssp_next_token
+ *
+ * See ssp.c: ssp_ctx_next_token
+ */
+int
+ntlmssp_next_token(struct ssp_ctx *sp, struct mbdata *in_mb,
+ struct mbdata *out_mb)
+{
+ int err;
+
+ if (out_mb == NULL) {
+ /* final call on successful auth. */
+ err = ntlmssp_final(sp);
+ goto out;
+ }
+
+ /* Will build an ouptut token. */
+ err = mb_init(out_mb, M_MINSIZE);
+ if (err)
+ goto out;
+
+ /*
+ * When called with in_mb == NULL, it means
+ * this is the first call for this session,
+ * so put a Type 1 (initialize) token.
+ */
+ if (in_mb == NULL) {
+ err = ntlmssp_put_type1(sp, out_mb);
+ goto out;
+ }
+
+ /*
+ * This is not the first call, so
+ * parse the response token we received.
+ * It should be a Type 2 (challenge).
+ * Then put a Type 3 (authenticate)
+ */
+ err = ntlmssp_get_type2(sp, in_mb);
+ if (err)
+ goto out;
+
+ err = ntlmssp_put_type3(sp, out_mb);
+
+out:
+ if (err)
+ DPRINT("ret: %d", err);
+ return (err);
+}
+
+/*
+ * ntlmssp_ctx_destroy
+ *
+ * Destroy mechanism-specific data.
+ */
+void
+ntlmssp_destroy(struct ssp_ctx *sp)
+{
+ ntlmssp_state_t *ssp_st;
+
+ ssp_st = sp->sp_private;
+ if (ssp_st != NULL) {
+ sp->sp_private = NULL;
+ free(ssp_st->ss_target_name);
+ m_freem(ssp_st->ss_target_info);
+ free(ssp_st);
+ }
+}
+
+/*
+ * ntlmssp_init_clnt
+ *
+ * Initialize a new NTLMSSP client context.
+ */
+int
+ntlmssp_init_client(struct ssp_ctx *sp)
+{
+ ntlmssp_state_t *ssp_st;
+
+ if ((sp->smb_ctx->ct_authflags &
+ (SMB_AT_NTLM2 | SMB_AT_NTLM1)) == 0) {
+ DPRINT("No NTLM authflags");
+ return (ENOTSUP);
+ }
+
+ ssp_st = calloc(1, sizeof (*ssp_st));
+ if (ssp_st == NULL)
+ return (ENOMEM);
+
+ sp->sp_nexttok = ntlmssp_next_token;
+ sp->sp_destroy = ntlmssp_destroy;
+ sp->sp_private = ssp_st;
+
+ return (0);
+}
diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.h b/usr/src/lib/libsmbfs/smb/ntlmssp.h
new file mode 100644
index 0000000000..591b1ab088
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/ntlmssp.h
@@ -0,0 +1,76 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NTLMSSP_H
+#define _NTLMSSP_H
+
+/*
+ * NT LanMan Security Support Package (NTLMSSP)
+ * Negotiation flags, etc.
+ *
+ * Reference: [MS-NLMP] NT LAN Manager (NTLM)
+ * Authentication Protocol Specification
+ * http://msdn.microsoft.com/en-us/library/cc236621(PROT.10).aspx
+ */
+
+/*
+ * NTLMSSP Negotiate Flags
+ * [MS-NLMP] sec. 2.2.2.5
+ */
+#define NTLMSSP_NEGOTIATE_UNICODE 0x00000001
+#define NTLMSSP_NEGOTIATE_OEM 0x00000002
+#define NTLMSSP_REQUEST_TARGET 0x00000004
+/* reserved 0x00000008 */
+#define NTLMSSP_NEGOTIATE_SIGN 0x00000010
+#define NTLMSSP_NEGOTIATE_SEAL 0x00000020
+#define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040
+#define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080
+/* reserved 0x00000100 */
+#define NTLMSSP_NEGOTIATE_NTLM 0x00000200
+#define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400
+/* old anonymous_session (ignored by servers) 0x00000800 */
+#define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000
+#define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000
+/* reserved 0x00004000 */
+#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000
+#define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000
+#define NTLMSSP_TARGET_TYPE_SERVER 0x00020000
+#define NTLMSSP_TARGET_TYPE_SHARE 0x00040000
+#define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000
+#define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000
+/* reserved 0x00200000 */
+#define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000
+#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000
+/* reserved 0x01000000 */
+#define NTLMSSP_NEGOTIATE_VERSION 0x02000000
+/* reserved 0x04000000 */
+/* reserved 0x08000000 */
+/* reserved 0x10000000 */
+#define NTLMSSP_NEGOTIATE_128 0x20000000
+#define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000
+#define NTLMSSP_NEGOTIATE_56 0x80000000
+
+#endif /* _NTLMSSP_H */
diff --git a/usr/src/lib/libsmbfs/smb/print.c b/usr/src/lib/libsmbfs/smb/print.c
index e0b18e8c40..263cafaa93 100644
--- a/usr/src/lib/libsmbfs/smb/print.c
+++ b/usr/src/lib/libsmbfs/smb/print.c
@@ -46,50 +46,77 @@
#include <grp.h>
#include <unistd.h>
+#include <netsmb/smb.h>
#include <netsmb/smb_lib.h>
-#include <cflib.h>
#include "private.h"
int
-smb_smb_open_print_file(struct smb_ctx *ctx, int setuplen, int mode,
- const char *ident, smbfh *fhp)
+smb_printer_open(struct smb_ctx *ctx, int setuplen, int mode,
+ const char *ident, int *fhp)
{
struct smb_rq *rqp;
struct mbdata *mbp;
- int error;
+ int error, flags2, uc;
+ uint16_t fh;
+ uint8_t wc;
+
+ flags2 = smb_ctx_flags2(ctx);
+ if (flags2 == -1)
+ return (EIO);
+ uc = flags2 & SMB_FLAGS2_UNICODE;
- error = smb_rq_init(ctx, SMB_COM_OPEN_PRINT_FILE, 2, &rqp);
+ error = smb_rq_init(ctx, SMB_COM_OPEN_PRINT_FILE, &rqp);
if (error)
return (error);
mbp = smb_rq_getrequest(rqp);
+ smb_rq_wstart(rqp);
mb_put_uint16le(mbp, setuplen);
mb_put_uint16le(mbp, mode);
smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
mb_put_uint8(mbp, SMB_DT_ASCII);
- smb_rq_dstring(mbp, ident);
+ mb_put_dstring(mbp, ident, uc);
+ smb_rq_bend(rqp);
error = smb_rq_simple(rqp);
- if (!error) {
- mbp = smb_rq_getreply(rqp);
- mb_get_uint16(mbp, fhp);
+ if (error)
+ goto out;
+
+ mbp = smb_rq_getreply(rqp);
+ error = mb_get_uint8(mbp, &wc);
+ if (error || wc < 1) {
+ error = EBADRPC;
+ goto out;
}
+ mb_get_uint16(mbp, &fh);
+ *fhp = fh;
+ error = 0;
+
+out:
smb_rq_done(rqp);
return (error);
}
+/*
+ * Similar to smb_fh_close
+ */
int
-smb_smb_close_print_file(struct smb_ctx *ctx, smbfh fh)
+smb_printer_close(struct smb_ctx *ctx, int fh)
{
struct smb_rq *rqp;
struct mbdata *mbp;
int error;
- error = smb_rq_init(ctx, SMB_COM_CLOSE_PRINT_FILE, 0, &rqp);
+ error = smb_rq_init(ctx, SMB_COM_CLOSE_PRINT_FILE, &rqp);
if (error)
return (error);
mbp = smb_rq_getrequest(rqp);
- mb_put_mem(mbp, (char *)&fh, 2);
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, (uint16_t)fh);
smb_rq_wend(rqp);
+ mb_put_uint16le(mbp, 0); /* byte count */
+
error = smb_rq_simple(rqp);
smb_rq_done(rqp);
+
return (error);
}
diff --git a/usr/src/lib/libsmbfs/smb/private.h b/usr/src/lib/libsmbfs/smb/private.h
index 6630ed160a..b95ec1f7f4 100644
--- a/usr/src/lib/libsmbfs/smb/private.h
+++ b/usr/src/lib/libsmbfs/smb/private.h
@@ -31,7 +31,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -44,6 +44,33 @@
*/
#include <inttypes.h>
+#include <sys/byteorder.h>
+#include <sys/ccompile.h>
+
+#include <netsmb/netbios.h>
+
+extern void dprint(const char *, const char *, ...)
+ __PRINTFLIKE(2);
+
+#if defined(DEBUG) || defined(__lint)
+#define DPRINT(...) dprint(__func__, __VA_ARGS__)
+#else
+#define DPRINT(...) ((void)0)
+#endif
+
+/*
+ * Flags bits in ct_vcflags (copied from smb_conn.h)
+ * Pass these to the driver?
+ */
+#define SMBV_RECONNECTING 0x0002 /* conn in process of reconnection */
+#define SMBV_LONGNAMES 0x0004 /* conn configured to use long names */
+#define SMBV_ENCRYPT 0x0008 /* server demands encrypted password */
+#define SMBV_WIN95 0x0010 /* used to apply bugfixes for this OS */
+#define SMBV_NT4 0x0020 /* used when NT4 issues invalid resp */
+#define SMBV_UNICODE 0x0040 /* conn configured to use Unicode */
+#define SMBV_EXT_SEC 0x0080 /* conn to use extended security */
+#define SMBV_WILL_SIGN 0x0100 /* negotiated signing */
+
/*
* BSD-style mbuf simulation
@@ -56,7 +83,6 @@ struct mbuf {
};
typedef struct mbuf mbuf_t;
-#if 0 /* in smb_lib.h */
struct mbdata {
struct mbuf *mb_top;
struct mbuf *mb_cur;
@@ -64,12 +90,16 @@ struct mbdata {
int mb_count;
};
typedef struct mbdata mbdata_t;
-#endif
+/*
+ * Note: Leaving a little space (8 bytes) between the
+ * mbuf header and the start of the data so we can
+ * prepend a NetBIOS header in that space.
+ */
#define M_ALIGNFACTOR (sizeof (long))
#define M_ALIGN(len) (((len) + M_ALIGNFACTOR - 1) & ~(M_ALIGNFACTOR - 1))
-#define M_BASESIZE (sizeof (struct mbuf))
-#define M_MINSIZE (256 - M_BASESIZE)
+#define M_BASESIZE (sizeof (struct mbuf) + 8)
+#define M_MINSIZE (1024 - M_BASESIZE)
#define M_TOP(m) ((char *)(m) + M_BASESIZE)
#define M_TRAILINGSPACE(m) ((m)->m_maxlen - (m)->m_len)
#define mtod(m, t) ((t)(m)->m_data)
@@ -78,32 +108,51 @@ typedef struct mbdata mbdata_t;
* request handling structures
*/
struct smb_rq {
- uchar_t rq_cmd;
+ struct smb_ctx *rq_ctx;
struct mbdata rq_rq;
struct mbdata rq_rp;
- struct smb_ctx *rq_ctx;
- int rq_wcount;
- int rq_bcount;
+ int rq_rpbufsz;
+ uint8_t rq_cmd;
+ uint8_t rq_hflags;
+ uint16_t rq_hflags2;
+ uint32_t rq_status;
+ uint16_t rq_uid;
+ uint16_t rq_tid;
+ uint16_t rq_mid;
+ uint32_t rq_seqno;
+ /* See rq_[bw]{start,end} functions */
+ char *rq_wcntp;
+ int rq_wcbase;
+ char *rq_bcntp;
+ int rq_bcbase;
};
typedef struct smb_rq smb_rq_t;
#define smb_rq_getrequest(rqp) (&(rqp)->rq_rq)
#define smb_rq_getreply(rqp) (&(rqp)->rq_rp)
-int smb_rq_init(struct smb_ctx *, uchar_t, size_t, struct smb_rq **);
+int smb_rq_init(struct smb_ctx *, uchar_t, struct smb_rq **);
void smb_rq_done(struct smb_rq *);
+void smb_rq_bstart(struct smb_rq *);
+void smb_rq_bend(struct smb_rq *);
+void smb_rq_wstart(struct smb_rq *);
void smb_rq_wend(struct smb_rq *);
int smb_rq_simple(struct smb_rq *);
int smb_rq_dmem(struct mbdata *, const char *, size_t);
-int smb_rq_dstring(struct mbdata *, const char *);
+int smb_rq_internal(struct smb_ctx *, struct smb_rq *);
+int smb_rq_sign(struct smb_rq *);
+int smb_rq_verify(struct smb_rq *);
/*
* Message compose/parse
*/
+void m_freem(struct mbuf *);
int m_getm(struct mbuf *, size_t, struct mbuf **);
int m_lineup(struct mbuf *, struct mbuf **);
+size_t m_totlen(struct mbuf *);
+
int mb_init(struct mbdata *, size_t);
int mb_initm(struct mbdata *, struct mbuf *);
int mb_done(struct mbdata *);
@@ -115,9 +164,11 @@ int mb_put_uint32be(struct mbdata *, uint32_t);
int mb_put_uint32le(struct mbdata *, uint32_t);
int mb_put_uint64be(struct mbdata *, uint64_t);
int mb_put_uint64le(struct mbdata *, uint64_t);
-int mb_put_mem(struct mbdata *, const char *, size_t);
-int mb_put_pstring(struct mbdata *mbp, const char *s);
+int mb_put_mem(struct mbdata *, const void *, size_t);
int mb_put_mbuf(struct mbdata *, struct mbuf *);
+int mb_put_astring(struct mbdata *mbp, const char *s);
+int mb_put_dstring(struct mbdata *mbp, const char *s, int);
+int mb_put_ustring(struct mbdata *mbp, const char *s);
int mb_get_uint8(struct mbdata *, uint8_t *);
int mb_get_uint16(struct mbdata *, uint16_t *);
@@ -129,26 +180,82 @@ int mb_get_uint32le(struct mbdata *, uint32_t *);
int mb_get_uint64(struct mbdata *, uint64_t *);
int mb_get_uint64be(struct mbdata *, uint64_t *);
int mb_get_uint64le(struct mbdata *, uint64_t *);
-int mb_get_mem(struct mbdata *, char *, size_t);
+int mb_get_mem(struct mbdata *, void *, size_t);
+int mb_get_mbuf(struct mbdata *, int, struct mbuf **);
+int mb_get_string(struct mbdata *, char **, int);
+int mb_get_astring(struct mbdata *, char **);
+int mb_get_ustring(struct mbdata *, char **);
+
/*
* Network stuff (NetBIOS and otherwise)
*/
+struct nb_name;
+struct sockaddr_nb;
+
+extern int smb_recv_timeout; /* seconds */
+
+void dump_ctx(char *, struct smb_ctx *);
+void dump_addrinfo(struct addrinfo *);
+void dump_sockaddr(struct sockaddr *);
+int nb_ssn_request(struct smb_ctx *, char *);
int nb_name_len(struct nb_name *);
-/* new flag UCflag. 1=uppercase,0=don't */
-int nb_name_encode(struct nb_name *, uchar_t *);
+int nb_name_encode(struct mbdata *, struct nb_name *);
int nb_encname_len(const uchar_t *);
-int nb_snballoc(int namelen, struct sockaddr_nb **);
+int nb_snballoc(struct sockaddr_nb **);
void nb_snbfree(struct sockaddr *);
int nb_sockaddr(struct sockaddr *, struct nb_name *, struct sockaddr_nb **);
+int nbns_getaddrinfo(const char *name, struct nb_ctx *nbc,
+ struct addrinfo **res);
int nbns_resolvename(const char *, struct nb_ctx *, struct sockaddr **);
-int nbns_getnodestatus(struct sockaddr *targethost,
- struct nb_ctx *ctx, char *system, char *workgroup);
-int nb_getlocalname(char *name, size_t maxlen);
+int get_xti_err(int);
+
+
+/*
+ * Private SMB stuff
+ */
+
+struct smb_bitname {
+ uint_t bn_bit;
+ char *bn_name;
+};
+typedef struct smb_bitname smb_bitname_t;
+char *smb_printb(char *, int, const struct smb_bitname *);
+
+int smb_ctx_getaddr(struct smb_ctx *ctx);
+int smb_ctx_gethandle(struct smb_ctx *ctx);
+
+int smb_ssn_send(struct smb_ctx *, struct mbdata *);
+int smb_ssn_recv(struct smb_ctx *, struct mbdata *);
+
+int smb_negprot(struct smb_ctx *, struct mbdata *);
+
+int smb_ssnsetup_null(struct smb_ctx *);
+int smb_ssnsetup_ntlm1(struct smb_ctx *);
+int smb_ssnsetup_ntlm2(struct smb_ctx *);
+int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);
+
+void smb_time_local2server(struct timeval *, int, long *);
+void smb_time_server2local(ulong_t, int, struct timeval *);
+void smb_time_NT2local(uint64_t, int, struct timeval *);
+void smb_time_local2NT(struct timeval *, int, uint64_t *);
+
+int smb_getlocalname(char **);
+int smb_get_authentication(struct smb_ctx *);
+int smb_get_keychain(struct smb_ctx *ctx);
+void smb_hexdump(const void *buf, int len);
+
+/* See ssp.c */
+int ssp_ctx_create_client(struct smb_ctx *, struct mbdata *);
+int ssp_ctx_next_token(struct smb_ctx *, struct mbdata *, struct mbdata *);
+void ssp_ctx_destroy(struct smb_ctx *);
+#ifdef KICONV_SUPPORT
+/* See nls.c (get rid of this?) */
extern uchar_t nls_lower[256], nls_upper[256];
+#endif /* KICONV_SUPPORT */
#endif /* _PRIVATE_H */
diff --git a/usr/src/lib/libsmbfs/smb/rap.c b/usr/src/lib/libsmbfs/smb/rap.c
index 3a9e785191..8260e2639c 100644
--- a/usr/src/lib/libsmbfs/smb/rap.c
+++ b/usr/src/lib/libsmbfs/smb/rap.c
@@ -204,7 +204,6 @@ smb_rap_create(int fn, const char *param, const char *data,
struct smb_rap *rap;
char *p;
int plen = 0, len = 0;
- int i;
rap = malloc(sizeof (*rap));
if (rap == NULL)
@@ -326,10 +325,10 @@ int
smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
{
uint16_t *rp, conv, *tmp;
- uint32_t *p32, ps1;
+ uint32_t *p32;
char *dp, *p = rap->r_nparam;
char ptype;
- int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow, i;
+ int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow;
rdatacnt = rap->r_rcvbuflen;
rparamcnt = rap->r_plen;
diff --git a/usr/src/lib/libsmbfs/smb/rcfile.c b/usr/src/lib/libsmbfs/smb/rcfile.c
index 3f5a87435d..22ca0fc420 100644
--- a/usr/src/lib/libsmbfs/smb/rcfile.c
+++ b/usr/src/lib/libsmbfs/smb/rcfile.c
@@ -36,45 +36,61 @@
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/stat.h>
+
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
-#include <libintl.h>
-#include <pwd.h>
+#include <synch.h>
#include <unistd.h>
-#include <sys/debug.h>
+#include <pwd.h>
+#include <libintl.h>
#include <cflib.h>
#include "rcfile_priv.h"
-extern int smb_debug;
-SLIST_HEAD(rcfile_head, rcfile);
-static struct rcfile_head pf_head = {NULL};
+#include <assert.h>
+
+#if 0 /* before SMF */
+#define SMB_CFG_FILE "/etc/nsmb.conf"
+#define OLD_SMB_CFG_FILE "/usr/local/etc/nsmb.conf"
+#endif
+#define SMBFS_SHARECTL_CMD "/usr/sbin/sharectl get smbfs"
+
+extern int smb_debug;
static struct rcfile *rc_cachelookup(const char *filename);
-struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname);
+static struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname);
static struct rcsection *rc_addsect(struct rcfile *rcp, const char *sectname);
-static int rc_freesect(struct rcfile *rcp, struct rcsection *rsp);
-struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname);
+static int rc_freesect(struct rcfile *rcp, struct rcsection *rsp);
+static struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *key);
static struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name,
const char *value);
static void rc_key_free(struct rckey *p);
static void rc_parse(struct rcfile *rcp);
+/* lock for the variables below */
+mutex_t rcfile_mutex = DEFAULTMUTEX;
+
+SLIST_HEAD(rcfile_head, rcfile);
+static struct rcfile_head pf_head = {NULL};
+struct rcfile *smb_rc;
+int home_nsmbrc;
int insecure_nsmbrc;
/*
* open rcfile and load its content, if already open - return previous handle
*/
-int
+static int
rc_open(const char *filename, const char *mode, struct rcfile **rcfile)
{
+ struct stat statbuf;
struct rcfile *rcp;
FILE *f;
- struct stat statbuf;
+
+ assert(MUTEX_HELD(&rcfile_mutex));
rcp = rc_cachelookup(filename);
if (rcp) {
@@ -102,12 +118,15 @@ rc_open(const char *filename, const char *mode, struct rcfile **rcfile)
return (0);
}
-int
+static int
rc_merge(const char *filename, struct rcfile **rcfile)
{
+ struct stat statbuf;
struct rcfile *rcp = *rcfile;
FILE *f, *t;
+ assert(MUTEX_HELD(&rcfile_mutex));
+
insecure_nsmbrc = 0;
if (rcp == NULL) {
return (rc_open(filename, "r", rcfile));
@@ -115,6 +134,10 @@ rc_merge(const char *filename, struct rcfile **rcfile)
f = fopen(filename, "r");
if (f == NULL)
return (errno);
+ insecure_nsmbrc = 0;
+ if (fstat(fileno(f), &statbuf) >= 0 &&
+ (statbuf.st_mode & 077) != 0)
+ insecure_nsmbrc = 1;
t = rcp->rf_f;
rcp->rf_f = f;
rc_parse(rcp);
@@ -123,43 +146,45 @@ rc_merge(const char *filename, struct rcfile **rcfile)
return (0);
}
-int
-rc_merge_pipe(const char *command, struct rcfile **rcfile)
+/*
+ * Like rc_open, but does popen of command:
+ * sharectl get smbfs
+ */
+static int
+rc_popen_cmd(const char *command, struct rcfile **rcfile)
{
- struct rcfile *rcp = *rcfile;
- FILE *f, *t;
+ struct rcfile *rcp;
+ FILE *f;
+
+ assert(MUTEX_HELD(&rcfile_mutex));
- insecure_nsmbrc = 0;
f = popen(command, "r");
if (f == NULL)
return (errno);
+ insecure_nsmbrc = 0;
+
+ rcp = malloc(sizeof (struct rcfile));
if (rcp == NULL) {
- rcp = malloc(sizeof (struct rcfile));
- if (rcp == NULL) {
- fclose(f);
- return (ENOMEM);
- }
- *rcfile = rcp;
- bzero(rcp, sizeof (struct rcfile));
- rcp->rf_name = strdup(command);
- rcp->rf_f = f;
- SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
- rc_parse(rcp);
- } else {
- t = rcp->rf_f;
- rcp->rf_f = f;
- rc_parse(rcp);
- rcp->rf_f = t;
+ fclose(f);
+ return (ENOMEM);
}
- fclose(f);
+ bzero(rcp, sizeof (struct rcfile));
+ rcp->rf_name = strdup(command);
+ rcp->rf_f = f;
+ SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
+ rc_parse(rcp);
+ *rcfile = rcp;
+ /* fclose(f) in rc_close */
return (0);
}
-int
+static int
rc_close(struct rcfile *rcp)
{
struct rcsection *p, *n;
+ mutex_lock(&rcfile_mutex);
+
fclose(rcp->rf_f);
for (p = SLIST_FIRST(&rcp->rf_sect); p; ) {
n = p;
@@ -169,6 +194,8 @@ rc_close(struct rcfile *rcp)
free(rcp->rf_name);
SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next);
free(rcp);
+
+ mutex_unlock(&rcfile_mutex);
return (0);
}
@@ -177,17 +204,21 @@ rc_cachelookup(const char *filename)
{
struct rcfile *p;
+ assert(MUTEX_HELD(&rcfile_mutex));
+
SLIST_FOREACH(p, &pf_head, rf_next)
if (strcmp(filename, p->rf_name) == 0)
return (p);
return (0);
}
-/* static */ struct rcsection *
+static struct rcsection *
rc_findsect(struct rcfile *rcp, const char *sectname)
{
struct rcsection *p;
+ assert(MUTEX_HELD(&rcfile_mutex));
+
SLIST_FOREACH(p, &rcp->rf_sect, rs_next)
if (strcasecmp(p->rs_name, sectname) == 0)
return (p);
@@ -199,6 +230,8 @@ rc_addsect(struct rcfile *rcp, const char *sectname)
{
struct rcsection *p;
+ assert(MUTEX_HELD(&rcfile_mutex));
+
p = rc_findsect(rcp, sectname);
if (p)
return (p);
@@ -216,6 +249,8 @@ rc_freesect(struct rcfile *rcp, struct rcsection *rsp)
{
struct rckey *p, *n;
+ assert(MUTEX_HELD(&rcfile_mutex));
+
SLIST_REMOVE(&rcp->rf_sect, rsp, rcsection, rs_next);
for (p = SLIST_FIRST(&rsp->rs_keys); p; ) {
n = p;
@@ -227,11 +262,13 @@ rc_freesect(struct rcfile *rcp, struct rcsection *rsp)
return (0);
}
-/* static */ struct rckey *
+static struct rckey *
rc_sect_findkey(struct rcsection *rsp, const char *keyname)
{
struct rckey *p;
+ assert(MUTEX_HELD(&rcfile_mutex));
+
SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
if (strcmp(p->rk_name, keyname) == 0)
return (p);
@@ -243,6 +280,8 @@ rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value)
{
struct rckey *p;
+ assert(MUTEX_HELD(&rcfile_mutex));
+
p = rc_sect_findkey(rsp, name);
if (!p) {
p = malloc(sizeof (*p));
@@ -273,16 +312,13 @@ rc_key_free(struct rckey *p)
free(p);
}
-enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
-
-int home_nsmbrc = 0;
-static char *minauth[] = {
- "kerberos",
- "ntlmv2",
- "ntlm",
- "lm",
+static char *minauth_values[] = {
"none",
+ "lm",
+ "ntlm",
+ "ntlmv2",
+ "kerberos",
NULL
};
@@ -291,43 +327,57 @@ eval_minauth(char *auth)
{
int i;
- for (i = 0; minauth[i]; i++)
- if (strcmp(auth, minauth[i]) == 0)
- break;
- return (i);
+ for (i = 0; minauth_values[i]; i++)
+ if (strcmp(auth, minauth_values[i]) == 0)
+ return (i);
+ return (-1);
}
/*
- * Ensure that "minauth" is set to the highest level (lowest array offset)
+ * Ensure that "minauth" is set to the highest level
*/
+/*ARGSUSED*/
static void
set_value(struct rcfile *rcp, struct rcsection *rsp, struct rckey *rkp,
char *ptr)
{
int now, new;
+#ifdef DEBUG
+ char *from;
+
+ if (smb_debug)
+ from = (home_nsmbrc) ?
+ "user file" : "SMF";
+#endif
if (strcmp(rkp->rk_name, "minauth") == 0) {
now = eval_minauth(rkp->rk_value);
new = eval_minauth(ptr);
- if (new >= now) {
+ if (new <= now) {
#ifdef DEBUG
if (smb_debug)
- printf(
- "set_value: rejecting %s=%s from %s\n",
- rkp->rk_name, ptr, home_nsmbrc ?
- "user file" : "SMF");
+ fprintf(stderr,
+ "set_value: rejecting %s=%s"
+ " in %s from %s\n",
+ rkp->rk_name, ptr,
+ rsp->rs_name, from);
#endif
return;
}
}
#ifdef DEBUG
if (smb_debug)
- printf("set_value: applying %s=%s from %s\n",
- rkp->rk_name, ptr, home_nsmbrc ? "user file" : "SMF");
+ fprintf(stderr,
+ "set_value: applying %s=%s in %s from %s\n",
+ rkp->rk_name, ptr, rsp->rs_name, from);
#endif
rkp->rk_value = strdup(ptr);
}
+
+/* states in rc_parse */
+enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
+
static void
rc_parse(struct rcfile *rcp)
{
@@ -338,6 +388,8 @@ rc_parse(struct rcfile *rcp)
char buf[2048];
char *next = buf, *last = &buf[sizeof (buf)-1];
+ assert(MUTEX_HELD(&rcfile_mutex));
+
while ((c = getc(f)) != EOF) {
if (c == '\r')
continue;
@@ -393,8 +445,8 @@ rc_parse(struct rcfile *rcp)
state = stSkipToEOL;
continue;
}
- if (home_nsmbrc &&
- (strcmp(buf, "nbns") == 0 ||
+ if (home_nsmbrc != 0 && (
+ strcmp(buf, "nbns") == 0 ||
strcmp(buf, "nbns_enable") == 0 ||
strcmp(buf, "nbns_broadcast") == 0 ||
strcmp(buf, "signing") == 0)) {
@@ -405,7 +457,8 @@ rc_parse(struct rcfile *rcp)
state = stNewLine;
continue;
}
- if (insecure_nsmbrc && (strcmp(buf, "password") == 0)) {
+ if (insecure_nsmbrc != 0 &&
+ strcmp(buf, "password") == 0) {
fprintf(stderr, dgettext(TEXT_DOMAIN,
"Warning: .nsmbrc file not secure, "
"ignoring passwords\n"));
@@ -445,16 +498,27 @@ rc_getstringptr(struct rcfile *rcp, const char *section, const char *key,
{
struct rcsection *rsp;
struct rckey *rkp;
+ int err;
+
+ mutex_lock(&rcfile_mutex);
*dest = NULL;
rsp = rc_findsect(rcp, section);
- if (!rsp)
- return (ENOENT);
+ if (!rsp) {
+ err = ENOENT;
+ goto out;
+ }
rkp = rc_sect_findkey(rsp, key);
- if (!rkp)
- return (ENOENT);
+ if (!rkp) {
+ err = ENOENT;
+ goto out;
+ }
*dest = rkp->rk_value;
- return (0);
+ err = 0;
+
+out:
+ mutex_unlock(&rcfile_mutex);
+ return (err);
}
int
@@ -468,7 +532,7 @@ rc_getstring(struct rcfile *rcp, const char *section, const char *key,
if (error)
return (error);
if (strlen(value) >= maxlen) {
- fprintf(stdout, dgettext(TEXT_DOMAIN,
+ fprintf(stderr, dgettext(TEXT_DOMAIN,
"line too long for key '%s' in section '%s', max = %d\n"),
key, section, maxlen);
return (EINVAL);
@@ -482,22 +546,31 @@ rc_getint(struct rcfile *rcp, const char *section, const char *key, int *value)
{
struct rcsection *rsp;
struct rckey *rkp;
+ int err;
+
+ mutex_lock(&rcfile_mutex);
rsp = rc_findsect(rcp, section);
- if (!rsp)
- return (ENOENT);
+ if (!rsp) {
+ err = ENOENT;
+ goto out;
+ }
rkp = rc_sect_findkey(rsp, key);
- if (!rkp)
- return (ENOENT);
+ if (!rkp) {
+ err = ENOENT;
+ goto out;
+ }
errno = 0;
*value = strtol(rkp->rk_value, NULL, 0);
- if (errno) {
- fprintf(stdout, dgettext(TEXT_DOMAIN,
+ if ((err = errno) != 0) {
+ fprintf(stderr, dgettext(TEXT_DOMAIN,
"invalid int value '%s' for key '%s' in section '%s'\n"),
rkp->rk_value, key, section);
- return (errno);
}
- return (0);
+
+out:
+ mutex_unlock(&rcfile_mutex);
+ return (err);
}
/*
@@ -510,139 +583,136 @@ rc_getbool(struct rcfile *rcp, const char *section, const char *key, int *value)
struct rcsection *rsp;
struct rckey *rkp;
char *p;
+ int err;
+
+ mutex_lock(&rcfile_mutex);
rsp = rc_findsect(rcp, section);
- if (!rsp)
- return (ENOENT);
+ if (!rsp) {
+ err = ENOENT;
+ goto out;
+ }
rkp = rc_sect_findkey(rsp, key);
- if (!rkp)
- return (ENOENT);
+ if (!rkp) {
+ err = ENOENT;
+ goto out;
+ }
p = rkp->rk_value;
while (*p && isspace(*p)) p++;
if (*p == '0' ||
strcasecmp(p, "no") == 0 ||
strcasecmp(p, "false") == 0) {
*value = 0;
- return (0);
+ err = 0;
+ goto out;
}
if (*p == '1' ||
strcasecmp(p, "yes") == 0 ||
strcasecmp(p, "true") == 0) {
*value = 1;
- return (0);
+ err = 0;
+ goto out;
}
fprintf(stderr, dgettext(TEXT_DOMAIN,
"invalid boolean value '%s' for key '%s' in section '%s' \n"),
p, key, section);
- return (EINVAL);
+ err = EINVAL;
+
+out:
+ mutex_unlock(&rcfile_mutex);
+ return (err);
+}
+
+#ifdef DEBUG
+void
+dump_props(char *where)
+{
+ struct rcsection *rsp = NULL;
+ struct rckey *rkp = NULL;
+
+ fprintf(stderr, "Settings %s\n", where);
+ SLIST_FOREACH(rsp, &smb_rc->rf_sect, rs_next) {
+ fprintf(stderr, "section=%s\n", rsp->rs_name);
+ fflush(stderr);
+
+ SLIST_FOREACH(rkp, &rsp->rs_keys, rk_next) {
+ fprintf(stderr, " key=%s, value=%s\n",
+ rkp->rk_name, rkp->rk_value);
+ fflush(stderr);
+ }
+ }
}
+#endif
/*
- * Unified command line/rc file parser
+ * first parse "sharectl get smbfs, then $HOME/.nsmbrc
+ * This is called by library consumers (commands)
*/
int
-opt_args_parse(struct rcfile *rcp, struct opt_args *ap, const char *sect,
- opt_callback_t *callback)
+smb_open_rcfile(char *home)
{
- int len, error;
-
- for (; ap->opt; ap++) {
- switch (ap->type) {
- case OPTARG_STR:
- if (rc_getstringptr(rcp, sect, ap->name, &ap->str) != 0)
- break;
- len = strlen(ap->str);
- if (len > ap->ival) {
- fprintf(stdout, dgettext(TEXT_DOMAIN,
- "rc: argument for option '%c' (%s) too long\n"),
- ap->opt, ap->name);
- return (EINVAL);
- }
- callback(ap);
- break;
- case OPTARG_BOOL:
- error = rc_getbool(rcp, sect, ap->name, &ap->ival);
- if (error == ENOENT)
- break;
- if (error)
- return (EINVAL);
- callback(ap);
- break;
- case OPTARG_INT:
- if (rc_getint(rcp, sect, ap->name, &ap->ival) != 0)
- break;
- if (((ap->flag & OPTFL_HAVEMIN) &&
- ap->ival < ap->min) ||
- ((ap->flag & OPTFL_HAVEMAX) &&
- ap->ival > ap->max)) {
- fprintf(stdout, dgettext(TEXT_DOMAIN,
- "rc: argument for option '%c' (%s) "
- "should be in [%d-%d] range\n"),
- ap->opt, ap->name, ap->min, ap->max);
- return (EINVAL);
- }
- callback(ap);
- break;
- default:
- break;
+ char *fn;
+ int len, error = 0;
+
+ mutex_lock(&rcfile_mutex);
+
+ smb_rc = NULL;
+#if 0 /* before SMF */
+ fn = SMB_CFG_FILE;
+ error = rc_open(fn, &smb_rc);
+#else
+ fn = SMBFS_SHARECTL_CMD;
+ error = rc_popen_cmd(fn, &smb_rc);
+#endif
+ if (error != 0 && error != ENOENT) {
+ /* Error from fopen. strerror is OK. */
+ fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "Can't open %s: %s\n"), fn, strerror(errno));
+ }
+#ifdef DEBUG
+ if (smb_debug)
+ dump_props(fn);
+#endif
+
+ if (home) {
+ len = strlen(home) + 20;
+ fn = malloc(len);
+ snprintf(fn, len, "%s/.nsmbrc", home);
+ home_nsmbrc = 1;
+ error = rc_merge(fn, &smb_rc);
+ if (error != 0 && error != ENOENT) {
+ fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "Can't open %s: %s\n"), fn, strerror(errno));
}
+ home_nsmbrc = 0;
+#ifdef DEBUG
+ if (smb_debug)
+ dump_props(fn);
+#endif
+ free(fn);
}
- return (0);
+
+ /* Mostly ignore error returns above. */
+ if (smb_rc == NULL)
+ error = ENOENT;
+ else
+ error = 0;
+
+ mutex_unlock(&rcfile_mutex);
+
+ return (error);
}
-int
-opt_args_parseopt(struct opt_args *ap, int opt, char *arg,
- opt_callback_t *callback)
+/*
+ * This is called by library consumers (commands)
+ */
+void
+smb_close_rcfile(void)
{
- int len;
+ struct rcfile *rcp;
- for (; ap->opt; ap++) {
- if (ap->opt != opt)
- continue;
- switch (ap->type) {
- case OPTARG_STR:
- ap->str = arg;
- if (arg) {
- len = strlen(ap->str);
- if (len > ap->ival) {
- fprintf(stdout, dgettext(TEXT_DOMAIN,
- "opt: Argument for option '%c' (%s) too long\n"),
- ap->opt, ap->name);
- return (EINVAL);
- }
- callback(ap);
- }
- break;
- case OPTARG_BOOL:
- ap->ival = 0;
- callback(ap);
- break;
- case OPTARG_INT:
- errno = 0;
- ap->ival = strtol(arg, NULL, 0);
- if (errno) {
- fprintf(stdout, dgettext(TEXT_DOMAIN,
- "opt: Invalid integer value for "
- "option '%c' (%s).\n"),
- ap->opt, ap->name);
- return (EINVAL);
- }
- if (((ap->flag & OPTFL_HAVEMIN) &&
- (ap->ival < ap->min)) ||
- ((ap->flag & OPTFL_HAVEMAX) &&
- (ap->ival > ap->max))) {
- fprintf(stdout, dgettext(TEXT_DOMAIN,
- "opt: Argument for option '%c' (%s) "
- "should be in [%d-%d] range\n"),
- ap->opt, ap->name, ap->min, ap->max);
- return (EINVAL);
- }
- callback(ap);
- break;
- default:
- break;
- }
- break;
+ if ((rcp = smb_rc) != NULL) {
+ smb_rc = NULL;
+ rc_close(rcp);
}
- return (0);
}
diff --git a/usr/src/lib/libsmbfs/smb/rcfile_priv.h b/usr/src/lib/libsmbfs/smb/rcfile_priv.h
index 85ed97e1fd..ef9e31d7fc 100644
--- a/usr/src/lib/libsmbfs/smb/rcfile_priv.h
+++ b/usr/src/lib/libsmbfs/smb/rcfile_priv.h
@@ -1,4 +1,34 @@
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2000, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
struct rckey {
SLIST_ENTRY(rckey) rk_next;
@@ -8,14 +38,17 @@ struct rckey {
struct rcsection {
SLIST_ENTRY(rcsection) rs_next;
- SLIST_HEAD(rckey_head,rckey) rs_keys;
+ SLIST_HEAD(rckey_head, rckey) rs_keys;
char *rs_name;
};
-
+
struct rcfile {
SLIST_ENTRY(rcfile) rf_next;
SLIST_HEAD(rcsec_head, rcsection) rf_sect;
char *rf_name;
FILE *rf_f;
+ int rf_flags; /* RCFILE_... */
};
+#define RCFILE_HOME_NSMBRC 1
+#define RCFILE_IS_INSECURE 2
diff --git a/usr/src/lib/libsmbfs/smb/rq.c b/usr/src/lib/libsmbfs/smb/rq.c
index 6390a3c157..7b21708428 100644
--- a/usr/src/lib/libsmbfs/smb/rq.c
+++ b/usr/src/lib/libsmbfs/smb/rq.c
@@ -47,26 +47,66 @@
#include <sysexits.h>
#include <libintl.h>
+#include <netsmb/smb.h>
#include <netsmb/smb_lib.h>
#include "private.h"
+static uint32_t smb_map_doserr(uint8_t, uint16_t);
+/*
+ * Create and initialize a request structure, for either an
+ * "internal" request (one that does not use the driver) or
+ * a regular "driver" request, that uses driver ioctls.
+ *
+ * The two kinds are built a little differently:
+ * Driver requests are composed starting with the
+ * first word of the "variable word vector" section.
+ * The driver prepends the SMB header and word count.
+ * The driver also needs an output buffer to receive
+ * the response, filled in via copyout in the ioctl.
+ *
+ * Internal requests are composed entirely in this library.
+ * Space for the SMB header is reserved here, and later
+ * filled in by smb_rq_internal before the send/receive.
+ */
int
-smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, size_t rpbufsz,
- struct smb_rq **rqpp)
+smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, struct smb_rq **rqpp)
{
struct smb_rq *rqp;
rqp = malloc(sizeof (*rqp));
if (rqp == NULL)
- return (ENOMEM);
+ goto errout;
bzero(rqp, sizeof (*rqp));
rqp->rq_cmd = cmd;
rqp->rq_ctx = ctx;
- mb_init(&rqp->rq_rq, M_MINSIZE);
- mb_init(&rqp->rq_rp, rpbufsz);
+
+ /*
+ * Setup the request buffer.
+ * Do the reply buffer later.
+ */
+ if (mb_init(&rqp->rq_rq, M_MINSIZE))
+ goto errout;
+
+ /* Space for the SMB header. (filled in later) */
+ mb_put_mem(&rqp->rq_rq, NULL, SMB_HDRLEN);
+
+ /*
+ * Copy the ctx flags here, so the caller can
+ * update the req flags before the OTW call.
+ */
+ rqp->rq_hflags = ctx->ct_hflags;
+ rqp->rq_hflags2 = ctx->ct_hflags2;
+
*rqpp = rqp;
return (0);
+
+errout:
+ if (rqp) {
+ smb_rq_done(rqp);
+ free(rqp);
+ }
+ return (ENOMEM);
}
void
@@ -77,81 +117,162 @@ smb_rq_done(struct smb_rq *rqp)
free(rqp);
}
+/*
+ * Reserve space for the word count, which is filled in later by
+ * smb_rq_wend(). Also initialize the counter that it uses
+ * to figure out what value to fill in.
+ *
+ * Note that the word count happens to be 8-bits,
+ * which can lead to confusion.
+ */
void
-smb_rq_wend(struct smb_rq *rqp)
+smb_rq_wstart(struct smb_rq *rqp)
{
- if (rqp->rq_rq.mb_count & 1)
- smb_error(dgettext(TEXT_DOMAIN,
- "smbrq_wend: odd word count\n"), 0);
- rqp->rq_wcount = rqp->rq_rq.mb_count / 2;
- rqp->rq_rq.mb_count = 0;
+ struct mbdata *mbp = &rqp->rq_rq;
+
+ mb_fit(mbp, 1, &rqp->rq_wcntp);
+ rqp->rq_wcbase = mbp->mb_count;
}
-int
-smb_rq_dmem(struct mbdata *mbp, const char *src, size_t size)
+/*
+ * Fill in the word count, in the space reserved by
+ * smb_rq_wstart().
+ */
+void
+smb_rq_wend(struct smb_rq *rqp)
{
- struct mbuf *m;
- char *dst;
- int cplen, error;
+ struct mbdata *mbp = &rqp->rq_rq;
+ int wcnt;
- if (size == 0)
- return (0);
- m = mbp->mb_cur;
- if ((error = m_getm(m, size, &m)) != 0)
- return (error);
- while (size > 0) {
- cplen = M_TRAILINGSPACE(m);
- if (cplen == 0) {
- m = m->m_next;
- continue;
- }
- if (cplen > (int)size)
- cplen = size;
- dst = mtod(m, char *) + m->m_len;
- nls_mem_toext(dst, src, cplen);
- size -= cplen;
- src += cplen;
- m->m_len += cplen;
- mbp->mb_count += cplen;
+ if (rqp->rq_wcntp == NULL) {
+ DPRINT("no wcount ptr\n");
+ return;
}
- mbp->mb_pos = mtod(m, char *) + m->m_len;
- mbp->mb_cur = m;
- return (0);
+ wcnt = mbp->mb_count - rqp->rq_wcbase;
+ if (wcnt > 0x1ff)
+ DPRINT("word count too large (%d)\n", wcnt);
+ if (wcnt & 1)
+ DPRINT("odd word count\n");
+ wcnt >>= 1;
+
+ /*
+ * Fill in the word count (8-bits).
+ * Also store it in the rq, in case
+ * we're using the ioctl path.
+ */
+ *rqp->rq_wcntp = (char)wcnt;
}
-int
-smb_rq_dstring(struct mbdata *mbp, const char *s)
+/*
+ * Reserve space for the byte count, which is filled in later by
+ * smb_rq_bend(). Also initialize the counter that it uses
+ * to figure out what value to fill in.
+ *
+ * Note that the byte count happens to be 16-bits,
+ * which can lead to confusion.
+ */
+void
+smb_rq_bstart(struct smb_rq *rqp)
+{
+ struct mbdata *mbp = &rqp->rq_rq;
+
+ mb_fit(mbp, 2, &rqp->rq_bcntp);
+ rqp->rq_bcbase = mbp->mb_count;
+}
+
+/*
+ * Fill in the byte count, in the space reserved by
+ * smb_rq_bstart().
+ */
+void
+smb_rq_bend(struct smb_rq *rqp)
{
- return (smb_rq_dmem(mbp, s, strlen(s) + 1));
+ struct mbdata *mbp = &rqp->rq_rq;
+ int bcnt;
+
+ if (rqp->rq_bcntp == NULL) {
+ DPRINT("no bcount ptr\n");
+ return;
+ }
+ bcnt = mbp->mb_count - rqp->rq_bcbase;
+ if (bcnt > 0xffff)
+ DPRINT("byte count too large (%d)\n", bcnt);
+ /*
+ * Fill in the byte count (16-bits).
+ * Also store it in the rq, in case
+ * we're using the ioctl path.
+ *
+ * The pointer is char * type due to
+ * typical off-by-one alignment.
+ */
+ rqp->rq_bcntp[0] = bcnt & 0xFF;
+ rqp->rq_bcntp[1] = (bcnt >> 8);
}
+/*
+ * Removed: smb_rq_dmem
+ * which was mostly like: mb_put_mem
+ */
+
int
smb_rq_simple(struct smb_rq *rqp)
{
struct smbioc_rq krq;
struct mbdata *mbp;
char *data;
- int i;
+ uint32_t len;
+ size_t rpbufsz;
+
+ bzero(&krq, sizeof (krq));
+ krq.ioc_cmd = rqp->rq_cmd;
+ /*
+ * Make the SMB request body contiguous,
+ * and fill in the ioctl request.
+ */
mbp = smb_rq_getrequest(rqp);
m_lineup(mbp->mb_top, &mbp->mb_top);
data = mtod(mbp->mb_top, char *);
- bzero(&krq, sizeof (krq));
- krq.ioc_cmd = rqp->rq_cmd;
- krq.ioc_twc = rqp->rq_wcount;
- krq.ioc_twords = data;
- krq.ioc_tbc = mbp->mb_count;
- krq.ioc_tbytes = data + rqp->rq_wcount * 2;
+ len = m_totlen(mbp->mb_top);
+ /*
+ * _rq_init left space for the SMB header,
+ * which makes mb_count the offset from
+ * the beginning of the header (useful).
+ * However, in this code path the driver
+ * prepends the header, so we skip it.
+ */
+ krq.ioc_tbufsz = len - SMB_HDRLEN;
+ krq.ioc_tbuf = data + SMB_HDRLEN;
+
+ /*
+ * Setup a buffer to hold the reply.
+ *
+ * Default size is M_MINSIZE, but the
+ * caller may increase rq_rpbufsz
+ * before calling this.
+ */
mbp = smb_rq_getreply(rqp);
- krq.ioc_rpbufsz = mbp->mb_top->m_maxlen;
- krq.ioc_rpbuf = mtod(mbp->mb_top, char *);
- if (ioctl(rqp->rq_ctx->ct_fd, SMBIOC_REQUEST, &krq) == -1) {
+ rpbufsz = rqp->rq_rpbufsz;
+ if (rpbufsz < M_MINSIZE)
+ rpbufsz = M_MINSIZE;
+ if (mb_init(mbp, rpbufsz))
+ return (ENOMEM);
+ krq.ioc_rbufsz = rpbufsz;
+ krq.ioc_rbuf = mtod(mbp->mb_top, char *);
+
+ /*
+ * Call the driver
+ */
+ if (ioctl(rqp->rq_ctx->ct_dev_fd, SMBIOC_REQUEST, &krq) == -1)
return (errno);
- }
- mbp->mb_top->m_len = krq.ioc_rwc * 2 + krq.ioc_rbc;
- rqp->rq_wcount = krq.ioc_rwc;
- rqp->rq_bcount = krq.ioc_rbc;
+
+ /*
+ * Initialize returned mbdata.
+ * SMB header already parsed.
+ */
+ mbp->mb_top->m_len = krq.ioc_rbufsz;
+
return (0);
}
@@ -167,13 +288,11 @@ smb_t2_request(struct smb_ctx *ctx, int setupcount, uint16_t *setup,
{
smbioc_t2rq_t *krq;
int i;
- char *pass;
-
krq = (smbioc_t2rq_t *)malloc(sizeof (smbioc_t2rq_t));
bzero(krq, sizeof (*krq));
- if (setupcount < 0 || setupcount >= SMB_MAXSETUPWORDS) {
+ if (setupcount < 0 || setupcount >= SMBIOC_T2RQ_MAXSETUP) {
/* Bogus setup count, or too many setup words */
return (EINVAL);
}
@@ -191,7 +310,7 @@ smb_t2_request(struct smb_ctx *ctx, int setupcount, uint16_t *setup,
krq->ioc_rparam = rparam;
krq->ioc_rdata = rdata;
- if (ioctl(ctx->ct_fd, SMBIOC_T2RQ, krq) == -1) {
+ if (ioctl(ctx->ct_dev_fd, SMBIOC_T2RQ, krq) == -1) {
return (errno);
}
@@ -200,5 +319,149 @@ smb_t2_request(struct smb_ctx *ctx, int setupcount, uint16_t *setup,
*buffer_oflow = (krq->ioc_rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
(krq->ioc_error == NT_STATUS_BUFFER_OVERFLOW);
free(krq);
+
return (0);
}
+
+
+/*
+ * Do an over-the-wire call without using the nsmb driver.
+ * This is all "internal" to this library, and used only
+ * for connection setup (negotiate protocol, etc.)
+ */
+int
+smb_rq_internal(struct smb_ctx *ctx, struct smb_rq *rqp)
+{
+ static const uint8_t ffsmb[4] = SMB_SIGNATURE;
+ struct smb_iods *is = &ctx->ct_iods;
+ uint32_t sigbuf[2];
+ struct mbdata mbtmp, *mbp;
+ int err, save_mlen;
+ uint8_t ctmp;
+
+ rqp->rq_uid = is->is_smbuid;
+ rqp->rq_tid = SMB_TID_UNKNOWN;
+ rqp->rq_mid = is->is_next_mid++;
+
+ /*
+ * Fill in the NBT and SMB headers
+ * Using mbtmp so we can rewind without
+ * affecting the passed request mbdata.
+ */
+ bcopy(&rqp->rq_rq, &mbtmp, sizeof (mbtmp));
+ mbp = &mbtmp;
+ mbp->mb_cur = mbp->mb_top;
+ mbp->mb_pos = mbp->mb_cur->m_data;
+ mbp->mb_count = 0;
+ /* Have to save and restore m_len */
+ save_mlen = mbp->mb_cur->m_len;
+ mbp->mb_cur->m_len = 0;
+
+ /*
+ * rewind done; fill it in
+ */
+ mb_put_mem(mbp, (char *)SMB_SIGNATURE, SMB_SIGLEN);
+ mb_put_uint8(mbp, rqp->rq_cmd);
+ mb_put_mem(mbp, NULL, 4); /* status */
+ mb_put_uint8(mbp, rqp->rq_hflags);
+ mb_put_uint16le(mbp, rqp->rq_hflags2);
+ mb_put_uint16le(mbp, 0); /* pid_hi */
+ mb_put_mem(mbp, NULL, 8); /* signature */
+ mb_put_uint16le(mbp, 0); /* reserved */
+ mb_put_uint16le(mbp, rqp->rq_tid);
+ mb_put_uint16le(mbp, 0); /* pid_lo */
+ mb_put_uint16le(mbp, rqp->rq_uid);
+ mb_put_uint16le(mbp, rqp->rq_mid);
+
+ /* Restore original m_len */
+ mbp->mb_cur->m_len = save_mlen;
+
+ /*
+ * Sign the message, if flags2 indicates.
+ */
+ if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
+ smb_rq_sign(rqp);
+ }
+
+ /*
+ * Send it, wait for the reply.
+ */
+ if ((err = smb_ssn_send(ctx, &rqp->rq_rq)) != 0)
+ return (err);
+
+ if ((err = smb_ssn_recv(ctx, &rqp->rq_rp)) != 0)
+ return (err);
+
+ /*
+ * Should have an SMB header, at least.
+ */
+ mbp = &rqp->rq_rp;
+ if (mbp->mb_cur->m_len < SMB_HDRLEN) {
+ DPRINT("len < 32");
+ return (EBADRPC);
+ }
+
+ /*
+ * If the request was signed, validate the
+ * signature on the response.
+ */
+ if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
+ err = smb_rq_verify(rqp);
+ if (err) {
+ DPRINT("bad signature");
+ return (err);
+ }
+ }
+
+ /*
+ * Decode the SMB header.
+ */
+ mb_get_mem(mbp, (char *)sigbuf, 4);
+ if (0 != bcmp(sigbuf, ffsmb, 4)) {
+ DPRINT("not SMB");
+ return (EBADRPC);
+ }
+ mb_get_uint8(mbp, &ctmp); /* SMB cmd */
+ mb_get_uint32le(mbp, &rqp->rq_status);
+ mb_get_uint8(mbp, &rqp->rq_hflags);
+ mb_get_uint16le(mbp, &rqp->rq_hflags2);
+ mb_get_uint16le(mbp, NULL); /* pid_hi */
+ mb_get_mem(mbp, NULL, 8); /* signature */
+ mb_get_uint16le(mbp, NULL); /* reserved */
+ mb_get_uint16le(mbp, &rqp->rq_tid);
+ mb_get_uint16le(mbp, NULL); /* pid_lo */
+ mb_get_uint16le(mbp, &rqp->rq_uid);
+ mb_get_uint16le(mbp, &rqp->rq_mid);
+
+ /*
+ * Figure out the status return.
+ * Caller looks at rq_status.
+ */
+ if ((rqp->rq_hflags2 & SMB_FLAGS2_ERR_STATUS) == 0) {
+ uint16_t serr;
+ uint8_t class;
+
+ class = rqp->rq_status & 0xff;
+ serr = rqp->rq_status >> 16;
+ rqp->rq_status = smb_map_doserr(class, serr);
+ }
+
+ return (0);
+}
+
+/*
+ * Map old DOS errors (etc.) to NT status codes.
+ * We probably don't need this anymore, since
+ * the oldest server we talk to is NT. But if
+ * later find we do need this, add support here
+ * for the DOS errors we care about.
+ */
+static uint32_t
+smb_map_doserr(uint8_t class, uint16_t serr)
+{
+ if (class == 0 && serr == 0)
+ return (0);
+
+ DPRINT("class 0x%x serr 0x%x", (int)class, (int)serr);
+ return (NT_STATUS_UNSUCCESSFUL);
+}
diff --git a/usr/src/lib/libsmbfs/smb/signing.c b/usr/src/lib/libsmbfs/smb/signing.c
new file mode 100644
index 0000000000..ef9a32e2e0
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/signing.c
@@ -0,0 +1,265 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Signing support, using libmd
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+
+#include <sys/types.h>
+#include <sys/md5.h>
+
+#include <netsmb/mchain.h>
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+
+#include "private.h"
+
+#define SMBSIGOFF 14 /* SMB signature offset */
+#define SMBSIGLEN 8 /* SMB signature length */
+
+/*
+ * Set this to a small number to debug sequence numbers
+ * that seem to get out of step.
+ */
+#ifdef DEBUG
+int nsmb_signing_fudge = 4;
+#endif
+
+/*
+ * Compute MD5 digest of packet data, using the stored MAC key.
+ *
+ * See similar code in the driver:
+ * uts/common/fs/smbclnt/netsmb/smb_signing.c
+ * and on the server side:
+ * uts/common/fs/smbsrv/smb_signing.c
+ */
+static int
+smb_compute_MAC(struct smb_ctx *ctx, mbuf_t *m,
+ uint32_t seqno, uchar_t *signature)
+{
+ MD5_CTX md5;
+ uchar_t digest[MD5_DIGEST_LENGTH];
+
+ /*
+ * This union is a little bit of trickery to:
+ * (1) get the sequence number int aligned, and
+ * (2) reduce the number of digest calls, at the
+ * cost of a copying 32 bytes instead of 8.
+ * Both sides of this union are 2+32 bytes.
+ */
+ union {
+ struct {
+ uint8_t skip[2]; /* not used - just alignment */
+ uint8_t raw[SMB_HDRLEN]; /* header length (32) */
+ } r;
+ struct {
+ uint8_t skip[2]; /* not used - just alignment */
+ uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
+ uint32_t sig[2]; /* MAC signature, aligned! */
+ uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
+ } s;
+ } smbhdr;
+
+ if (m->m_len < SMB_HDRLEN)
+ return (EIO);
+ if (ctx->ct_mackey == NULL)
+ return (EINVAL);
+
+ /*
+ * Make an aligned copy of the SMB header
+ * and fill in the sequence number.
+ */
+ bcopy(m->m_data, smbhdr.r.raw, SMB_HDRLEN);
+ smbhdr.s.sig[0] = htolel(seqno);
+ smbhdr.s.sig[1] = 0;
+
+ /*
+ * Compute the MAC: MD5(concat(Key, message))
+ */
+ MD5Init(&md5);
+
+ /* Digest the MAC Key */
+ MD5Update(&md5, ctx->ct_mackey, ctx->ct_mackeylen);
+
+ /* Digest the (copied) SMB header */
+ MD5Update(&md5, smbhdr.r.raw, SMB_HDRLEN);
+
+ /* Digest the rest of the first mbuf */
+ if (m->m_len > SMB_HDRLEN) {
+ MD5Update(&md5, m->m_data + SMB_HDRLEN,
+ m->m_len - SMB_HDRLEN);
+ }
+ m = m->m_next;
+
+ /* Digest rest of the SMB message. */
+ while (m) {
+ MD5Update(&md5, m->m_data, m->m_len);
+ m = m->m_next;
+ }
+
+ /* Final */
+ MD5Final(digest, &md5);
+
+ /*
+ * Finally, store the signature.
+ * (first 8 bytes of the digest)
+ */
+ if (signature)
+ bcopy(digest, signature, SMBSIGLEN);
+
+ return (0);
+}
+
+/*
+ * Sign a request with HMAC-MD5.
+ */
+int
+smb_rq_sign(struct smb_rq *rqp)
+{
+ struct smb_ctx *ctx = rqp->rq_ctx;
+ mbuf_t *m = rqp->rq_rq.mb_top;
+ uint8_t *sigloc;
+ int err;
+
+ /*
+ * Our mblk allocation ensures this,
+ * but just in case...
+ */
+ if (m->m_len < SMB_HDRLEN)
+ return (EIO);
+ sigloc = (uchar_t *)m->m_data + SMBSIGOFF;
+
+ if (ctx->ct_mackey == NULL) {
+ /*
+ * Signing is required, but we have no key yet
+ * fill in with the magic fake signing value.
+ * This happens with SPNEGO, NTLMSSP, ...
+ */
+ bcopy("BSRSPLY", sigloc, 8);
+ return (0);
+ }
+
+ /*
+ * This will compute the MAC and store it
+ * directly into the message at sigloc.
+ */
+ rqp->rq_seqno = ctx->ct_mac_seqno;
+ ctx->ct_mac_seqno += 2;
+ err = smb_compute_MAC(ctx, m, rqp->rq_seqno, sigloc);
+ if (err) {
+ DPRINT("compute MAC, err %d", err);
+ bzero(sigloc, SMBSIGLEN);
+ return (ENOTSUP);
+ }
+ return (0);
+}
+
+/*
+ * Verify reply signature.
+ */
+int
+smb_rq_verify(struct smb_rq *rqp)
+{
+ struct smb_ctx *ctx = rqp->rq_ctx;
+ mbuf_t *m = rqp->rq_rp.mb_top;
+ uint8_t sigbuf[SMBSIGLEN];
+ uint8_t *sigloc;
+ uint32_t rseqno;
+ int err, fudge;
+
+ /*
+ * Note ct_mackey and ct_mackeylen gets initialized by
+ * smb_smb_ssnsetup. It's normal to have a null MAC key
+ * during extended security session setup.
+ */
+ if (ctx->ct_mackey == NULL)
+ return (0);
+
+ /*
+ * Let caller deal with empty reply or short messages by
+ * returning zero. Caller will fail later, in parsing.
+ */
+ if (m == NULL) {
+ DPRINT("empty reply");
+ return (0);
+ }
+ if (m->m_len < SMB_HDRLEN) {
+ DPRINT("short reply");
+ return (0);
+ }
+
+ sigloc = (uchar_t *)m->m_data + SMBSIGOFF;
+ rseqno = rqp->rq_seqno + 1;
+
+ DPRINT("rq_rseqno = 0x%x", rseqno);
+
+ err = smb_compute_MAC(ctx, m, rseqno, sigbuf);
+ if (err) {
+ DPRINT("compute MAC, err %d", err);
+ /*
+ * If we can't compute a MAC, then there's
+ * no point trying other seqno values.
+ */
+ return (EBADRPC);
+ }
+
+ /*
+ * Compare the computed signature with the
+ * one found in the message (at sigloc)
+ */
+ if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
+ return (0);
+
+ DPRINT("BAD signature, MID=0x%x", rqp->rq_mid);
+
+#ifdef DEBUG
+ /*
+ * For diag purposes, we check whether the client/server idea
+ * of the sequence # has gotten a bit out of sync.
+ */
+ for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) {
+ smb_compute_MAC(ctx, m, rseqno + fudge, sigbuf);
+ if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
+ break;
+ smb_compute_MAC(ctx, m, rseqno - fudge, sigbuf);
+ if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) {
+ fudge = -fudge;
+ break;
+ }
+ }
+ if (fudge <= nsmb_signing_fudge) {
+ DPRINT("rseqno=%d, but %d would have worked",
+ rseqno, rseqno + fudge);
+ }
+#endif
+ return (EBADRPC);
+}
diff --git a/usr/src/lib/libsmbfs/smb/smb_crypt.h b/usr/src/lib/libsmbfs/smb/smb_crypt.h
new file mode 100644
index 0000000000..15005ddab6
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/smb_crypt.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Various crypto stuff.
+ * from the driver: smb_crypt.c
+ */
+
+int
+smb_encrypt_DES(uchar_t *Result, int ResultLen,
+ const uchar_t *Key, int KeyLen,
+ const uchar_t *Data, int DataLen);
+
+int
+smb_get_urandom(void *data, size_t dlen);
diff --git a/usr/src/lib/libsmbfs/smb/spnegoparse.c b/usr/src/lib/libsmbfs/smb/spnegoparse.c
index 5da1983c27..e9f1e2781b 100644
--- a/usr/src/lib/libsmbfs/smb/spnegoparse.c
+++ b/usr/src/lib/libsmbfs/smb/spnegoparse.c
@@ -20,8 +20,6 @@
//
/////////////////////////////////////////////////////////////
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
@@ -1615,7 +1613,7 @@ int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength )
int IsValidMechOid( SPNEGO_MECH_OID mechOid )
{
return ( mechOid >= spnego_mech_oid_Kerberos_V5_Legacy &&
- mechOid <= spnego_mech_oid_Spnego );
+ mechOid <= spnego_mech_oid_NTLMSSP );
}
/////////////////////////////////////////////////////////////////////////////
diff --git a/usr/src/lib/libsmbfs/smb/ssnsetup.c b/usr/src/lib/libsmbfs/smb/ssnsetup.c
new file mode 100644
index 0000000000..e4b5ec4f20
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/ssnsetup.c
@@ -0,0 +1,519 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * SMB Session Setup, and related.
+ * Copied from the driver: smb_smb.c
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/mchain.h>
+#include <netsmb/netbios.h>
+#include <netsmb/smb_dev.h>
+#include <netsmb/smb.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+
+#include "private.h"
+#include "charsets.h"
+#include "ntlm.h"
+#include "smb_crypt.h"
+
+/*
+ * When we have a _real_ ntstatus.h, eliminate this.
+ * XXX: Current smb.h defines it without the high bits.
+ */
+#define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016
+
+static int
+smb__ssnsetup(struct smb_ctx *ctx,
+ struct mbdata *mbc1, struct mbdata *mbc2,
+ uint32_t *statusp, uint16_t *actionp);
+
+/*
+ * Session Setup: NULL session (anonymous)
+ */
+int
+smb_ssnsetup_null(struct smb_ctx *ctx)
+{
+ int err;
+ uint32_t ntstatus;
+ uint16_t action = 0;
+
+ if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
+ /* Should not get here with... */
+ err = EINVAL;
+ goto out;
+ }
+
+ err = smb__ssnsetup(ctx, NULL, NULL, &ntstatus, &action);
+ if (err)
+ goto out;
+
+ DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
+ if (ntstatus != 0)
+ err = EAUTH;
+
+out:
+ return (err);
+}
+
+
+/*
+ * SMB Session Setup, using NTLMv1 (and maybe LMv1)
+ */
+int
+smb_ssnsetup_ntlm1(struct smb_ctx *ctx)
+{
+ struct mbdata lm_mbc, nt_mbc;
+ int err;
+ uint32_t ntstatus;
+ uint16_t action = 0;
+
+ if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
+ /* Should not get here with... */
+ err = EINVAL;
+ goto out;
+ }
+
+ /* Make mb_done calls at out safe. */
+ bzero(&lm_mbc, sizeof (lm_mbc));
+ bzero(&nt_mbc, sizeof (nt_mbc));
+
+ /* Put the LM,NTLM responses (as mbdata). */
+ err = ntlm_put_v1_responses(ctx, &lm_mbc, &nt_mbc);
+ if (err)
+ goto out;
+
+ /*
+ * If we negotiated signing, compute the MAC key
+ * and start signing messages, but only on the
+ * first non-null session login.
+ */
+ if ((ctx->ct_vcflags & SMBV_WILL_SIGN) &&
+ (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
+ struct mbuf *m = nt_mbc.mb_top;
+ char *p;
+
+ /*
+ * MAC_key = concat(session_key, nt_response)
+ */
+ ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len;
+ ctx->ct_mackey = malloc(ctx->ct_mackeylen);
+ if (ctx->ct_mackey == NULL) {
+ ctx->ct_mackeylen = 0;
+ err = ENOMEM;
+ goto out;
+ }
+ p = ctx->ct_mackey;
+ memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
+ memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
+
+ /* OK, start signing! */
+ ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
+ }
+
+ err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
+ if (err)
+ goto out;
+
+ DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
+ if (ntstatus != 0)
+ err = EAUTH;
+
+out:
+ mb_done(&lm_mbc);
+ mb_done(&nt_mbc);
+
+ return (err);
+}
+
+/*
+ * SMB Session Setup, using NTLMv2 (and LMv2)
+ */
+int
+smb_ssnsetup_ntlm2(struct smb_ctx *ctx)
+{
+ struct mbdata lm_mbc, nt_mbc, ti_mbc;
+ int err;
+ uint32_t ntstatus;
+ uint16_t action = 0;
+
+ if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
+ /* Should not get here with... */
+ err = EINVAL;
+ goto out;
+ }
+
+ /* Make mb_done calls at out safe. */
+ bzero(&lm_mbc, sizeof (lm_mbc));
+ bzero(&nt_mbc, sizeof (nt_mbc));
+ bzero(&ti_mbc, sizeof (ti_mbc));
+
+ /* Build the NTLMv2 "target info" blob (as mbdata) */
+ err = ntlm_build_target_info(ctx, NULL, &ti_mbc);
+ if (err)
+ goto out;
+
+ /* Put the LMv2, NTLMv2 responses (as mbdata). */
+ err = ntlm_put_v2_responses(ctx, &ti_mbc, &lm_mbc, &nt_mbc);
+ if (err)
+ goto out;
+
+ /*
+ * If we negotiated signing, compute the MAC key
+ * and start signing messages, but only on the
+ * first non-null session login.
+ */
+ if ((ctx->ct_vcflags & SMBV_WILL_SIGN) &&
+ (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
+ struct mbuf *m = nt_mbc.mb_top;
+ char *p;
+
+ /*
+ * MAC_key = concat(session_key, nt_response)
+ */
+ ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len;
+ ctx->ct_mackey = malloc(ctx->ct_mackeylen);
+ if (ctx->ct_mackey == NULL) {
+ ctx->ct_mackeylen = 0;
+ err = ENOMEM;
+ goto out;
+ }
+ p = ctx->ct_mackey;
+ memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
+ memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
+
+ /* OK, start signing! */
+ ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
+ }
+
+ err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
+ if (err)
+ goto out;
+
+ DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
+ if (ntstatus != 0)
+ err = EAUTH;
+
+out:
+ mb_done(&ti_mbc);
+ mb_done(&lm_mbc);
+ mb_done(&nt_mbc);
+
+ return (err);
+}
+
+int
+smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
+{
+ struct mbdata send_mb, recv_mb;
+ int err;
+ uint32_t ntstatus;
+ uint16_t action = 0;
+
+ err = ssp_ctx_create_client(ctx, hint_mb);
+ if (err)
+ goto out;
+
+ bzero(&send_mb, sizeof (send_mb));
+ bzero(&recv_mb, sizeof (recv_mb));
+
+ /* NULL input indicates first call. */
+ err = ssp_ctx_next_token(ctx, NULL, &send_mb);
+ if (err)
+ goto out;
+
+ for (;;) {
+ err = smb__ssnsetup(ctx, &send_mb, &recv_mb,
+ &ntstatus, &action);
+ if (err)
+ goto out;
+ if (ntstatus == 0)
+ break; /* normal loop termination */
+ if (ntstatus != STATUS_MORE_PROCESSING_REQUIRED) {
+ err = EAUTH;
+ break;
+ }
+
+ /* middle calls get both in, out */
+ err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
+ if (err)
+ goto out;
+ }
+ DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
+
+ /* NULL output indicates last call. */
+ (void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
+
+out:
+ ssp_ctx_destroy(ctx);
+
+ return (err);
+}
+
+/*
+ * Session Setup function used for all the forms we support.
+ * To allow this sharing, the crypto stuff is computed by
+ * callers and passed in as mbdata chains. Also, the args
+ * have different meanings for extended security vs. old.
+ * Some may be used as either IN or OUT parameters.
+ *
+ * For NTLM (v1, v2), all parameters are inputs
+ * mbc1: [in] LM password hash
+ * mbc2: [in] NT password hash
+ * For Extended security (spnego)
+ * mbc1: [in] outgoing blob data
+ * mbc2: [out] received blob data
+ * For both forms, these are optional:
+ * statusp: [out] NT status
+ * actionp: [out] Logon Action (i.e. SMB_ACT_GUEST)
+ */
+static int
+smb__ssnsetup(struct smb_ctx *ctx,
+ struct mbdata *mbc1, struct mbdata *mbc2,
+ uint32_t *statusp, uint16_t *actionp)
+{
+ static const char NativeOS[] = "Solaris";
+ static const char LanMan[] = "NETSMB";
+ struct smb_sopt *sv = &ctx->ct_sopt;
+ struct smb_iods *is = &ctx->ct_iods;
+ struct smb_rq *rqp = NULL;
+ struct mbdata *mbp;
+ struct mbuf *m;
+ int err, uc;
+ uint32_t caps;
+ uint16_t bc, len1, len2, sblen;
+ uint8_t wc;
+
+ /*
+ * Some of the "capability" bits we offer will be copied
+ * from those offered by the server, with a mask applied.
+ * This is the mask of capabilies copied from the server.
+ * Some others get special handling below.
+ */
+ static const uint32_t caps_mask =
+ SMB_CAP_UNICODE |
+ SMB_CAP_LARGE_FILES |
+ SMB_CAP_NT_SMBS |
+ SMB_CAP_STATUS32 |
+ SMB_CAP_EXT_SECURITY;
+
+ caps = ctx->ct_sopt.sv_caps & caps_mask;
+ uc = ctx->ct_hflags2 & SMB_FLAGS2_UNICODE;
+
+ err = smb_rq_init(ctx, SMB_COM_SESSION_SETUP_ANDX, &rqp);
+ if (err)
+ goto out;
+
+ /*
+ * Build the SMB request.
+ */
+ mbp = &rqp->rq_rq;
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, 0xff); /* 0: AndXCommand */
+ mb_put_uint16le(mbp, 0); /* 1: AndXOffset */
+ mb_put_uint16le(mbp, sv->sv_maxtx); /* 2: MaxBufferSize */
+ mb_put_uint16le(mbp, sv->sv_maxmux); /* 3: MaxMpxCount */
+ mb_put_uint16le(mbp, 1); /* 4: VcNumber */
+ mb_put_uint32le(mbp, sv->sv_skey); /* 5,6: Session Key */
+
+ if (caps & SMB_CAP_EXT_SECURITY) {
+ len1 = mbc1 ? mbc1->mb_count : 0;
+ mb_put_uint16le(mbp, len1); /* 7: Sec. Blob Len */
+ mb_put_uint32le(mbp, 0); /* 8,9: reserved */
+ mb_put_uint32le(mbp, caps); /* 10,11: Capabilities */
+ smb_rq_wend(rqp); /* 12: Byte Count */
+ smb_rq_bstart(rqp);
+ if (mbc1 && mbc1->mb_top) {
+ mb_put_mbuf(mbp, mbc1->mb_top); /* sec. blob */
+ mbc1->mb_top = NULL; /* consumed */
+ }
+ /* mbc2 is required below */
+ if (mbc2 == NULL) {
+ err = EINVAL;
+ goto out;
+ }
+ } else {
+ len1 = mbc1 ? mbc1->mb_count : 0;
+ len2 = mbc2 ? mbc2->mb_count : 0;
+ mb_put_uint16le(mbp, len1); /* 7: LM pass. len */
+ mb_put_uint16le(mbp, len2); /* 8: NT pass. len */
+ mb_put_uint32le(mbp, 0); /* 9,10: reserved */
+ mb_put_uint32le(mbp, caps); /* 11,12: Capabilities */
+ smb_rq_wend(rqp); /* 13: Byte Count */
+ smb_rq_bstart(rqp);
+ if (mbc1 && mbc1->mb_top) {
+ mb_put_mbuf(mbp, mbc1->mb_top); /* LM password */
+ mbc1->mb_top = NULL; /* consumed */
+ }
+ if (mbc2 && mbc2->mb_top) {
+ mb_put_mbuf(mbp, mbc2->mb_top); /* NT password */
+ mbc2->mb_top = NULL; /* consumed */
+ }
+ mb_put_dstring(mbp, ctx->ct_user, uc);
+ mb_put_dstring(mbp, ctx->ct_domain, uc);
+ }
+ mb_put_dstring(mbp, NativeOS, uc);
+ mb_put_dstring(mbp, LanMan, uc);
+ smb_rq_bend(rqp);
+
+ err = smb_rq_internal(ctx, rqp);
+ if (err)
+ goto out;
+
+ if (statusp)
+ *statusp = rqp->rq_status;
+
+ /*
+ * If we have a real error, the response probably has
+ * no more data, so don't try to parse any more.
+ * Note: err=0, means rq_status is valid.
+ */
+ if (rqp->rq_status != 0 &&
+ rqp->rq_status != STATUS_MORE_PROCESSING_REQUIRED) {
+ goto out;
+ }
+
+ /*
+ * Parse the reply
+ */
+ uc = rqp->rq_hflags2 & SMB_FLAGS2_UNICODE;
+ is->is_smbuid = rqp->rq_uid;
+ mbp = &rqp->rq_rp;
+
+ err = mb_get_uint8(mbp, &wc);
+ if (err)
+ goto out;
+
+ err = EBADRPC; /* for any problems in this section */
+ if (caps & SMB_CAP_EXT_SECURITY) {
+ if (wc != 4)
+ goto out;
+ mb_get_uint16le(mbp, NULL); /* secondary cmd */
+ mb_get_uint16le(mbp, NULL); /* andxoffset */
+ mb_get_uint16le(mbp, actionp); /* action */
+ mb_get_uint16le(mbp, &sblen); /* sec. blob len */
+ mb_get_uint16le(mbp, &bc); /* byte count */
+ /*
+ * Get the security blob, after
+ * sanity-checking the length.
+ */
+ if (sblen == 0 || bc < sblen)
+ goto out;
+ err = mb_get_mbuf(mbp, sblen, &m);
+ if (err)
+ goto out;
+ mb_initm(mbc2, m);
+ mbc2->mb_count = sblen;
+ } else {
+ if (wc != 3)
+ goto out;
+ mb_get_uint16le(mbp, NULL); /* secondary cmd */
+ mb_get_uint16le(mbp, NULL); /* andxoffset */
+ mb_get_uint16le(mbp, actionp); /* action */
+ err = mb_get_uint16le(mbp, &bc); /* byte count */
+ if (err)
+ goto out;
+ }
+
+ /*
+ * Native OS, LANMGR, & Domain follow here.
+ * Parse these strings and store for later.
+ * If unicode, they should be aligned.
+ *
+ * Note that with Extended security, we may use
+ * multiple calls to this function. Only parse
+ * these strings on the last one (status == 0).
+ * Ditto for the CAP_LARGE work-around.
+ */
+ if (rqp->rq_status != 0)
+ goto out;
+
+ /* Ignore any parsing errors for these strings. */
+ err = mb_get_string(mbp, &ctx->ct_srv_OS, uc);
+ DPRINT("server OS: %s", err ? "?" : ctx->ct_srv_OS);
+ err = mb_get_string(mbp, &ctx->ct_srv_LM, uc);
+ DPRINT("server LM: %s", err ? "?" : ctx->ct_srv_LM);
+ /*
+ * There's sometimes a server domain folloing
+ * at this point, but we don't need it.
+ */
+
+ /* Success! (See Ignore any ... above) */
+ err = 0;
+
+ /*
+ * Windows systems don't suport CAP_LARGE_READX,WRITEX
+ * when signing is enabled, so adjust sv_caps.
+ */
+ if (ctx->ct_srv_OS &&
+ 0 == strncmp(ctx->ct_srv_OS, "Windows ", 8)) {
+ DPRINT("Server is Windows");
+ if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
+ DPRINT("disable CAP_LARGE_(r/w)");
+ ctx->ct_sopt.sv_caps &=
+ ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX);
+ }
+ }
+
+out:
+ if (rqp)
+ smb_rq_done(rqp);
+
+ return (err);
+}
diff --git a/usr/src/lib/libsmbfs/smb/ssp.c b/usr/src/lib/libsmbfs/smb/ssp.c
new file mode 100644
index 0000000000..f8433ba8e5
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/ssp.c
@@ -0,0 +1,395 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Security Provider glue
+ *
+ * Modeled after SSPI for now, only because we're currently
+ * using the Microsoft sample spnego code.
+ *
+ * ToDo: Port all of this to GSS-API plugins.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/mchain.h>
+
+#include "private.h"
+#include "charsets.h"
+#include "spnego.h"
+#include "derparse.h"
+#include "ssp.h"
+
+
+/*
+ * ssp_ctx_create_client
+ *
+ * This is the first function called for SMB "extended security".
+ * Here we select a security support provider (SSP), or mechanism,
+ * and build the security context used throughout authentication.
+ *
+ * Note that we receive a "hint" in the SMB Negotiate response
+ * that contains the list of mechanisms supported by the server.
+ * We use this to help us select a mechanism.
+ *
+ * With SSPI this would call:
+ * ssp->InitSecurityInterface()
+ * ssp->AcquireCredentialsHandle()
+ * ssp->InitializeSecurityContext()
+ * With GSS-API this will become:
+ * gss_import_name(... service_principal_name)
+ * gss_init_sec_context(), etc.
+ */
+int
+ssp_ctx_create_client(struct smb_ctx *ctx, struct mbdata *hint_mb)
+{
+ struct ssp_ctx *sp;
+ mbuf_t *m;
+ SPNEGO_MECH_OID oid;
+ int indx, rc;
+ int err = ENOTSUP; /* in case nothing matches */
+
+ sp = malloc(sizeof (*sp));
+ if (sp == NULL)
+ return (ENOMEM);
+ bzero(sp, sizeof (*sp));
+ ctx->ct_ssp_ctx = sp;
+ sp->smb_ctx = ctx;
+
+ /*
+ * Parse the SPNEGO "hint" to get the server's list of
+ * supported mechanisms. If the "hint" is empty,
+ * assume NTLMSSP. (Or could use "raw NTLMSSP")
+ */
+ m = hint_mb->mb_top;
+ if (m == NULL)
+ goto use_ntlm;
+ rc = spnegoInitFromBinary((uchar_t *)m->m_data, m->m_len,
+ &sp->sp_hint);
+ if (rc) {
+ DPRINT("parse hint, rc %d", rc);
+ goto use_ntlm;
+ }
+
+ /*
+ * Did the server offer Kerberos?
+ * Either spec. OID or legacy is OK,
+ * but have to remember what we got.
+ */
+ oid = spnego_mech_oid_NotUsed;
+ if (0 == spnegoIsMechTypeAvailable(sp->sp_hint,
+ spnego_mech_oid_Kerberos_V5, &indx))
+ oid = spnego_mech_oid_Kerberos_V5;
+ else if (0 == spnegoIsMechTypeAvailable(sp->sp_hint,
+ spnego_mech_oid_Kerberos_V5_Legacy, &indx))
+ oid = spnego_mech_oid_Kerberos_V5_Legacy;
+ if (oid != spnego_mech_oid_NotUsed) {
+ /*
+ * Yes! Server offers Kerberos.
+ * Try to init our krb5 mechanism.
+ * It will fail if the calling user
+ * does not have krb5 credentials.
+ */
+ sp->sp_mech = oid;
+ err = krb5ssp_init_client(sp);
+ if (err == 0) {
+ DPRINT("using Kerberos");
+ return (0);
+ }
+ /* else fall back to NTLMSSP */
+ }
+
+ /*
+ * Did the server offer NTLMSSP?
+ */
+ if (0 == spnegoIsMechTypeAvailable(sp->sp_hint,
+ spnego_mech_oid_NTLMSSP, &indx)) {
+ /*
+ * OK, we'll use NTLMSSP
+ */
+ use_ntlm:
+ sp->sp_mech = spnego_mech_oid_NTLMSSP;
+ err = ntlmssp_init_client(sp);
+ if (err == 0) {
+ DPRINT("using NTLMSSP");
+ return (0);
+ }
+ }
+
+ /* No supported mechanisms! */
+ return (err);
+}
+
+
+/*
+ * ssp_ctx_destroy
+ *
+ * Dispatch to the mechanism-specific destroy.
+ */
+void
+ssp_ctx_destroy(struct smb_ctx *ctx)
+{
+ ssp_ctx_t *sp;
+
+ sp = ctx->ct_ssp_ctx;
+ ctx->ct_ssp_ctx = NULL;
+
+ if (sp == NULL)
+ return;
+
+ if (sp->sp_destroy != NULL)
+ (sp->sp_destroy)(sp);
+
+ if (sp->sp_hint != NULL)
+ spnegoFreeData(sp->sp_hint);
+
+ free(sp);
+}
+
+
+/*
+ * ssp_ctx_next_token
+ *
+ * This is the function called to generate the next token to send,
+ * given a token just received, using the selected back-end method.
+ * The back-end method is called a security service provider (SSP).
+ *
+ * This is also called to generate the first token to send
+ * (when called with caller_in == NULL) and to handle the last
+ * token received (when called with caller_out == NULL).
+ * See caller: smb_ssnsetup_spnego
+ *
+ * Note that if the back-end SSP "next token" function ever
+ * returns an error, the conversation ends, and there are
+ * no further calls to this function for this context.
+ *
+ * General outline of this funcion:
+ * if (caller_in)
+ * Unwrap caller_in spnego blob,
+ * store payload in body_in
+ * Call back-end SSP "next token" method (body_in, body_out)
+ * if (caller_out)
+ * Wrap returned body_out in spnego,
+ * store in caller_out
+ *
+ * With SSPI this would call:
+ * ssp->InitializeSecurityContext()
+ * With GSS-API this will become:
+ * gss_init_sec_context()
+ */
+int
+ssp_ctx_next_token(struct smb_ctx *ctx,
+ struct mbdata *caller_in,
+ struct mbdata *caller_out)
+{
+ struct mbdata body_in, body_out;
+ SPNEGO_TOKEN_HANDLE stok_in, stok_out;
+ SPNEGO_NEGRESULT result;
+ ssp_ctx_t *sp;
+ struct mbuf *m;
+ ulong_t toklen;
+ int err, rc;
+
+ bzero(&body_in, sizeof (body_in));
+ bzero(&body_out, sizeof (body_out));
+ stok_out = stok_in = NULL;
+ sp = ctx->ct_ssp_ctx;
+
+ /*
+ * If we have an spnego input token, parse it,
+ * extract the payload for the back-end SSP.
+ */
+ if (caller_in != NULL) {
+
+ /*
+ * Let the spnego code parse it.
+ */
+ m = caller_in->mb_top;
+ rc = spnegoInitFromBinary((uchar_t *)m->m_data,
+ m->m_len, &stok_in);
+ if (rc) {
+ DPRINT("parse reply, rc %d", rc);
+ err = EBADRPC;
+ goto out;
+ }
+ /* Note: Allocated stok_in */
+
+ /*
+ * Now get the payload. Two calls:
+ * first gets the size, 2nd the data.
+ *
+ * Expect SPNEGO_E_BUFFER_TOO_SMALL here,
+ * but if the payload is missing, we'll
+ * get SPNEGO_E_ELEMENT_UNAVAILABLE.
+ */
+ rc = spnegoGetMechToken(stok_in, NULL, &toklen);
+ switch (rc) {
+ case SPNEGO_E_ELEMENT_UNAVAILABLE:
+ toklen = 0;
+ break;
+ case SPNEGO_E_BUFFER_TOO_SMALL:
+ /* have toklen */
+ break;
+ default:
+ DPRINT("GetMechTok1, rc %d", rc);
+ err = EBADRPC;
+ goto out;
+ }
+ err = mb_init(&body_in, (size_t)toklen);
+ if (err)
+ goto out;
+ m = body_in.mb_top;
+ if (toklen > 0) {
+ rc = spnegoGetMechToken(stok_in,
+ (uchar_t *)m->m_data, &toklen);
+ if (rc) {
+ DPRINT("GetMechTok2, rc %d", rc);
+ err = EBADRPC;
+ goto out;
+ }
+ body_in.mb_count = m->m_len = (size_t)toklen;
+ }
+ }
+
+ /*
+ * Call the back-end security provider (SSP) to
+ * handle the received token (if present) and
+ * generate an output token (if requested).
+ */
+ err = sp->sp_nexttok(sp,
+ caller_in ? &body_in : NULL,
+ caller_out ? &body_out : NULL);
+ if (err)
+ goto out;
+
+ /*
+ * Wrap the outgoing body if requested,
+ * either negTokenInit on first call, or
+ * negTokenTarg on subsequent calls.
+ */
+ if (caller_out != NULL) {
+ m = body_out.mb_top;
+
+ if (caller_in == NULL) {
+ /*
+ * This is the first call, so create a
+ * negTokenInit.
+ */
+ rc = spnegoCreateNegTokenInit(
+ sp->sp_mech, 0,
+ (uchar_t *)m->m_data, m->m_len,
+ NULL, 0, &stok_out);
+ /* Note: allocated stok_out */
+ } else {
+ /*
+ * Note: must pass spnego_mech_oid_NotUsed,
+ * instead of sp->sp_mech so that the spnego
+ * code will not marshal a mech OID list.
+ * The mechanism is determined at this point,
+ * and some servers won't parse an unexpected
+ * mech. OID list in a negTokenTarg
+ */
+ rc = spnegoCreateNegTokenTarg(
+ spnego_mech_oid_NotUsed,
+ spnego_negresult_NotUsed,
+ (uchar_t *)m->m_data, m->m_len,
+ NULL, 0, &stok_out);
+ /* Note: allocated stok_out */
+ }
+ if (rc) {
+ DPRINT("CreateNegTokenX, rc 0x%x", rc);
+ err = EBADRPC;
+ goto out;
+ }
+
+ /*
+ * Copy binary from stok_out to caller_out
+ * Two calls: get the size, get the data.
+ */
+ rc = spnegoTokenGetBinary(stok_out, NULL, &toklen);
+ if (rc != SPNEGO_E_BUFFER_TOO_SMALL) {
+ DPRINT("GetBinary1, rc 0x%x", rc);
+ err = EBADRPC;
+ goto out;
+ }
+ err = mb_init(caller_out, (size_t)toklen);
+ if (err)
+ goto out;
+ m = caller_out->mb_top;
+ rc = spnegoTokenGetBinary(stok_out,
+ (uchar_t *)m->m_data, &toklen);
+ if (rc) {
+ DPRINT("GetBinary2, rc 0x%x", rc);
+ err = EBADRPC;
+ goto out;
+ }
+ caller_out->mb_count = m->m_len = (size_t)toklen;
+ } else {
+ /*
+ * caller_out == NULL, so this is the "final" call.
+ * Get final SPNEGO result from the INPUT token.
+ */
+ rc = spnegoGetNegotiationResult(stok_in, &result);
+ if (rc) {
+ DPRINT("rc 0x%x", rc);
+ err = EBADRPC;
+ goto out;
+ }
+ DPRINT("spnego result: 0x%x", result);
+ if (result != spnego_negresult_success) {
+ err = EAUTH;
+ goto out;
+ }
+ }
+ err = 0;
+
+out:
+ mb_done(&body_in);
+ mb_done(&body_out);
+ spnegoFreeData(stok_in);
+ spnegoFreeData(stok_out);
+
+ return (err);
+}
diff --git a/usr/src/lib/libsmbfs/smb/ssp.h b/usr/src/lib/libsmbfs/smb/ssp.h
new file mode 100644
index 0000000000..7370fffc9c
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/ssp.h
@@ -0,0 +1,56 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SSP_H
+#define _SSP_H
+
+/*
+ * Security Support Package (SSP) interface,
+ * somewhat modeled on Microsoft's SSPI.
+ *
+ * XXX: Yes, should use GSS-API. See ssp.c
+ */
+
+typedef struct ssp_ctx {
+ struct smb_ctx *smb_ctx;
+
+ SPNEGO_TOKEN_HANDLE sp_hint;
+ SPNEGO_MECH_OID sp_mech;
+
+ /*
+ * Now the mechanism-specific stuff.
+ */
+ int (*sp_nexttok)(struct ssp_ctx *,
+ struct mbdata *, struct mbdata *);
+ void (*sp_destroy)(struct ssp_ctx *);
+ void *sp_private;
+
+} ssp_ctx_t;
+
+int ntlmssp_init_client(ssp_ctx_t *);
+int krb5ssp_init_client(ssp_ctx_t *);
+
+#endif /* _SSP_H */
diff --git a/usr/src/lib/libsmbfs/smb/subr.c b/usr/src/lib/libsmbfs/smb/subr.c
index 36a3c30ed9..0b81606f2c 100644
--- a/usr/src/lib/libsmbfs/smb/subr.c
+++ b/usr/src/lib/libsmbfs/smb/subr.c
@@ -49,15 +49,13 @@
#include <netsmb/netbios.h>
#include <netsmb/smb_lib.h>
#include <netsmb/nb_lib.h>
-#include <cflib.h>
+
#include <err.h>
-uid_t real_uid, eff_uid;
+#include "private.h"
static int smblib_initialized;
-struct rcfile *smb_rc;
-
int
smb_lib_init(void)
{
@@ -74,6 +72,23 @@ smb_lib_init(void)
return (0);
}
+int
+smb_getlocalname(char **namepp)
+{
+ char buf[SMBIOC_MAX_NAME], *cp;
+
+ if (gethostname(buf, sizeof (buf)) != 0)
+ return (errno);
+ cp = strchr(buf, '.');
+ if (cp)
+ *cp = '\0';
+ cp = strdup(buf);
+ if (cp == NULL)
+ return (ENOMEM);
+ *namepp = cp;
+ return (0);
+}
+
/*
* Private version of strerror(3C) that
* knows our special error codes.
@@ -162,93 +177,6 @@ smb_printb(char *dest, int flags, const struct smb_bitname *bnp) {
return (dest);
}
-extern int home_nsmbrc;
-
-#ifdef DEBUG
-#include "queue.h"
-#include "rcfile_priv.h"
-
-struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname);
-struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname);
-
-void
-dump_props(char *where)
-{
- struct rcsection *rsp = NULL;
- struct rckey *rkp = NULL;
-
- printf("Settings %s\n", where);
- SLIST_FOREACH(rsp, &smb_rc->rf_sect, rs_next) {
- printf("section=%s\n", rsp->rs_name);
- fflush(stdout);
-
- SLIST_FOREACH(rkp, &rsp->rs_keys, rk_next) {
- printf(" key=%s, value=%s\n",
- rkp->rk_name, rkp->rk_value);
- fflush(stdout);
- }
- }
-}
-#endif
-
-/*
- * first read ~/.smbrc, next try to merge SMB_CFG_FILE - if that fails
- * because SMB_CFG_FILE doesn't exist, try to merge OLD_SMB_CFG_FILE
- */
-int
-smb_open_rcfile(struct smb_ctx *ctx)
-{
- char *home, *fn;
- int error, len;
-
- smb_rc = NULL;
-#ifdef DEPRECATED
- fn = SMB_CFG_FILE;
- error = rc_merge(fn, &smb_rc);
- if (error == ENOENT) {
- /*
- * OK, try to read a config file in the old location.
- */
- fn = OLD_SMB_CFG_FILE;
- error = rc_merge(fn, &smb_rc);
- }
-#endif
- fn = "/usr/sbin/sharectl get smbfs";
- error = rc_merge_pipe(fn, &smb_rc);
- if (error != 0 && error != ENOENT)
- fprintf(stderr, dgettext(TEXT_DOMAIN,
- "Can't open %s: %s\n"), fn, smb_strerror(errno));
-#ifdef DEBUG
- if (smb_debug)
- dump_props("after reading global repository");
-#endif
-
- home = getenv("HOME");
- if (home == NULL && ctx && ctx->ct_home)
- home = ctx->ct_home;
- if (home) {
- len = strlen(home) + 20;
- fn = malloc(len);
- snprintf(fn, len, "%s/.nsmbrc", home);
- home_nsmbrc = 1;
- error = rc_merge(fn, &smb_rc);
- if (error != 0 && error != ENOENT) {
- fprintf(stderr, dgettext(TEXT_DOMAIN,
- "Can't open %s: %s\n"), fn, smb_strerror(errno));
- }
- free(fn);
- }
- home_nsmbrc = 0;
-#ifdef DEBUG
- if (smb_debug)
- dump_props("after reading user settings");
-#endif
- if (smb_rc == NULL) {
- return (ENOENT);
- }
- return (0);
-}
-
void
smb_simplecrypt(char *dst, const char *src)
{
@@ -303,6 +231,79 @@ smb_simpledecrypt(char *dst, const char *src)
return (0);
}
+/*
+ * Number of seconds between 1970 and 1601 year
+ * (134774 * 24 * 60 * 60)
+ */
+static const uint64_t DIFF1970TO1601 = 11644473600ULL;
+
+void
+smb_time_local2server(struct timeval *tsp, int tzoff, long *seconds)
+{
+ *seconds = tsp->tv_sec - tzoff * 60;
+}
+
+void
+smb_time_server2local(ulong_t seconds, int tzoff, struct timeval *tsp)
+{
+ tsp->tv_sec = seconds + tzoff * 60;
+ tsp->tv_usec = 0;
+}
+
+/*
+ * Time from server comes as UTC, so no need to use tz
+ */
+/*ARGSUSED*/
+void
+smb_time_NT2local(uint64_t nsec, int tzoff, struct timeval *tsp)
+{
+ smb_time_server2local(nsec / 10000000 - DIFF1970TO1601, 0, tsp);
+}
+
+/*ARGSUSED*/
+void
+smb_time_local2NT(struct timeval *tsp, int tzoff, uint64_t *nsec)
+{
+ long seconds;
+
+ smb_time_local2server(tsp, 0, &seconds);
+ *nsec = (((uint64_t)(seconds) & ~1) + DIFF1970TO1601) *
+ (uint64_t)10000000;
+}
+
+void
+smb_hexdump(const void *buf, int len)
+{
+ const uchar_t *p = buf;
+ int ofs = 0;
+
+ while (len--) {
+ if (ofs % 16 == 0)
+ fprintf(stderr, "%02X: ", ofs);
+ fprintf(stderr, "%02x ", *p++);
+ ofs++;
+ if (ofs % 16 == 0)
+ fprintf(stderr, "\n");
+ }
+ if (ofs % 16 != 0)
+ fprintf(stderr, "\n");
+}
+
+void
+dprint(const char *fname, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if (smb_debug) {
+ fprintf(stderr, "%s: ", fname);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ }
+ va_end(ap);
+}
+
#undef __progname
char *__progname = NULL;
diff --git a/usr/src/lib/libsmbfs/smb/ui-sun.c b/usr/src/lib/libsmbfs/smb/ui-sun.c
index 7512d2c964..69aa3161ab 100644
--- a/usr/src/lib/libsmbfs/smb/ui-sun.c
+++ b/usr/src/lib/libsmbfs/smb/ui-sun.c
@@ -22,8 +22,6 @@
* @APPLE_LICENSE_HEADER_END@
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Routines for interacting with the user to get credentials
* (workgroup/domain, username, password, etc.)
@@ -38,11 +36,11 @@
#include <ctype.h>
#include <netsmb/smb_lib.h>
-#include <netsmb/smb_keychain.h>
+#include "private.h"
+#include "ntlm.h"
+#if 0 /* not yet */
#define MAXLINE 127
-#define MAXPASSWD 256 /* from libc:getpass */
-
static void
smb_tty_prompt(char *prmpt,
char *buf, size_t buflen)
@@ -72,78 +70,69 @@ smb_tty_prompt(char *prmpt,
/* Use input as new value. */
strncpy(buf, temp, buflen);
}
+#endif /* not yet */
+/*
+ * Prompt for a new password after auth. failure.
+ * (and maybe new user+domain, but not yet)
+ */
int
-smb_get_authentication(
- char *dom, size_t domlen,
- char *usr, size_t usrlen,
- char *passwd, size_t passwdlen,
- const char *systemname, struct smb_ctx *ctx)
+smb_get_authentication(struct smb_ctx *ctx)
{
char *npw;
- int error, i, kcask, kcerr;
+ int err;
- if (ctx->ct_flags & SMBCF_KCFOUND || ctx->ct_flags & SMBCF_KCBAD) {
- ctx->ct_flags &= ~SMBCF_KCFOUND;
- } else {
- ctx->ct_flags &= ~(SMBCF_KCFOUND | SMBCF_KCDOMAIN);
+ /*
+ * If we're getting a password, we must be doing
+ * some kind of NTLM, possibly after a failure to
+ * authenticate using Kerberos. Turn off krb5.
+ */
+ ctx->ct_authflags &= ~SMB_AT_KRB5;
- /*
- * 1st: try lookup using system name
- */
- kcerr = smbfs_keychain_chk(systemname, usr);
- if (!kcerr) {
- /*
- * Need passwd to be not empty for existing logic.
- * The string here is arbitrary (a debugging hint)
- * and will be replaced in the driver by the real
- * password from the keychain.
- */
- strcpy(passwd, "$KC_SYSTEM");
- ctx->ct_flags |= SMBCF_KCFOUND;
- if (smb_debug) {
- printf("found keychain entry for"
- " server/user: %s/%s\n",
- systemname, usr);
- }
- return (0);
- }
+ if (ctx->ct_flags & SMBCF_KCFOUND) {
+ /* Tried a keychain hash and failed. */
+ /* XXX: delete the KC entry? */
+ ctx->ct_flags |= SMBCF_KCBAD;
+ }
+
+ if (ctx->ct_flags & SMBCF_NOPWD)
+ return (ENOTTY);
+
+ if (isatty(STDIN_FILENO)) {
+
+ /* Need command-line prompting. */
+ npw = getpassphrase(dgettext(TEXT_DOMAIN, "Password:"));
+ if (npw == NULL)
+ return (EINTR);
+ memset(ctx->ct_password, 0, sizeof (ctx->ct_password));
+ strlcpy(ctx->ct_password, npw, sizeof (ctx->ct_password));
+ } else {
/*
- * 2nd: try lookup using domain name
+ * XXX: Ask the user for help, possibly via
+ * GNOME dbus or some such... (todo).
*/
- kcerr = smbfs_keychain_chk(dom, usr);
- if (!kcerr) {
- /* Need passwd to be not empty... (see above) */
- strcpy(passwd, "$KC_DOMAIN");
- ctx->ct_flags |= (SMBCF_KCFOUND | SMBCF_KCDOMAIN);
- if (smb_debug) {
- printf("found keychain entry for"
- " domain/user: %s/%s\n",
- dom, usr);
- }
- return (0);
- }
- }
-
- if (isatty(STDIN_FILENO)) { /* need command-line prompting? */
- if (passwd && passwd[0] == '\0') {
- npw = getpassphrase(dgettext(TEXT_DOMAIN, "Password:"));
- strncpy(passwd, npw, passwdlen);
- }
- return (0);
+ smb_error(dgettext(TEXT_DOMAIN,
+ "Cannot prompt for a password when input is redirected."), 0);
+ return (ENOTTY);
}
/*
- * XXX: Ask the user for help, possibly via
- * GNOME dbus or some such... (todo).
+ * Recompute the password hashes.
*/
- smb_error(dgettext(TEXT_DOMAIN,
- "Cannot prompt for a password when input is redirected."), 0);
+ if (ctx->ct_password[0]) {
+ err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password);
+ if (err != 0)
+ return (err);
+ err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password);
+ if (err != 0)
+ return (err);
+ }
- return (ENOTTY);
+ return (0);
}
+/*ARGSUSED*/
int
smb_browse(struct smb_ctx *ctx, int anon)
{
diff --git a/usr/src/lib/libsmbfs/smb/utf_str.c b/usr/src/lib/libsmbfs/smb/utf_str.c
index e80b1180f2..f53189e64c 100644
--- a/usr/src/lib/libsmbfs/smb/utf_str.c
+++ b/usr/src/lib/libsmbfs/smb/utf_str.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -205,3 +205,67 @@ convert_utf8_to_ucs2xx(iconv_t cd, const char *utf8_string)
return (obuf);
}
+
+
+/*
+ * A simple wrapper around u8_textprep_str() that returns the Unicode
+ * upper-case version of some string. Returns memory from malloc.
+ * Borrowed from idmapd.
+ */
+static char *
+utf8_str_to_upper_or_lower(const char *s, int upper_lower)
+{
+ char *res = NULL;
+ char *outs;
+ size_t inlen, outlen, inbleft, outbleft;
+ int rc, err;
+
+ /*
+ * u8_textprep_str() does not allocate memory. The input and
+ * output buffers may differ in size (though that would be more
+ * likely when normalization is done). We have to loop over it...
+ *
+ * To improve the chances that we can avoid looping we add 10
+ * bytes of output buffer room the first go around.
+ */
+ inlen = inbleft = strlen(s);
+ outlen = outbleft = inlen + 10;
+ if ((res = malloc(outlen)) == NULL)
+ return (NULL);
+ outs = res;
+
+ while ((rc = u8_textprep_str((char *)s, &inbleft, outs,
+ &outbleft, upper_lower, U8_UNICODE_LATEST, &err)) < 0 &&
+ err == E2BIG) {
+ if ((res = realloc(res, outlen + inbleft)) == NULL)
+ return (NULL);
+ /* adjust input/output buffer pointers */
+ s += (inlen - inbleft);
+ outs = res + outlen - outbleft;
+ /* adjust outbleft and outlen */
+ outlen += inbleft;
+ outbleft += inbleft;
+ }
+
+ if (rc < 0) {
+ free(res);
+ res = NULL;
+ return (NULL);
+ }
+
+ res[outlen - outbleft] = '\0';
+
+ return (res);
+}
+
+char *
+utf8_str_toupper(const char *s)
+{
+ return (utf8_str_to_upper_or_lower(s, U8_TEXTPREP_TOUPPER));
+}
+
+char *
+utf8_str_tolower(const char *s)
+{
+ return (utf8_str_to_upper_or_lower(s, U8_TEXTPREP_TOLOWER));
+}
diff --git a/usr/src/pkgdefs/SUNWsmbfsu/prototype_com b/usr/src/pkgdefs/SUNWsmbfsu/prototype_com
index 985c9cecb4..e1a79c3742 100644
--- a/usr/src/pkgdefs/SUNWsmbfsu/prototype_com
+++ b/usr/src/pkgdefs/SUNWsmbfsu/prototype_com
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# This required package information file contains a list of package contents.
@@ -66,3 +66,5 @@ d none usr/lib/mdb/kvm 755 root sys
d none usr/lib/security 755 root bin
f none usr/lib/security/pam_smbfs_login.so.1 755 root bin
s none usr/lib/security/pam_smbfs_login.so=pam_smbfs_login.so.1
+d none usr/lib/smbfs 755 root bin
+f none usr/lib/smbfs/smbiod 555 root bin
diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386
index d284303d1c..c6258111ff 100644
--- a/usr/src/pkgdefs/etc/exception_list_i386
+++ b/usr/src/pkgdefs/etc/exception_list_i386
@@ -1128,6 +1128,9 @@ usr/include/sys/sdcard/sda_ioctl.h i386
#
# libsmbfs is private
#
+usr/include/netsmb i386
+usr/include/netsmb/smbfs_acl.h i386
+usr/include/netsmb/smbfs_api.h i386
usr/lib/libsmbfs.so i386
usr/lib/amd64/libsmbfs.so i386
usr/lib/llib-lsmbfs i386
diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc
index dc12bf72ae..0d4b524242 100644
--- a/usr/src/pkgdefs/etc/exception_list_sparc
+++ b/usr/src/pkgdefs/etc/exception_list_sparc
@@ -1206,6 +1206,9 @@ usr/include/sys/sdcard/sda_ioctl.h sparc
#
# libsmbfs is private
#
+usr/include/netsmb sparc
+usr/include/netsmb/smbfs_acl.h sparc
+usr/include/netsmb/smbfs_api.h sparc
usr/lib/libsmbfs.so sparc
usr/lib/sparcv9/libsmbfs.so sparc
usr/lib/llib-lsmbfs sparc
diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh
index c9258350af..a2ada6d6eb 100644
--- a/usr/src/tools/scripts/bfu.sh
+++ b/usr/src/tools/scripts/bfu.sh
@@ -7490,10 +7490,16 @@ mondo_loop() {
rm -f $root/usr/sbin/pfild
# Remove nsmb and smbfs modules from old locations
- # Also remove new locations of kmdb stuff for BFU
+ # Also remove new locations of moved stuff for BFU
# from newer to older build ("backward BFU").
# These will be reinstalled from the archive.
# old locations:
+ rm -f $root/kernel/drv/nsmb
+ rm -f $root/kernel/drv/amd64/nsmb
+ rm -f $root/kernel/drv/sparcv9/nsmb
+ rm -f $root/kernel/fs/smbfs
+ rm -f $root/kernel/fs/amd64/smbfs
+ rm -f $root/kernel/fs/sparcv9/smbfs
rm -f $root/kernel/kmdb/nsmb
rm -f $root/kernel/kmdb/smbfs
rm -f $root/kernel/kmdb/amd64/nsmb
@@ -7504,6 +7510,12 @@ mondo_loop() {
rm -f $usr/kernel/sys/amd64/smbfs
rm -f $usr/kernel/sys/sparcv9/smbfs
# new locations:
+ rm -f $usr/kernel/drv/nsmb
+ rm -f $usr/kernel/drv/amd64/nsmb
+ rm -f $usr/kernel/drv/sparcv9/nsmb
+ rm -f $usr/kernel/fs/smbfs
+ rm -f $usr/kernel/fs/amd64/smbfs
+ rm -f $usr/kernel/fs/sparcv9/smbfs
rm -f $usr/kernel/kmdb/nsmb
rm -f $usr/kernel/kmdb/smbfs
rm -f $usr/kernel/kmdb/amd64/nsmb
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index c99d41bb4e..4201a1c0f3 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1233,8 +1233,8 @@ UFS_OBJS += ufs_alloc.o ufs_bmap.o ufs_dir.o ufs_xattr.o \
lufs_log.o lufs_map.o lufs_top.o lufs_debug.o
VSCAN_OBJS += vscan_drv.o vscan_svc.o vscan_door.o
-NSMB_OBJS += smb_conn.o smb_crypt.o smb_dev.o smb_iod.o \
- smb_rq.o smb_smb.o smb_tran.o smb_trantcp.o \
+NSMB_OBJS += smb_conn.o smb_dev.o smb_iod.o smb_rq.o \
+ smb_sign.o smb_smb.o smb_tran.o smb_trantcp.o \
smb_usr.o smb_subrs.o subr_mchain.o smb_pass.o
SMBFS_OBJS += smbfs_vfsops.o smbfs_vnops.o smbfs_node.o \
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
index 6c39fa5a22..61c06a738c 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
@@ -18,18 +18,18 @@
\
\ CDDL HEADER END
\
+
\
-\ Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+\ Copyright 2009 Sun Microsystems, Inc. All rights reserved.
\ Use is subject to license terms.
\
-#pragma ident "%Z%%M% %I% %E% SMI"
-
\
\ offsets.in: input file for the ctfstabs program,
\ used to generate ioc_check.h - which verifies
\ invariance of our ioctl data structures across
\ 32-bit and 64-bit ABIs.
+\
#ifndef _GENASSYM
#define _GENASSYM
@@ -43,56 +43,73 @@
#include <netsmb/netbios.h>
#include <netsmb/smb_dev.h>
-sockaddr_any SIZEOF_SOCKADDR_ANY
-
-sockaddr_in SIZEOF_SOCKADDR_IN
-
-sockaddr_nb SIZEOF_SOCKADDR_NB
-
-smbioc_ossn SIZEOF_SMBIOC_OSSN
- ioc_server
- ioc_local
- ioc_localcs
- ioc_servercs
- ioc_srvname
- ioc_user
- ioc_workgroup
- ioc_password IOC_SSN_PASSWD
- ioc_opt IOC_SSN_OPT
- ioc_timeout
- ioc_retrycount
- ioc_owner IOC_SSN_OWNER
- ioc_group IOC_SSN_GROUP
- ioc_mode IOC_SSN_MODE
- ioc_rights IOC_SSN_RIGHTS
- ioc_intoklen
- ioc_outtoklen
- _ioc_intok
- _ioc_outtok
-
-smbioc_oshare SIZEOF_SMBIOC_OSHARE
- ioc_share
- ioc_password IOC_SH_PASSWD
- ioc_opt IOC_SH_OPT
- ioc_stype
- ioc_owner IOC_SH_OWNER
- ioc_group IOC_SH_GROUP
- ioc_mode IOC_SH_MODE
- ioc_rights IOC_SH_RIGHTS
+smbioc_sockaddr
+
+smbioc_ssn_ident
+ id_srvaddr
+ id_domain
+ id_user
+
+smbioc_ossn
+ ssn_vopt
+ ssn_owner
+ ssn_id
+ ssn_srvname
+
+smbioc_oshare
+ sh_pwlen
+ sh_name
+ sh_pass
+ sh_type_req
+ sh_type_ret
+
+smbioc_tcon
+ tc_flags
+ tc_opt
+ tc_sh
+
+smb_sopt
+ sv_proto
+ sv_sm
+ sv_tz
+ sv_maxmux
+ sv_maxvcs
+ sv_rawmode
+ sv_maxtx
+ sv_maxraw
+ sv_skey
+ sv_caps
+
+smb_iods
+ is_tran_fd
+ is_vcflags
+ is_hflags
+ is_hflags2
+ is_smbuid
+ is_next_mid
+ is_txmax
+ is_rwmax
+ is_rxmax
+ is_wxmax
+ is_ssn_key
+ is_next_seq
+ is_u_maclen
+ is_u_mackey
+
+smbioc_ssn_work
+ wk_iods
+ wk_sopt
+ wk_out_state
smbioc_rq SIZEOF_SMBIOC_RQ
ioc_cmd
- ioc_twc
- ioc_tbc
- ioc_rpbufsz
- ioc_rwc
- ioc_rbc
ioc_errclass IOC_RQ_ERRCLASS
ioc_serror IOC_RQ_SERROR
ioc_error IOC_RQ_ERROR
- _ioc_twords
- _ioc_tbytes
- _ioc_rpbuf
+ ioc_tbufsz
+ ioc_rbufsz
+ _ioc_tbuf
+ _ioc_rbuf
smbioc_t2rq SIZEOF_SMBIOC_T2RQ
ioc_setup
@@ -116,12 +133,6 @@ smbioc_flags SIZEOF_SMBIOC_FLAGS
ioc_mask
ioc_flags
-smbioc_lookup SIZEOF_SMBIOC_LOOKUP
- ioc_level IOC_LOOK_LEVEL
- ioc_flags IOC_LOOK_FLAGS
- ioc_sh
- ioc_ssn
-
smbioc_rw SIZEOF_SMBIOC_RW
ioc_fh
ioc_cnt
@@ -129,6 +140,8 @@ smbioc_rw SIZEOF_SMBIOC_RW
_ioc_base
smbioc_pk SIZEOF_SMBIOC_PK
+ pk_uid
pk_dom
pk_usr
- pk_pass
+ pk_lmhash
+ pk_nthash
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
index 42475923d3..102b57fe28 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
@@ -32,7 +32,7 @@
* $Id: smb_conn.c,v 1.27.166.1 2005/05/27 02:35:29 lindak Exp $
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -57,6 +57,7 @@
#include <sys/cmn_err.h>
#include <sys/thread.h>
#include <sys/atomic.h>
+#include <sys/u8_textprep.h>
#ifdef APPLE
#include <sys/smb_apple.h>
@@ -72,7 +73,6 @@
#include <netsmb/smb_pass.h>
static struct smb_connobj smb_vclist;
-static uint_t smb_vcnext = 0; /* next unique id for VC */
void smb_co_init(struct smb_connobj *cp, int level, char *objname);
void smb_co_done(struct smb_connobj *cp);
@@ -80,19 +80,12 @@ void smb_co_hold(struct smb_connobj *cp);
void smb_co_rele(struct smb_connobj *cp);
void smb_co_kill(struct smb_connobj *cp);
-#ifdef APPLE
-static void smb_sm_lockvclist(void);
-static void smb_sm_unlockvclist(void);
-#endif
-
static void smb_vc_free(struct smb_connobj *cp);
static void smb_vc_gone(struct smb_connobj *cp);
static void smb_share_free(struct smb_connobj *cp);
static void smb_share_gone(struct smb_connobj *cp);
-/* smb_dup_sockaddr moved to smb_tran.c */
-
int
smb_sm_init(void)
{
@@ -125,401 +118,7 @@ smb_sm_done(void)
smb_co_done(&smb_vclist);
}
-/*
- * Find a VC identified by the info in vcspec,
- * and return it with a "hold", but not locked.
- */
-/*ARGSUSED*/
-static int
-smb_sm_lookupvc(
- struct smb_vcspec *vcspec,
- struct smb_cred *scred,
- struct smb_vc **vcpp)
-{
- struct smb_connobj *co;
- struct smb_vc *vcp;
- zoneid_t zoneid = getzoneid();
-
- ASSERT(MUTEX_HELD(&smb_vclist.co_lock));
-
- /* var, head, next_field */
- SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
- vcp = CPTOVC(co);
-
- /*
- * Some things we can check without
- * holding the lock (those that are
- * set at creation and never change).
- */
-
- /* VCs in other zones are invisibile. */
- if (vcp->vc_zoneid != zoneid)
- continue;
-
- /* Also segregate by owner. */
- if (vcp->vc_uid != vcspec->owner)
- continue;
-
- /* XXX: we ignore the group. Remove vc_gid? */
-
- /* server */
- if (smb_cmp_sockaddr(vcp->vc_paddr, vcspec->sap))
- continue;
-
- /* domain+user */
- if (strcmp(vcp->vc_domain, vcspec->domain))
- continue;
- if (strcmp(vcp->vc_username, vcspec->username))
- continue;
-
- SMB_VC_LOCK(vcp);
-
- /* No new references allowed when _GONE is set */
- if (vcp->vc_flags & SMBV_GONE)
- goto unlock_continue;
-
- if (vcp->vc_vopt & SMBVOPT_PRIVATE)
- goto unlock_continue;
-
- found:
- /*
- * Success! (Found one we can use)
- * Return with it held, unlocked.
- * In-line smb_vc_hold here.
- */
- co->co_usecount++;
- SMB_VC_UNLOCK(vcp);
- *vcpp = vcp;
- return (0);
-
- unlock_continue:
- SMB_VC_UNLOCK(vcp);
- /* keep looking. */
- }
-
- return (ENOENT);
-}
-
-int
-smb_sm_findvc(
- struct smb_vcspec *vcspec,
- struct smb_cred *scred,
- struct smb_vc **vcpp)
-{
- struct smb_vc *vcp;
- int error;
-
- *vcpp = vcp = NULL;
-
- SMB_CO_LOCK(&smb_vclist);
- error = smb_sm_lookupvc(vcspec, scred, &vcp);
- SMB_CO_UNLOCK(&smb_vclist);
-
- /* Return if smb_sm_lookupvc fails */
- if (error != 0)
- return (error);
-
- /* Ingore any VC that's not active. */
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- smb_vc_rele(vcp);
- return (ENOENT);
- }
-
- /* Active VC. Return it held. */
- *vcpp = vcp;
- return (error);
-}
-
-int
-smb_sm_negotiate(
- struct smb_vcspec *vcspec,
- struct smb_cred *scred,
- struct smb_vc **vcpp)
-{
- struct smb_vc *vcp;
- clock_t tmo;
- int created, error;
-
-top:
- *vcpp = vcp = NULL;
-
- SMB_CO_LOCK(&smb_vclist);
- error = smb_sm_lookupvc(vcspec, scred, &vcp);
- if (error) {
- /* The VC was not found. Create? */
- if ((vcspec->optflags & SMBVOPT_CREATE) == 0) {
- SMB_CO_UNLOCK(&smb_vclist);
- return (error);
- }
- error = smb_vc_create(vcspec, scred, &vcp);
- if (error) {
- /* Could not create? Unusual. */
- SMB_CO_UNLOCK(&smb_vclist);
- return (error);
- }
- /* Note: co_usecount == 1 */
- created = 1;
- } else
- created = 0;
- SMB_CO_UNLOCK(&smb_vclist);
-
- if (created == 0) {
- /*
- * Found an existing VC. Reuse it, but first,
- * wait for any other thread doing setup, etc.
- * Note: We hold a reference on the VC.
- */
- error = 0;
- SMB_VC_LOCK(vcp);
- while (vcp->vc_state < SMBIOD_ST_VCACTIVE) {
- if (vcp->vc_flags & SMBV_GONE)
- break;
- tmo = lbolt + SEC_TO_TICK(2);
- tmo = cv_timedwait_sig(&vcp->vc_statechg,
- &vcp->vc_lock, tmo);
- if (tmo == 0) {
- error = EINTR;
- break;
- }
- }
- SMB_VC_UNLOCK(vcp);
-
- /* Interrupted? */
- if (error)
- goto out;
-
- /*
- * Was there a vc_kill while we waited?
- * If so, this VC is gone. Start over.
- */
- if (vcp->vc_flags & SMBV_GONE) {
- smb_vc_rele(vcp);
- goto top;
- }
-
- /*
- * The possible states here are:
- * SMBIOD_ST_VCACTIVE, SMBIOD_ST_DEAD
- *
- * SMBIOD_ST_VCACTIVE is the normal case,
- * where found a connection ready to use.
- *
- * We may find vc_state == SMBIOD_ST_DEAD
- * if a previous session has disconnected.
- * In this case, we'd like to reconnect,
- * so take over setting up this VC as if
- * this thread had created it.
- */
- SMB_VC_LOCK(vcp);
- if (vcp->vc_state == SMBIOD_ST_DEAD) {
- vcp->vc_state = SMBIOD_ST_NOTCONN;
- created = 1;
- /* Will signal vc_statechg below */
- }
- SMB_VC_UNLOCK(vcp);
- }
-
- if (created) {
- /*
- * We have a NEW VC, held, but not locked.
- */
-
- SMBIODEBUG("vc_state=%d\n", vcp->vc_state);
- switch (vcp->vc_state) {
-
- case SMBIOD_ST_NOTCONN:
- (void) smb_vc_setup(vcspec, scred, vcp, 0);
- vcp->vc_genid++;
- /* XXX: Save credentials of caller here? */
- vcp->vc_state = SMBIOD_ST_RECONNECT;
- /* FALLTHROUGH */
-
- case SMBIOD_ST_RECONNECT:
- error = smb_iod_connect(vcp);
- if (error)
- break;
- vcp->vc_state = SMBIOD_ST_TRANACTIVE;
- /* FALLTHROUGH */
-
- case SMBIOD_ST_TRANACTIVE:
- /* XXX: Just pass vcspec instead? */
- vcp->vc_intok = vcspec->tok;
- vcp->vc_intoklen = vcspec->toklen;
- error = smb_smb_negotiate(vcp, &vcp->vc_scred);
- vcp->vc_intok = NULL;
- vcp->vc_intoklen = 0;
- if (error)
- break;
- vcp->vc_state = SMBIOD_ST_NEGOACTIVE;
- /* FALLTHROUGH */
-
- case SMBIOD_ST_NEGOACTIVE:
- case SMBIOD_ST_SSNSETUP:
- case SMBIOD_ST_VCACTIVE:
- /* We can (re)use this VC. */
- error = 0;
- break;
-
- default:
- error = EINVAL;
- break;
- }
-
- if (error) {
- /*
- * Leave the VC in a state that allows the
- * next open to attempt a new connection.
- * This call does the cv_broadcast too,
- * so that's in the else part.
- */
- smb_iod_disconnect(vcp);
- } else {
- SMB_VC_LOCK(vcp);
- cv_broadcast(&vcp->vc_statechg);
- SMB_VC_UNLOCK(vcp);
- }
- }
-
-out:
- if (error) {
- /*
- * Undo the hold from lookupvc,
- * or destroy if from vc_create.
- */
- smb_vc_rele(vcp);
- } else {
- /* Return it held. */
- *vcpp = vcp;
- }
-
- return (error);
-}
-
-
-int
-smb_sm_ssnsetup(
- struct smb_vcspec *vcspec,
- struct smb_cred *scred,
- struct smb_vc *vcp)
-{
- int error;
-
- /*
- * We have a VC, held, but not locked.
- *
- * Code from smb_iod_ssnsetup,
- * with lots of rework.
- */
-
- SMBIODEBUG("vc_state=%d\n", vcp->vc_state);
- switch (vcp->vc_state) {
-
- case SMBIOD_ST_NEGOACTIVE:
- /*
- * This is the state we normally find.
- * Calling _setup AGAIN to update the
- * flags, security info, etc.
- */
- error = smb_vc_setup(vcspec, scred, vcp, 1);
- if (error)
- break;
- vcp->vc_state = SMBIOD_ST_SSNSETUP;
- /* FALLTHROUGH */
-
- case SMBIOD_ST_SSNSETUP:
- /* XXX: Just pass vcspec instead? */
- vcp->vc_intok = vcspec->tok;
- vcp->vc_intoklen = vcspec->toklen;
- error = smb_smb_ssnsetup(vcp, &vcp->vc_scred);
- vcp->vc_intok = NULL;
- vcp->vc_intoklen = 0;
- if (error)
- break;
- /* OK, start the reader thread... */
- error = smb_iod_create(vcp);
- if (error)
- break;
- vcp->vc_state = SMBIOD_ST_VCACTIVE;
- /* FALLTHROUGH */
-
- case SMBIOD_ST_VCACTIVE:
- /* We can (re)use this VC. */
- error = 0;
- break;
-
- default:
- error = EINVAL;
- break;
- }
-
- SMB_VC_LOCK(vcp);
- cv_broadcast(&vcp->vc_statechg);
- SMB_VC_UNLOCK(vcp);
-
- return (error);
-}
-
-int
-smb_sm_tcon(
- struct smb_sharespec *shspec,
- struct smb_cred *scred,
- struct smb_vc *vcp,
- struct smb_share **sspp)
-{
- struct smb_share *ssp;
- int error;
-
- *sspp = ssp = NULL;
-
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- /*
- * The wait for vc_state in smb_sm_negotiate
- * _should_ get us a VC in the right state.
- */
- SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
- return (ENOTCONN);
- }
-
- SMB_VC_LOCK(vcp);
- error = smb_vc_lookupshare(vcp, shspec, scred, &ssp);
- if (error) {
- /* The share was not found. Create? */
- if ((shspec->optflags & SMBVOPT_CREATE) == 0) {
- SMB_VC_UNLOCK(vcp);
- return (error);
- }
- error = smb_share_create(vcp, shspec, scred, &ssp);
- if (error) {
- /* Could not create? Unusual. */
- SMB_VC_UNLOCK(vcp);
- return (error);
- }
- /* Note: co_usecount == 1 */
- }
- SMB_VC_UNLOCK(vcp);
-
- /*
- * We have a share, held, but not locked.
- * Make it connected...
- */
- SMB_SS_LOCK(ssp);
- if (!smb_share_valid(ssp))
- error = smb_share_tcon(ssp);
- SMB_SS_UNLOCK(ssp);
-
- if (error) {
- /*
- * Undo hold from lookupshare,
- * or destroy if from _create.
- */
- smb_share_rele(ssp);
- } else {
- /* Return it held. */
- *sspp = ssp;
- }
- return (error);
-}
/*
* Common code for connection object
@@ -692,161 +291,11 @@ smb_co_kill(struct smb_connobj *co)
/*
- * Session implementation
+ * Session objects, which are referred to as "VC" for
+ * "virtual cirtuit". This has nothing to do with the
+ * CIFS notion of a "virtual cirtuit". See smb_conn.h
*/
-/*
- * This sets the fields that are allowed to change
- * when doing a reconnect. Many others are set in
- * smb_vc_create and never change afterwards.
- * Don't want domain or user to change here.
- */
-int
-smb_vc_setup(struct smb_vcspec *vcspec, struct smb_cred *scred,
- struct smb_vc *vcp, int is_ss)
-{
- int error, minauth;
-
- /* Just save all the SMBVOPT_ options. */
- vcp->vc_vopt = vcspec->optflags;
-
- if (is_ss) {
- /* Called from smb_sm_ssnsetup */
-
- if (vcspec->optflags & SMBVOPT_USE_KEYCHAIN) {
- /*
- * Get p/w hashes from the keychain.
- * The password in vcspec->pass is
- * fiction, so don't store it.
- */
- error = smb_pkey_getpwh(vcp, scred->vc_ucred);
- return (error);
- }
-
- /*
- * Note: this can be called more than once
- * for a given vcp, so free the old strings.
- */
- SMB_STRFREE(vcp->vc_pass);
-
- /*
- * Don't store the cleartext password
- * unless the minauth value was changed
- * to allow use of cleartext passwords.
- * (By default, this is not allowed.)
- */
- minauth = vcspec->optflags & SMBVOPT_MINAUTH;
- if (minauth == SMBVOPT_MINAUTH_NONE)
- vcp->vc_pass = smb_strdup(vcspec->pass);
-
- /* Compute LM and NTLM hashes. */
- smb_oldlm_hash(vcspec->pass, vcp->vc_lmhash);
- smb_ntlmv1hash(vcspec->pass, vcp->vc_nthash);
- }
-
- /* Success! */
- error = 0;
- return (error);
-}
-
-/*ARGSUSED*/
-int
-smb_vc_create(struct smb_vcspec *vcspec,
- struct smb_cred *scred, struct smb_vc **vcpp)
-{
- static char objtype[] = "smb_vc";
- struct smb_vc *vcp;
- int error = 0;
-
- ASSERT(MUTEX_HELD(&smb_vclist.co_lock));
-
- /*
- * Checks for valid uid/gid are now in
- * smb_usr_ioc2vcspec, so at this point
- * we know the user has right to create
- * with the uid/gid in the vcspec.
- */
-
- vcp = kmem_zalloc(sizeof (struct smb_vc), KM_SLEEP);
-
- smb_co_init(VCTOCP(vcp), SMBL_VC, objtype);
- vcp->vc_co.co_free = smb_vc_free;
- vcp->vc_co.co_gone = smb_vc_gone;
-
- cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL);
- sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL);
- rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL);
- cv_init(&vcp->iod_exit, objtype, CV_DRIVER, NULL);
-
- vcp->vc_number = atomic_inc_uint_nv(&smb_vcnext);
- vcp->vc_state = SMBIOD_ST_NOTCONN;
- vcp->vc_timo = SMB_DEFRQTIMO;
- /*
- * I think SMB_UID_UNKNOWN is not the correct
- * initial value for vc_smbuid. See the long
- * comment in smb_iod_sendrq()
- */
- vcp->vc_smbuid = SMB_UID_UNKNOWN; /* XXX should be zero */
- vcp->vc_tdesc = &smb_tran_nbtcp_desc;
-
- /*
- * These identify the connection.
- */
- vcp->vc_zoneid = getzoneid();
- vcp->vc_uid = vcspec->owner;
- vcp->vc_grp = vcspec->group;
- vcp->vc_mode = vcspec->rights & SMBM_MASK;
-
- vcp->vc_domain = smb_strdup(vcspec->domain);
- vcp->vc_username = smb_strdup(vcspec->username);
- vcp->vc_srvname = smb_strdup(vcspec->srvname);
- vcp->vc_paddr = smb_dup_sockaddr(vcspec->sap);
- vcp->vc_laddr = smb_dup_sockaddr(vcspec->lap);
-
-#ifdef NOICONVSUPPORT
- /*
- * REVISIT
- */
- error = iconv_open("tolower", vcspec->localcs, &vcp->vc_tolower);
- if (error)
- goto errout;
-
- error = iconv_open("toupper", vcspec->localcs, &vcp->vc_toupper);
- if (error)
- goto errout;
-
- if (vcspec->servercs[0]) {
-
- error = iconv_open(vcspec->servercs, vcspec->localcs,
- &vcp->vc_toserver);
- if (error)
- goto errout;
-
- error = iconv_open(vcspec->localcs, vcspec->servercs,
- &vcp->vc_tolocal);
- if (error)
- goto errout;
- }
-#endif /* NOICONVSUPPORT */
-
- /* This fills in vcp->vc_tdata */
- if ((error = SMB_TRAN_CREATE(vcp, curproc)) != 0)
- goto errout;
-
- /* Success! */
- smb_co_addchild(&smb_vclist, VCTOCP(vcp));
- *vcpp = vcp;
- return (0);
-
-errout:
- /*
- * This will destroy the new vc.
- * See: smb_vc_free
- */
- smb_vc_rele(vcp);
- return (error);
-}
-
void
smb_vc_hold(struct smb_vc *vcp)
{
@@ -883,37 +332,27 @@ smb_vc_gone(struct smb_connobj *cp)
* Was smb_vc_disconnect(vcp);
*/
smb_iod_disconnect(vcp);
-
- /* Note: smb_iod_destroy in vc_free */
}
+/*
+ * The VC has no more references. Free it.
+ * No locks needed here.
+ */
static void
smb_vc_free(struct smb_connobj *cp)
{
struct smb_vc *vcp = CPTOVC(cp);
/*
- * The VC has no more references, so
- * no locks should be needed here.
- * Make sure the IOD is gone.
+ * The _gone call should have emptied the request list,
+ * but let's make sure, as requests may have references
+ * to this VC without taking a hold. (The hold is the
+ * responsibility of threads placing requests.)
*/
- smb_iod_destroy(vcp);
+ ASSERT(vcp->iod_rqlist.tqh_first == NULL);
if (vcp->vc_tdata)
- SMB_TRAN_DONE(vcp, curproc);
-
- SMB_STRFREE(vcp->vc_username);
- SMB_STRFREE(vcp->vc_srvname);
- SMB_STRFREE(vcp->vc_pass);
- SMB_STRFREE(vcp->vc_domain);
- if (vcp->vc_paddr) {
- smb_free_sockaddr(vcp->vc_paddr);
- vcp->vc_paddr = NULL;
- }
- if (vcp->vc_laddr) {
- smb_free_sockaddr(vcp->vc_laddr);
- vcp->vc_laddr = NULL;
- }
+ SMB_TRAN_DONE(vcp);
/*
* We are not using the iconv routines here. So commenting them for now.
@@ -929,17 +368,11 @@ smb_vc_free(struct smb_connobj *cp)
if (vcp->vc_toserver)
iconv_close(vcp->vc_toserver);
#endif
- if (vcp->vc_intok)
- kmem_free(vcp->vc_intok, vcp->vc_intoklen);
- if (vcp->vc_outtok)
- kmem_free(vcp->vc_outtok, vcp->vc_outtoklen);
- if (vcp->vc_negtok)
- kmem_free(vcp->vc_negtok, vcp->vc_negtoklen);
if (vcp->vc_mackey != NULL)
kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
- cv_destroy(&vcp->iod_exit);
+ cv_destroy(&vcp->iod_idle);
rw_destroy(&vcp->iod_rqlock);
sema_destroy(&vcp->vc_sendlock);
cv_destroy(&vcp->vc_statechg);
@@ -947,158 +380,232 @@ smb_vc_free(struct smb_connobj *cp)
kmem_free(vcp, sizeof (*vcp));
}
+/*ARGSUSED*/
+int
+smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
+{
+ static char objtype[] = "smb_vc";
+ cred_t *cr = scred->scr_cred;
+ struct smb_vc *vcp;
+ int error = 0;
+
+ ASSERT(MUTEX_HELD(&smb_vclist.co_lock));
+
+ vcp = kmem_zalloc(sizeof (struct smb_vc), KM_SLEEP);
+
+ smb_co_init(VCTOCP(vcp), SMBL_VC, objtype);
+ vcp->vc_co.co_free = smb_vc_free;
+ vcp->vc_co.co_gone = smb_vc_gone;
+
+ cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL);
+ sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL);
+ rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL);
+ cv_init(&vcp->iod_idle, objtype, CV_DRIVER, NULL);
+
+ /* Expanded TAILQ_HEAD_INITIALIZER */
+ vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first;
+
+ vcp->vc_state = SMBIOD_ST_IDLE;
+
+ /*
+ * These identify the connection.
+ */
+ vcp->vc_zoneid = getzoneid();
+ bcopy(ossn, &vcp->vc_ssn, sizeof (*ossn));
+
+ /* This fills in vcp->vc_tdata */
+ vcp->vc_tdesc = &smb_tran_nbtcp_desc;
+ if ((error = SMB_TRAN_CREATE(vcp, cr)) != 0)
+ goto errout;
+
+ /* Success! */
+ smb_co_addchild(&smb_vclist, VCTOCP(vcp));
+ *vcpp = vcp;
+ return (0);
+
+errout:
+ /*
+ * This will destroy the new vc.
+ * See: smb_vc_free
+ */
+ smb_vc_rele(vcp);
+ return (error);
+}
/*
- * Lookup share in the given VC. Share referenced and locked on return.
- * VC expected to be locked on entry and will be left locked on exit.
+ * Find or create a VC identified by the info in ossn
+ * and return it with a "hold", but not locked.
*/
/*ARGSUSED*/
int
-smb_vc_lookupshare(struct smb_vc *vcp, struct smb_sharespec *shspec,
- struct smb_cred *scred, struct smb_share **sspp)
+smb_vc_findcreate(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
{
struct smb_connobj *co;
- struct smb_share *ssp = NULL;
+ struct smb_vc *vcp;
+ smbioc_ssn_ident_t *vc_id;
+ int error;
+ zoneid_t zoneid = getzoneid();
- ASSERT(MUTEX_HELD(&vcp->vc_lock));
+ *vcpp = vcp = NULL;
- *sspp = NULL;
+ SMB_CO_LOCK(&smb_vclist);
/* var, head, next_field */
- SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
- ssp = CPTOSS(co);
+ SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
+ vcp = CPTOVC(co);
+
+ /*
+ * Some things we can check without
+ * holding the lock (those that are
+ * set at creation and never change).
+ */
- /* No new refs if _GONE is set. */
- if (ssp->ss_flags & SMBS_GONE)
+ /* VCs in other zones are invisibile. */
+ if (vcp->vc_zoneid != zoneid)
continue;
- /* This has a hold, so no need to lock it. */
- if (strcmp(ssp->ss_name, shspec->name) == 0)
- goto found;
- }
- return (ENOENT);
+ /* Also segregate by Unix owner. */
+ if (vcp->vc_owner != ossn->ssn_owner)
+ continue;
-found:
- /* Return it with a hold. */
- smb_share_hold(ssp);
- *sspp = ssp;
- return (0);
-}
+ /*
+ * Compare identifying info:
+ * server address, user, domain
+ * names are case-insensitive
+ */
+ vc_id = &vcp->vc_ssn.ssn_id;
+ if (bcmp(&vc_id->id_srvaddr,
+ &ossn->ssn_id.id_srvaddr,
+ sizeof (vc_id->id_srvaddr)))
+ continue;
+ if (u8_strcmp(vc_id->id_user, ossn->ssn_id.id_user, 0,
+ U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
+ continue;
+ if (u8_strcmp(vc_id->id_domain, ossn->ssn_id.id_domain, 0,
+ U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
+ continue;
+ /*
+ * We have a match, but still have to check
+ * the _GONE flag, and do that with a lock.
+ * No new references when _GONE is set.
+ *
+ * Also clear SMBVOPT_CREATE which the caller
+ * may check to find out if we did create.
+ */
+ SMB_VC_LOCK(vcp);
+ if ((vcp->vc_flags & SMBV_GONE) == 0) {
+ ossn->ssn_vopt &= ~SMBVOPT_CREATE;
+ /*
+ * Return it held, unlocked.
+ * In-line smb_vc_hold here.
+ */
+ co->co_usecount++;
+ SMB_VC_UNLOCK(vcp);
+ *vcpp = vcp;
+ error = 0;
+ goto out;
+ }
+ SMB_VC_UNLOCK(vcp);
+ /* keep looking. */
+ }
+ vcp = NULL;
-static char smb_emptypass[] = "";
+ /* Note: smb_vclist is still locked. */
-const char *
-smb_vc_getpass(struct smb_vc *vcp)
-{
- if (vcp->vc_pass)
- return (vcp->vc_pass);
- return (smb_emptypass);
+ if (ossn->ssn_vopt & SMBVOPT_CREATE) {
+ /*
+ * Create a new VC. It starts out with
+ * hold count = 1, so don't incr. here.
+ */
+ error = smb_vc_create(ossn, scred, &vcp);
+ if (error == 0)
+ *vcpp = vcp;
+ } else
+ error = ENOENT;
+
+out:
+ SMB_CO_UNLOCK(&smb_vclist);
+ return (error);
}
-uint16_t
-smb_vc_nextmid(struct smb_vc *vcp)
-{
- uint16_t r;
- r = atomic_inc_16_nv(&vcp->vc_mid);
- return (r);
-}
+/*
+ * Helper functions that operate on VCs
+ */
/*
* Get a pointer to the IP address suitable for passing to Trusted
* Extensions find_tpc() routine. Used by smbfs_mount_label_policy().
* Compare this code to nfs_mount_label_policy() if problems arise.
- * Without support for direct CIFS-over-TCP, we should always see
- * an AF_NETBIOS sockaddr here.
*/
void *
smb_vc_getipaddr(struct smb_vc *vcp, int *ipvers)
{
- switch (vcp->vc_paddr->sa_family) {
- case AF_NETBIOS: {
- struct sockaddr_nb *snb;
-
- *ipvers = IPV4_VERSION;
- /*LINTED*/
- snb = (struct sockaddr_nb *)vcp->vc_paddr;
- return ((void *)&snb->snb_ipaddr);
- }
- case AF_INET: {
- struct sockaddr_in *sin;
+ smbioc_ssn_ident_t *id = &vcp->vc_ssn.ssn_id;
+ void *ret;
+ switch (id->id_srvaddr.sa.sa_family) {
+ case AF_INET:
*ipvers = IPV4_VERSION;
- /*LINTED*/
- sin = (struct sockaddr_in *)vcp->vc_paddr;
- return ((void *)&sin->sin_addr);
- }
- case AF_INET6: {
- struct sockaddr_in6 *sin6;
+ ret = &id->id_srvaddr.sin.sin_addr;
+ break;
+ case AF_INET6:
*ipvers = IPV6_VERSION;
- /*LINTED*/
- sin6 = (struct sockaddr_in6 *)vcp->vc_paddr;
- return ((void *)&sin6->sin6_addr);
- }
+ ret = &id->id_srvaddr.sin6.sin6_addr;
+ break;
default:
SMBSDEBUG("invalid address family %d\n",
- vcp->vc_paddr->sa_family);
+ id->id_srvaddr.sa.sa_family);
*ipvers = 0;
- return (NULL);
+ ret = NULL;
+ break;
}
+ return (ret);
}
-/*
- * Share implementation
- */
-/*
- * Allocate share structure and attach it to the given VC
- * Connection expected to be locked on entry. Share will be returned
- * in locked state.
- */
-/*ARGSUSED*/
-int
-smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec,
- struct smb_cred *scred, struct smb_share **sspp)
+void
+smb_vc_walkshares(struct smb_vc *vcp,
+ walk_share_func_t func)
{
- static char objtype[] = "smb_ss";
- struct smb_share *ssp;
+ smb_connobj_t *co;
+ smb_share_t *ssp;
- ASSERT(MUTEX_HELD(&vcp->vc_lock));
+ /*
+ * Walk the share list calling func(ssp, arg)
+ */
+ SMB_VC_LOCK(vcp);
+ SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
+ ssp = CPTOSS(co);
+ SMB_SS_LOCK(ssp);
+ func(ssp);
+ SMB_SS_UNLOCK(ssp);
+ }
+ SMB_VC_UNLOCK(vcp);
+}
- ssp = kmem_zalloc(sizeof (struct smb_share), KM_SLEEP);
- smb_co_init(SSTOCP(ssp), SMBL_SHARE, objtype);
- ssp->ss_co.co_free = smb_share_free;
- ssp->ss_co.co_gone = smb_share_gone;
- ssp->ss_name = smb_strdup(shspec->name);
- ssp->ss_mount = NULL;
- if (shspec->pass && shspec->pass[0])
- ssp->ss_pass = smb_strdup(shspec->pass);
- ssp->ss_type = shspec->stype;
- ssp->ss_tid = SMB_TID_UNKNOWN;
- ssp->ss_mode = shspec->rights & SMBM_MASK;
- ssp->ss_fsname = NULL;
- smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp));
- *sspp = ssp;
+/*
+ * Share implementation
+ */
- return (0);
+void
+smb_share_hold(struct smb_share *ssp)
+{
+ smb_co_hold(SSTOCP(ssp));
}
-/*
- * Normally called via smb_share_rele()
- * after co_usecount drops to zero.
- */
-static void
-smb_share_free(struct smb_connobj *cp)
+void
+smb_share_rele(struct smb_share *ssp)
{
- struct smb_share *ssp = CPTOSS(cp);
+ smb_co_rele(SSTOCP(ssp));
+}
- SMB_STRFREE(ssp->ss_name);
- SMB_STRFREE(ssp->ss_pass);
- SMB_STRFREE(ssp->ss_fsname);
- smb_co_done(SSTOCP(ssp));
- kmem_free(ssp, sizeof (*ssp));
+void
+smb_share_kill(struct smb_share *ssp)
+{
+ smb_co_kill(SSTOCP(ssp));
}
/*
@@ -1112,80 +619,172 @@ smb_share_gone(struct smb_connobj *cp)
struct smb_cred scred;
struct smb_share *ssp = CPTOSS(cp);
- smb_credinit(&scred, curproc, NULL);
+ smb_credinit(&scred, NULL);
smb_iod_shutdown_share(ssp);
smb_smb_treedisconnect(ssp, &scred);
smb_credrele(&scred);
}
-void
-smb_share_hold(struct smb_share *ssp)
+/*
+ * Normally called via smb_share_rele()
+ * after co_usecount drops to zero.
+ */
+static void
+smb_share_free(struct smb_connobj *cp)
{
- smb_co_hold(SSTOCP(ssp));
-}
+ struct smb_share *ssp = CPTOSS(cp);
-void
-smb_share_rele(struct smb_share *ssp)
-{
- smb_co_rele(SSTOCP(ssp));
+ cv_destroy(&ssp->ss_conn_done);
+ smb_co_done(SSTOCP(ssp));
+ kmem_free(ssp, sizeof (*ssp));
}
-void
-smb_share_kill(struct smb_share *ssp)
+/*
+ * Allocate share structure and attach it to the given VC
+ * Connection expected to be locked on entry. Share will be returned
+ * in locked state.
+ */
+/*ARGSUSED*/
+int
+smb_share_create(smbioc_tcon_t *tcon, struct smb_vc *vcp,
+ struct smb_share **sspp, struct smb_cred *scred)
{
- smb_co_kill(SSTOCP(ssp));
-}
+ static char objtype[] = "smb_ss";
+ struct smb_share *ssp;
+ ASSERT(MUTEX_HELD(&vcp->vc_lock));
-void
-smb_share_invalidate(struct smb_share *ssp)
-{
+ ssp = kmem_zalloc(sizeof (struct smb_share), KM_SLEEP);
+ smb_co_init(SSTOCP(ssp), SMBL_SHARE, objtype);
+ ssp->ss_co.co_free = smb_share_free;
+ ssp->ss_co.co_gone = smb_share_gone;
+
+ cv_init(&ssp->ss_conn_done, objtype, CV_DRIVER, NULL);
ssp->ss_tid = SMB_TID_UNKNOWN;
+
+ bcopy(&tcon->tc_sh, &ssp->ss_ioc,
+ sizeof (smbioc_oshare_t));
+
+ smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp));
+ *sspp = ssp;
+
+ return (0);
}
/*
- * Returns NON-zero if the share is valid.
- * Called with the share locked.
+ * Find or create a share under the given VC
+ * and return it with a "hold", but not locked.
*/
+
int
-smb_share_valid(struct smb_share *ssp)
+smb_share_findcreate(smbioc_tcon_t *tcon, struct smb_vc *vcp,
+ struct smb_share **sspp, struct smb_cred *scred)
{
- struct smb_vc *vcp = SSTOVC(ssp);
+ struct smb_connobj *co;
+ struct smb_share *ssp = NULL;
+ int error = 0;
- ASSERT(MUTEX_HELD(&ssp->ss_lock));
+ *sspp = NULL;
- if ((ssp->ss_flags & SMBS_CONNECTED) == 0)
- return (0);
+ SMB_VC_LOCK(vcp);
- if (ssp->ss_tid == SMB_TID_UNKNOWN) {
- SMBIODEBUG("found TID unknown\n");
- ssp->ss_flags &= ~SMBS_CONNECTED;
- }
+ /* var, head, next_field */
+ SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
+ ssp = CPTOSS(co);
+
+ /* Share name */
+ if (u8_strcmp(ssp->ss_name, tcon->tc_sh.sh_name, 0,
+ U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
+ continue;
- if (ssp->ss_vcgenid != vcp->vc_genid) {
- SMBIODEBUG("wrong genid\n");
- ssp->ss_flags &= ~SMBS_CONNECTED;
+ /*
+ * We have a match, but still have to check
+ * the _GONE flag, and do that with a lock.
+ * No new references when _GONE is set.
+ *
+ * Also clear SMBSOPT_CREATE which the caller
+ * may check to find out if we did create.
+ */
+ SMB_SS_LOCK(ssp);
+ if ((ssp->ss_flags & SMBS_GONE) == 0) {
+ tcon->tc_opt &= ~SMBSOPT_CREATE;
+ /*
+ * Return it held, unlocked.
+ * In-line smb_share_hold here.
+ */
+ co->co_usecount++;
+ SMB_SS_UNLOCK(ssp);
+ *sspp = ssp;
+ error = 0;
+ goto out;
+ }
+ SMB_SS_UNLOCK(ssp);
+ /* keep looking. */
}
+ ssp = NULL;
+
+ /* Note: vcp (list of shares) is still locked. */
+
+ if (tcon->tc_opt & SMBSOPT_CREATE) {
+ /*
+ * Create a new share. It starts out with
+ * hold count = 1, so don't incr. here.
+ */
+ error = smb_share_create(tcon, vcp, &ssp, scred);
+ if (error == 0)
+ *sspp = ssp;
+ } else
+ error = ENOENT;
- return (ssp->ss_flags & SMBS_CONNECTED);
+out:
+ SMB_VC_UNLOCK(vcp);
+ return (error);
+}
+
+
+/*
+ * Helper functions that operate on shares
+ */
+
+/*
+ * Mark this share as invalid, so consumers will know
+ * their file handles have become invalid.
+ *
+ * Most share consumers store a copy of ss_vcgenid when
+ * opening a file handle and compare that with what's in
+ * the share before using a file handle. If the genid
+ * doesn't match, the file handle has become "stale"
+ * due to disconnect. Therefore, zap ss_vcgenid here.
+ */
+void
+smb_share_invalidate(struct smb_share *ssp)
+{
+
+ ASSERT(MUTEX_HELD(&ssp->ss_lock));
+
+ ssp->ss_flags &= ~SMBS_CONNECTED;
+ ssp->ss_tid = SMB_TID_UNKNOWN;
+ ssp->ss_vcgenid = 0;
}
/*
* Connect (or reconnect) a share object.
- * Called with the share locked.
+ *
+ * Called by smb_usr_get_tree() for new connections,
+ * and called by smb_rq_enqueue() for reconnect.
*/
int
-smb_share_tcon(struct smb_share *ssp)
+smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred)
{
- struct smb_vc *vcp = SSTOVC(ssp);
clock_t tmo;
int error;
- ASSERT(MUTEX_HELD(&ssp->ss_lock));
+ SMB_SS_LOCK(ssp);
if (ssp->ss_flags & SMBS_CONNECTED) {
SMBIODEBUG("alread connected?");
- return (0);
+ error = 0;
+ goto out;
}
/*
@@ -1198,76 +797,41 @@ smb_share_tcon(struct smb_share *ssp)
ssp->ss_conn_waiters--;
if (tmo == 0) {
/* Interrupt! */
- return (EINTR);
+ error = EINTR;
+ goto out;
}
}
/* Did someone else do it for us? */
- if (ssp->ss_flags & SMBS_CONNECTED)
- return (0);
+ if (ssp->ss_flags & SMBS_CONNECTED) {
+ error = 0;
+ goto out;
+ }
/*
* OK, we'll do the work.
*/
ssp->ss_flags |= SMBS_RECONNECTING;
- /* Drop the lock while doing the call. */
+ /*
+ * Drop the lock while doing the TCON.
+ * On success, sets ss_tid, ss_vcgenid,
+ * and ss_flags |= SMBS_CONNECTED;
+ */
SMB_SS_UNLOCK(ssp);
- error = smb_smb_treeconnect(ssp, &vcp->vc_scred);
+ error = smb_smb_treeconnect(ssp, scred);
SMB_SS_LOCK(ssp);
- if (!error)
- ssp->ss_flags |= SMBS_CONNECTED;
ssp->ss_flags &= ~SMBS_RECONNECTING;
/* They can all go ahead! */
if (ssp->ss_conn_waiters)
cv_broadcast(&ssp->ss_conn_done);
- return (error);
-}
-
-const char *
-smb_share_getpass(struct smb_share *ssp)
-{
- struct smb_vc *vcp;
-
- if (ssp->ss_pass)
- return (ssp->ss_pass);
- vcp = SSTOVC(ssp);
- if (vcp->vc_pass)
- return (vcp->vc_pass);
- return (smb_emptypass);
-}
-
-int
-smb_share_count(void)
-{
- struct smb_connobj *covc, *coss;
- struct smb_vc *vcp;
- zoneid_t zoneid = getzoneid();
- int nshares = 0;
-
- SMB_CO_LOCK(&smb_vclist);
- SLIST_FOREACH(covc, &smb_vclist.co_children, co_next) {
- vcp = CPTOVC(covc);
-
- /* VCs in other zones are invisibile. */
- if (vcp->vc_zoneid != zoneid)
- continue;
-
- SMB_VC_LOCK(vcp);
-
- /* var, head, next_field */
- SLIST_FOREACH(coss, &(VCTOCP(vcp)->co_children), co_next) {
- nshares++;
- }
-
- SMB_VC_UNLOCK(vcp);
- }
- SMB_CO_UNLOCK(&smb_vclist);
+out:
+ SMB_SS_UNLOCK(ssp);
- return (nshares);
+ return (error);
}
/*
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
index 4662acd111..df85a77d11 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
@@ -33,28 +33,24 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SMB_CONN_H
#define _SMB_CONN_H
+#include <sys/dditypes.h>
#include <sys/t_lock.h>
#include <sys/queue.h> /* for SLIST below */
#include <sys/uio.h>
#include <netsmb/smb_dev.h>
-#ifndef _KERNEL
-#error "Not _KERNEL?"
-#endif
-
/*
* Credentials of user/process for processing in the connection procedures
*/
typedef struct smb_cred {
- pid_t vc_pid;
- cred_t *vc_ucred;
+ struct cred *scr_cred;
} smb_cred_t;
/*
@@ -67,25 +63,17 @@ typedef struct smb_cred {
* Many of these were duplicates of SMBVOPT_ flags
* and we now keep those too instead of merging
* them into vc_flags.
- *
- * Careful here: In smb_smb_negotiate, we clear ALL OF
- * vc_flags except: SMBV_GONE, SMBV_RECONNECTING
*/
-#define SMBV_RECONNECTING 0x0002 /* conn in process of reconnection */
-#define SMBV_LONGNAMES 0x0004 /* conn configured to use long names */
-#define SMBV_ENCRYPT 0x0008 /* server demands encrypted password */
#define SMBV_WIN95 0x0010 /* used to apply bugfixes for this OS */
#define SMBV_NT4 0x0020 /* used when NT4 issues invalid resp */
#define SMBV_UNICODE 0x0040 /* conn configured to use Unicode */
-#define SMBV_EXT_SEC 0x0080 /* conn to use extended security */
-#define SMBV_WILL_SIGN 0x0100 /* negotiated signing */
/*
* Note: the common "obj" level uses this GONE flag by
* the name SMBO_GONE. Keep this alias as a reminder.
*/
-#define SMBV_GONE SMBO_GONE
+#define SMBV_GONE SMBO_GONE
/*
* bits in smb_share ss_flags (a.k.a. ss_co.co_flags)
@@ -98,78 +86,13 @@ typedef struct smb_cred {
* ^ This partition can't handle dates before 1980. It's probably a FAT
* partition but could be some other ancient FS type
*/
-#define SMBS_RESUMEKEYS 0x0010 /* must use resume keys */
+#define SMBS_RESUMEKEYS 0x0020 /* must use resume keys */
+#define SMBS_LONGNAMES 0x0040 /* share can use long names */
/*
* Note: the common "obj" level uses this GONE flag by
* the name SMBO_GONE. Keep this alias as a reminder.
*/
-#define SMBS_GONE SMBO_GONE
-
-/*
- * Negotiated protocol parameters
- */
-struct smb_sopt {
- int sv_proto;
- int16_t sv_tz; /* offset in min relative to UTC */
- uint32_t sv_maxtx; /* maximum transmit buf size */
- uchar_t sv_sm; /* security mode */
- uint16_t sv_maxmux; /* max number of outstanding rq's */
- uint16_t sv_maxvcs; /* max number of VCs */
- uint16_t sv_rawmode;
- uint32_t sv_maxraw; /* maximum raw-buffer size */
- uint32_t sv_skey; /* session key */
- uint32_t sv_caps; /* capabilites SMB_CAP_ */
-};
-typedef struct smb_sopt smb_sopt_t;
-
-/*
- * network IO daemon states
- * really connection states.
- */
-enum smbiod_state {
- SMBIOD_ST_NOTCONN, /* no connect request was made */
- SMBIOD_ST_RECONNECT, /* a [re]connect attempt is in progress */
- SMBIOD_ST_TRANACTIVE, /* transport level is up */
- SMBIOD_ST_NEGOACTIVE, /* completed negotiation */
- SMBIOD_ST_SSNSETUP, /* started (a) session setup */
- SMBIOD_ST_VCACTIVE, /* session established */
- SMBIOD_ST_DEAD /* connection broken, transport is down */
-};
-
-
-/*
- * Info structures
- */
-#define SMB_INFO_NONE 0
-#define SMB_INFO_VC 2
-#define SMB_INFO_SHARE 3
-
-struct smb_vc_info {
- int itype;
- int usecount;
- uid_t uid; /* user id of connection */
- gid_t gid; /* group of connection */
- mode_t mode; /* access mode */
- int flags;
- enum smbiod_state iodstate;
- struct smb_sopt sopt;
- char srvname[SMB_MAXSRVNAMELEN+1];
- char vcname[128];
-};
-typedef struct smb_vc_info smb_vc_info_t;
-
-struct smb_share_info {
- int itype;
- int usecount;
- ushort_t tid; /* TID */
- int type; /* share type */
- uid_t uid; /* user id of connection */
- gid_t gid; /* group of connection */
- mode_t mode; /* access mode */
- int flags;
- char sname[128];
-};
-typedef struct smb_share_info smb_share_info_t;
+#define SMBS_GONE SMBO_GONE
struct smb_rq;
/* This declares struct smb_rqhead */
@@ -221,88 +144,76 @@ struct smb_connobj {
typedef struct smb_connobj smb_connobj_t;
/*
- * Virtual Circuit (session) to a server.
- * This is the most (over)complicated part of SMB protocol.
- * For the user security level (usl), each session with different remote
- * user name has its own VC.
- * It is unclear however, should share security level (ssl) allow additional
- * VCs, because user name is not used and can be the same. On other hand,
- * multiple VCs allows us to create separate sessions to server on a per
- * user basis.
+ * "Level" in the connection object hierarchy
*/
+#define SMBL_SM 0
+#define SMBL_VC 1
+#define SMBL_SHARE 2
+/*
+ * Virtual Circuit to a server (really connection + session).
+ * Yes, calling this a "Virtual Circuit" is confusining,
+ * because it has nothing to do with the SMB notion of a
+ * "Virtual Circuit".
+ */
typedef struct smb_vc {
- struct smb_connobj vc_co;
- enum smbiod_state vc_state;
- kcondvar_t vc_statechg;
- ksema_t vc_sendlock;
-
- zoneid_t vc_zoneid;
- char *vc_srvname;
- struct sockaddr *vc_paddr; /* server addr */
- struct sockaddr *vc_laddr; /* local addr, if any */
- char *vc_domain; /* domain that defines username */
- char *vc_username;
- char *vc_pass; /* password for usl case */
- uchar_t vc_lmhash[SMB_PWH_MAX];
- uchar_t vc_nthash[SMB_PWH_MAX];
- uint8_t *vc_mackey; /* MAC key */
- int vc_mackeylen; /* length of MAC key */
- uint32_t vc_seqno; /* my next sequence number - */
- /* - serialized by iod_rqlock */
- uint_t vc_timo; /* default request timeout */
- int vc_maxvcs; /* maximum number of VC per conn */
-
- void *vc_tolower; /* local charset */
- void *vc_toupper; /* local charset */
- void *vc_toserver; /* local charset to server one */
- void *vc_tolocal; /* server charset to local one */
- int vc_number; /* number of this VC from client side */
- int vc_genid; /* "generation ID" of this VC */
- uid_t vc_uid; /* user id of connection */
- gid_t vc_grp; /* group of connection */
- mode_t vc_mode; /* access mode */
- uint16_t vc_smbuid; /* auth. session ID from server */
-
- uint8_t vc_hflags; /* or'ed with flags in the smb header */
- uint16_t vc_hflags2; /* or'ed with flags in the smb header */
- void *vc_tdata; /* transport control block */
- struct smb_tran_desc *vc_tdesc;
- int vc_chlen; /* actual challenge length */
- uchar_t vc_challenge[SMB_MAXCHALLENGELEN];
- uint16_t vc_mid; /* multiplex id */
- int vc_vopt; /* local options SMBVOPT_ */
- struct smb_sopt vc_sopt; /* server options */
- struct smb_cred vc_scred; /* used in reconnect procedure */
- int vc_txmax; /* max tx/rx packet size */
- int vc_rxmax; /* max readx data size */
- int vc_wxmax; /* max writex data size */
-
- /* Authentication tokens */
- size_t vc_intoklen;
- caddr_t vc_intok;
- size_t vc_outtoklen;
- caddr_t vc_outtok;
- size_t vc_negtoklen;
- caddr_t vc_negtok;
+ struct smb_connobj vc_co; /* keep first! See CPTOVC */
+ enum smbiod_state vc_state;
+ kcondvar_t vc_statechg;
- /*
- * These members used to be in struct smbiod,
- * which has been eliminated.
- */
- krwlock_t iod_rqlock; /* iod_rqlist */
+ zoneid_t vc_zoneid;
+ uid_t vc_owner; /* Unix owner */
+ int vc_genid; /* "generation" ID */
+
+ int vc_mackeylen; /* length of MAC key */
+ uint8_t *vc_mackey; /* MAC key */
+
+ ksema_t vc_sendlock;
+ struct smb_tran_desc *vc_tdesc; /* transport ops. vector */
+ void *vc_tdata; /* transport control block */
+
+ kcondvar_t iod_idle; /* IOD thread idle CV */
+ krwlock_t iod_rqlock; /* iod_rqlist */
struct smb_rqhead iod_rqlist; /* list of outstanding reqs */
struct _kthread *iod_thr; /* the IOD (reader) thread */
- kcondvar_t iod_exit; /* IOD thread termination */
int iod_flags; /* see SMBIOD_* below */
int iod_newrq; /* send needed (iod_rqlock) */
int iod_muxfull; /* maxmux limit reached */
- uint_t iod_rqwaiting; /* count of waiting requests */
+
+ /* This is copied in/out when IOD enters/returns */
+ smbioc_ssn_work_t vc_work;
+
+ /* session identity, etc. */
+ smbioc_ossn_t vc_ssn;
} smb_vc_t;
#define vc_lock vc_co.co_lock
#define vc_flags vc_co.co_flags
-#define vc_maxmux vc_sopt.sv_maxmux
+
+/* defines for members in vc_ssn */
+#define vc_owner vc_ssn.ssn_owner
+#define vc_srvname vc_ssn.ssn_srvname
+#define vc_srvaddr vc_ssn.ssn_id.id_srvaddr
+#define vc_domain vc_ssn.ssn_id.id_domain
+#define vc_username vc_ssn.ssn_id.id_user
+#define vc_vopt vc_ssn.ssn_vopt
+
+/* defines for members in vc_work */
+#define vc_sopt vc_work.wk_sopt
+#define vc_maxmux vc_work.wk_sopt.sv_maxmux
+#define vc_tran_fd vc_work.wk_iods.is_tran_fd
+#define vc_hflags vc_work.wk_iods.is_hflags
+#define vc_hflags2 vc_work.wk_iods.is_hflags2
+#define vc_smbuid vc_work.wk_iods.is_smbuid
+#define vc_next_mid vc_work.wk_iods.is_next_mid
+#define vc_txmax vc_work.wk_iods.is_txmax
+#define vc_rwmax vc_work.wk_iods.is_rwmax
+#define vc_rxmax vc_work.wk_iods.is_rxmax
+#define vc_wxmax vc_work.wk_iods.is_wxmax
+#define vc_ssn_key vc_work.wk_iods.is_ssn_key
+#define vc_next_seq vc_work.wk_iods.is_next_seq
+#define vc_u_mackey vc_work.wk_iods.is_u_mackey
+#define vc_u_maclen vc_work.wk_iods.is_u_maclen
#define SMB_VC_LOCK(vcp) mutex_enter(&(vcp)->vc_lock)
#define SMB_VC_UNLOCK(vcp) mutex_exit(&(vcp)->vc_lock)
@@ -319,104 +230,121 @@ typedef struct smb_vc {
*/
typedef struct smb_share {
- struct smb_connobj ss_co;
+ struct smb_connobj ss_co; /* keep first! See CPTOSS */
kcondvar_t ss_conn_done; /* wait for reconnect */
int ss_conn_waiters;
- char *ss_name;
- char *ss_pass; /* share password, can be null */
- char *ss_fsname;
- void *ss_mount; /* used for smb up/down */
- uint16_t ss_tid; /* TID */
- int ss_type; /* share type */
- mode_t ss_mode; /* access mode */
int ss_vcgenid; /* check VC generation ID */
- uint32_t ss_maxfilenamelen;
- int ss_sopt; /* local options SMBSOPT_ */
+ uint16_t ss_tid; /* TID */
+ uint16_t ss_options; /* option support bits */
+ smbioc_oshare_t ss_ioc;
} smb_share_t;
#define ss_lock ss_co.co_lock
#define ss_flags ss_co.co_flags
+#define ss_name ss_ioc.sh_name
+#define ss_pwlen ss_ioc.sh_pwlen
+#define ss_pass ss_ioc.sh_pass
+#define ss_type_req ss_ioc.sh_type_req
+#define ss_type_ret ss_ioc.sh_type_ret
+
#define SMB_SS_LOCK(ssp) mutex_enter(&(ssp)->ss_lock)
#define SMB_SS_UNLOCK(ssp) mutex_exit(&(ssp)->ss_lock)
-#define CPTOVC(cp) ((struct smb_vc *)(cp))
+#define CPTOVC(cp) ((struct smb_vc *)((void *)(cp)))
#define VCTOCP(vcp) (&(vcp)->vc_co)
-#define CPTOSS(cp) ((struct smb_share *)(cp))
+#define CPTOSS(cp) ((struct smb_share *)((void *)(cp)))
#define SSTOVC(ssp) CPTOVC(((ssp)->ss_co.co_parent))
#define SSTOCP(ssp) (&(ssp)->ss_co)
/*
- * This is used internally to pass all the info about
- * some VC that an ioctl caller is looking for.
- */
-struct smb_vcspec {
- char *srvname;
- struct sockaddr *sap;
- struct sockaddr *lap;
- int optflags;
- char *domain;
- char *username;
- char *pass;
- uid_t owner;
- gid_t group;
- mode_t mode;
- mode_t rights;
- char *localcs;
- char *servercs;
- size_t toklen;
- caddr_t tok;
-};
-typedef struct smb_vcspec smb_vcspec_t;
-
-/*
- * This is used internally to pass all the info about
- * some share that an ioctl caller is looking for.
- */
-struct smb_sharespec {
- char *name;
- char *pass;
- mode_t mode;
- mode_t rights;
- uid_t owner;
- gid_t group;
- int stype;
- int optflags;
-};
-typedef struct smb_sharespec smb_sharespec_t;
-
-
-/*
* Call-back operations vector, so the netsmb module
* can notify smbfs about events affecting mounts.
* Installed in netsmb after smbfs loads.
*/
-/* #define NEED_SMBFS_CALLBACKS 1 */
-#ifdef NEED_SMBFS_CALLBACKS
typedef struct smb_fscb {
- void (*fscb_dead)(smb_share_t *);
+ /* Called when the VC has disconnected. */
+ void (*fscb_disconn)(smb_share_t *);
+ /* Called when the VC has reconnected. */
+ void (*fscb_connect)(smb_share_t *);
+ /* Called when the server becomes unresponsive. */
void (*fscb_down)(smb_share_t *);
+ /* Called when the server is responding again. */
void (*fscb_up)(smb_share_t *);
} smb_fscb_t;
/* Install the above vector, or pass NULL to clear it. */
int smb_fscb_set(smb_fscb_t *);
-#endif /* NEED_SMBFS_CALLBACKS */
+
+/*
+ * The driver per open instance object.
+ * Mostly used in: smb_dev.c, smb_usr.c
+ */
+typedef struct smb_dev {
+ int sd_opened; /* Opened or not */
+ int sd_level; /* Future use */
+ struct smb_vc *sd_vc; /* Reference to VC */
+ struct smb_share *sd_share; /* Reference to share if any */
+ int sd_vcgenid; /* Generation of share or VC */
+ int sd_poll; /* Future use */
+ int sd_seq; /* Kind of minor number/instance no */
+ int sd_flags; /* State of connection */
+#define NSMBFL_OPEN 0x0001
+#define NSMBFL_IOD 0x0002
+ zoneid_t zoneid; /* Zone id */
+ dev_info_t *smb_dip; /* ptr to dev_info node */
+ void *sd_devfs; /* Dont know how to use this. but */
+ struct cred *smb_cred; /* per dev credentails. Future use */
+} smb_dev_t;
+
+extern const uint32_t nsmb_version;
+
+/*
+ * smb_dev.c
+ */
+int smb_dev2share(int fd, struct smb_share **sspp);
+
+
+/*
+ * smb_usr.c
+ */
+int smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags);
+int smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags);
+
+int smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr);
+int smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr);
+int smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr);
+
+int smb_usr_get_ssn(smb_dev_t *, int, intptr_t, int, cred_t *);
+int smb_usr_drop_ssn(smb_dev_t *sdp, int cmd);
+
+int smb_usr_get_tree(smb_dev_t *, int, intptr_t, int, cred_t *);
+int smb_usr_drop_tree(smb_dev_t *sdp, int cmd);
+
+int smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr);
+int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags);
+
/*
* IOD functions
*/
-int smb_iod_create(struct smb_vc *vcp);
-int smb_iod_destroy(struct smb_vc *vcp);
-int smb_iod_connect(struct smb_vc *vcp);
-int smb_iod_disconnect(struct smb_vc *vcp);
+int smb_iod_create(smb_vc_t *vcp);
+int smb_iod_destroy(smb_vc_t *vcp);
+int smb_iod_connect(smb_vc_t *vcp);
+int smb_iod_disconnect(smb_vc_t *vcp);
int smb_iod_addrq(struct smb_rq *rqp);
int smb_iod_multirq(struct smb_rq *rqp);
int smb_iod_waitrq(struct smb_rq *rqp);
int smb_iod_removerq(struct smb_rq *rqp);
-void smb_iod_shutdown_share(struct smb_share *ssp);
-void smb_iod_notify_down(struct smb_vc *vcp);
-void smb_iod_notify_up(struct smb_vc *vcp);
+void smb_iod_shutdown_share(smb_share_t *ssp);
+
+void smb_iod_sendall(smb_vc_t *);
+int smb_iod_recvall(smb_vc_t *);
+
+int smb_iod_vc_work(smb_vc_t *, cred_t *);
+int smb_iod_vc_idle(smb_vc_t *);
+int smb_iod_vc_rcfail(smb_vc_t *);
+int smb_iod_reconnect(smb_vc_t *);
/*
* Session level functions
@@ -425,63 +353,45 @@ int smb_sm_init(void);
int smb_sm_idle(void);
void smb_sm_done(void);
-int smb_sm_findvc(struct smb_vcspec *vcspec,
- struct smb_cred *scred, struct smb_vc **vcpp);
-int smb_sm_negotiate(struct smb_vcspec *vcspec,
- struct smb_cred *scred, struct smb_vc **vcpp);
-int smb_sm_ssnsetup(struct smb_vcspec *vcspec,
- struct smb_cred *scred, struct smb_vc *vcp);
-int smb_sm_tcon(struct smb_sharespec *shspec, struct smb_cred *scred,
- struct smb_vc *vcp, struct smb_share **sspp);
-
/*
* VC level functions
*/
-int smb_vc_setup(struct smb_vcspec *vcspec, struct smb_cred *scred,
- struct smb_vc *vcp, int is_ss);
-int smb_vc_create(struct smb_vcspec *vcspec,
- struct smb_cred *scred, struct smb_vc **vcpp);
-int smb_vc_negotiate(struct smb_vc *vcp, struct smb_cred *scred);
-int smb_vc_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred);
-void smb_vc_hold(struct smb_vc *vcp);
-void smb_vc_rele(struct smb_vc *vcp);
-void smb_vc_kill(struct smb_vc *vcp);
-int smb_vc_lookupshare(struct smb_vc *vcp, struct smb_sharespec *shspec,
- struct smb_cred *scred, struct smb_share **sspp);
-const char *smb_vc_getpass(struct smb_vc *vcp);
-uint16_t smb_vc_nextmid(struct smb_vc *vcp);
-void *smb_vc_getipaddr(struct smb_vc *vcp, int *ipvers);
+void smb_vc_hold(smb_vc_t *vcp);
+void smb_vc_rele(smb_vc_t *vcp);
+void smb_vc_kill(smb_vc_t *vcp);
+
+int smb_vc_findcreate(smbioc_ossn_t *, smb_cred_t *, smb_vc_t **);
+int smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp);
+
+const char *smb_vc_getpass(smb_vc_t *vcp);
+uint16_t smb_vc_nextmid(smb_vc_t *vcp);
+void *smb_vc_getipaddr(smb_vc_t *vcp, int *ipvers);
+
+typedef void (*walk_share_func_t)(smb_share_t *);
+void smb_vc_walkshares(struct smb_vc *, walk_share_func_t);
/*
* share level functions
*/
-int smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec,
- struct smb_cred *scred, struct smb_share **sspp);
-void smb_share_hold(struct smb_share *ssp);
-void smb_share_rele(struct smb_share *ssp);
-void smb_share_kill(struct smb_share *ssp);
+int smb_share_findcreate(smbioc_tcon_t *, smb_vc_t *,
+ smb_share_t **, smb_cred_t *);
+
+void smb_share_hold(smb_share_t *ssp);
+void smb_share_rele(smb_share_t *ssp);
+void smb_share_kill(smb_share_t *ssp);
-void smb_share_invalidate(struct smb_share *ssp);
-int smb_share_tcon(struct smb_share *ssp);
-int smb_share_valid(struct smb_share *ssp);
-const char *smb_share_getpass(struct smb_share *ssp);
-int smb_share_count(void);
+void smb_share_invalidate(smb_share_t *ssp);
+int smb_share_tcon(smb_share_t *, smb_cred_t *);
/*
* SMB protocol level functions
*/
-int smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred);
-int smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred);
-int smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred);
-int smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred);
-int smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred);
-int smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo);
-#ifdef APPLE
-int smb_smb_checkdir(struct smb_share *ssp, void *dnp,
- char *name, int nmlen, struct smb_cred *scred);
-#endif
-int smb_rwuio(struct smb_share *ssp, uint16_t fid, uio_rw_t rw,
- uio_t *uiop, struct smb_cred *scred, int timo);
+int smb_smb_echo(smb_vc_t *vcp, smb_cred_t *scred, int timo);
+int smb_smb_treeconnect(smb_share_t *ssp, smb_cred_t *scred);
+int smb_smb_treedisconnect(smb_share_t *ssp, smb_cred_t *scred);
+
+int smb_rwuio(smb_share_t *ssp, uint16_t fid, uio_rw_t rw,
+ uio_t *uiop, smb_cred_t *scred, int timo);
#endif /* _SMB_CONN_H */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_crypt.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_crypt.c
deleted file mode 100644
index 10d77644de..0000000000
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_crypt.c
+++ /dev/null
@@ -1,662 +0,0 @@
-/*
- * Copyright (c) 2000-2001, Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id: smb_crypt.c,v 1.13 2005/01/26 23:50:50 lindak Exp $
- */
-
-/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/conf.h>
-#include <sys/proc.h>
-#include <sys/fcntl.h>
-#include <sys/socket.h>
-#include <sys/md4.h>
-#include <sys/md5.h>
-#include <sys/des.h>
-#include <sys/kmem.h>
-#include <sys/crypto/api.h>
-#include <sys/crypto/common.h>
-#include <sys/cmn_err.h>
-#include <sys/stream.h>
-#include <sys/strsun.h>
-#include <sys/sdt.h>
-
-#include <netsmb/smb_osdep.h>
-#include <netsmb/smb.h>
-#include <netsmb/smb_conn.h>
-#include <netsmb/smb_subr.h>
-#include <netsmb/smb_dev.h>
-#include <netsmb/smb_rq.h>
-
-#ifdef DEBUG
-/*
- * Set this to a small number to debug sequence numbers
- * that seem to get out of step.
- */
-int nsmb_signing_fudge = 0;
-#endif
-
-/* Mechanism definitions */
-static crypto_mechanism_t crypto_mech_md5 = { CRYPTO_MECH_INVALID };
-static crypto_mechanism_t crypto_mech_des = { CRYPTO_MECH_INVALID };
-
-void
-smb_crypto_mech_init(void)
-{
- crypto_mech_des.cm_type = crypto_mech2id(SUN_CKM_DES_ECB);
- crypto_mech_md5.cm_type = crypto_mech2id(SUN_CKM_MD5);
-}
-
-static void
-smb_E(const uchar_t *key, const uchar_t *data, uchar_t *dest)
-{
- int rv;
- uchar_t kk[8];
- crypto_data_t d1, d2;
- crypto_key_t keyt;
-
-
- bzero(&d1, sizeof (crypto_data_t));
- bzero(&d2, sizeof (crypto_data_t));
- /*
- * 'Key' here is the username - 7-bytes. Convert that to
- * to a 8-byte string.
- */
- kk[0] = key[0] & 0xfe;
- kk[1] = key[0] << 7 | (key[1] >> 1 & 0xfe);
- kk[2] = key[1] << 6 | (key[2] >> 2 & 0xfe);
- kk[3] = key[2] << 5 | (key[3] >> 3 & 0xfe);
- kk[4] = key[3] << 4 | (key[4] >> 4 & 0xfe);
- kk[5] = key[4] << 3 | (key[5] >> 5 & 0xfe);
- kk[6] = key[5] << 2 | (key[6] >> 6 & 0xfe);
- kk[7] = key[6] << 1;
-
- keyt.ck_format = CRYPTO_KEY_RAW;
- keyt.ck_length = 8 * 8;
- keyt.ck_data = (void *)kk;
-
- d1.cd_format = CRYPTO_DATA_RAW;
- d1.cd_length = 8;
- d1.cd_offset = 0;
- d1.cd_raw.iov_len = 8;
- d1.cd_raw.iov_base = (void *)data;
-
- d2.cd_format = CRYPTO_DATA_RAW;
- d2.cd_length = 8;
- d2.cd_offset = 0;
- d2.cd_raw.iov_len = 8;
- d2.cd_raw.iov_base = (void *)dest;
-
- /* Checked this in callers */
- ASSERT(crypto_mech_des.cm_type != CRYPTO_MECH_INVALID);
-
- rv = crypto_encrypt(&crypto_mech_des, &d1, &keyt, NULL, &d2, NULL);
- if (rv != CRYPTO_SUCCESS)
- SMBSDEBUG("crypto_encrypt failed.\n");
-}
-
-/*
- * Compute the LM hash, which is used to compute the LM response.
- */
-void
-smb_oldlm_hash(const char *apwd, uchar_t *lmhash)
-{
- static const uchar_t N8[] = "KGS!@#$%";
- uchar_t P14[14+1];
-
- /* In case we error out. */
- bzero(lmhash, 21);
-
- /* Note ASSERT in smb_E */
- if (crypto_mech_des.cm_type == CRYPTO_MECH_INVALID) {
- SMBSDEBUG("crypto_mech_des invalid\n");
- return;
- }
-
- /* Convert apwd to upper case, zero extend. */
- bzero(P14, sizeof (P14));
- smb_toupper(apwd, (char *)P14, 14);
-
- /*
- * lmhash = concat(Ex(P14, N8), zeros(5));
- */
- smb_E(P14, N8, lmhash);
- smb_E(P14 + 7, N8, lmhash + 8);
-}
-
-/*
- * Compute an LM or NTLM response given the LM or NTLM hash and a
- * challenge. Note: This now replaces smb_ntlmresponse which
- * used to compute a different hash and then do the same
- * response computation as found here. Now that the hash
- * is computed by the caller, this is used for both.
- */
-int
-smb_lmresponse(const uchar_t *hash, const uchar_t *C8, uchar_t *RN)
-{
-
- /* In case we error out. */
- bzero(RN, 24);
-
- /* Note ASSERT in smb_E */
- if (crypto_mech_des.cm_type == CRYPTO_MECH_INVALID) {
- SMBSDEBUG("crypto_mech_des invalid\n");
- return (ENOTSUP);
- }
-
- smb_E(hash, C8, RN);
- smb_E(hash + 7, C8, RN + 8);
- smb_E(hash + 14, C8, RN + 16);
-
- return (0);
-}
-
-/*
- * Compute the NTLMv1 hash, which is used to compute both NTLMv1 and
- * NTLMv2 responses.
- */
-void
-smb_ntlmv1hash(const char *apwd, uchar_t *v1hash)
-{
- u_int16_t *unipwd;
- MD4_CTX *ctxp;
- size_t alen, unilen;
-
- alen = strlen(apwd);
- unipwd = kmem_alloc(alen * 2, KM_SLEEP);
- /*
- * v1hash = concat(MD4(U(apwd)), zeros(5));
- */
- unilen = smb_strtouni(unipwd, apwd, alen, UCONV_IGNORE_NULL);
-
- ctxp = kmem_alloc(sizeof (MD4_CTX), KM_SLEEP);
- MD4Init(ctxp);
- MD4Update(ctxp, unipwd, unilen);
- bzero(v1hash, 21);
- MD4Final(v1hash, ctxp);
-
- kmem_free(ctxp, sizeof (MD4_CTX));
- kmem_free(unipwd, alen * 2);
-}
-
-/*
- * Note: smb_ntlmresponse() is gone.
- * Use: smb_lmresponse() instead.
- */
-
-static void
-HMACT64(const uchar_t *key, size_t key_len, const uchar_t *data,
- size_t data_len, uchar_t *digest)
-{
- MD5_CTX context;
- uchar_t k_ipad[64]; /* inner padding - key XORd with ipad */
- uchar_t k_opad[64]; /* outer padding - key XORd with opad */
- int i;
-
- /* if key is longer than 64 bytes use only the first 64 bytes */
- if (key_len > 64)
- key_len = 64;
-
- /*
- * The HMAC-MD5 (and HMACT64) transform looks like:
- *
- * MD5(K XOR opad, MD5(K XOR ipad, data))
- *
- * where K is an n byte key
- * ipad is the byte 0x36 repeated 64 times
- * opad is the byte 0x5c repeated 64 times
- * and data is the data being protected.
- */
-
- /* start out by storing key in pads */
- bzero(k_ipad, sizeof (k_ipad));
- bzero(k_opad, sizeof (k_opad));
- bcopy(key, k_ipad, key_len);
- bcopy(key, k_opad, key_len);
-
- /* XOR key with ipad and opad values */
- for (i = 0; i < 64; i++) {
- k_ipad[i] ^= 0x36;
- k_opad[i] ^= 0x5c;
- }
-
- /*
- * perform inner MD5
- */
- MD5Init(&context); /* init context for 1st pass */
- MD5Update(&context, k_ipad, 64); /* start with inner pad */
- MD5Update(&context, data, data_len); /* then data of datagram */
- MD5Final(digest, &context); /* finish up 1st pass */
-
- /*
- * perform outer MD5
- */
- MD5Init(&context); /* init context for 2nd pass */
- MD5Update(&context, k_opad, 64); /* start with outer pad */
- MD5Update(&context, digest, 16); /* then results of 1st hash */
- MD5Final(digest, &context); /* finish up 2nd pass */
-}
-
-/*
- * Compute an NTLMv2 hash given the NTLMv1 hash, the user name,
- * the destination machine or domain name, and a challenge.
- */
-void
-smb_ntlmv2hash(const uchar_t *v1hash, const char *user,
- const char *destination, uchar_t *v2hash)
-{
- u_int16_t *uniuser, *unidest;
- size_t uniuserlen, unidestlen;
- size_t uniuser_sz, unidest_sz;
- int len;
- size_t datalen;
- uchar_t *data;
-
- /*
- * v2hash = HMACT64(v1hash, 16, concat(upcase(user), upcase(dest))
- * where "dest" is the domain or server name ("target name")
- * We assume that user and destination are supplied to us as
- * upper-case UTF-8.
- */
- len = strlen((char *)user);
- uniuser_sz = (len + 1) * sizeof (u_int16_t);
- uniuser = kmem_alloc(uniuser_sz, KM_SLEEP);
- uniuserlen = smb_strtouni(uniuser, (char *)user, len,
- UCONV_IGNORE_NULL);
-
- len = strlen((char *)destination);
- unidest_sz = (len + 1) * sizeof (u_int16_t);
- unidest = kmem_alloc(unidest_sz, KM_SLEEP);
- unidestlen = smb_strtouni(unidest, (char *)destination, len,
- UCONV_IGNORE_NULL);
-
- datalen = uniuserlen + unidestlen;
- data = kmem_alloc(datalen, KM_SLEEP);
- bcopy(uniuser, data, uniuserlen);
- bcopy(unidest, data + uniuserlen, unidestlen);
- kmem_free(uniuser, uniuser_sz);
- kmem_free(unidest, unidest_sz);
-
- HMACT64(v1hash, 16, data, datalen, v2hash);
- kmem_free(data, datalen);
-}
-
-/*
- * Compute an NTLMv2 response given the 16 byte NTLMv2 hash,
- * a challenge, and the blob.
- */
-int
-smb_ntlmv2response(const uchar_t *v2hash, const uchar_t *C8,
- const uchar_t *blob, size_t bloblen, uchar_t **RN, size_t *RNlen)
-{
- size_t datalen;
- uchar_t *data;
- size_t v2resplen;
- uchar_t *v2resp;
-
- datalen = 8 + bloblen;
- data = kmem_alloc(datalen, KM_SLEEP);
- bcopy(C8, data, 8);
- bcopy(blob, data + 8, bloblen);
- v2resplen = 16 + bloblen;
- v2resp = kmem_alloc(v2resplen, KM_SLEEP);
- HMACT64(v2hash, 16, data, datalen, v2resp);
- kmem_free(data, datalen);
- bcopy(blob, v2resp + 16, bloblen);
- *RN = v2resp;
- *RNlen = v2resplen;
-
- return (0);
-}
-
-/*
- * Calculate NTLMv2 message authentication code (MAC) key for
- * this VC and store it in vc_mackey (allocated here).
- *
- * The MAC key is the concatenation of the 16 byte session key
- * and the NT response.
- *
- * XXX: Should factor out computation of the session key
- * from both this and the next function, and then use a
- * common function to compute the MAC key (which then
- * can do simple concatenation). Later.
- */
-int
-smb_calcv2mackey(struct smb_vc *vcp, const uchar_t *v2hash,
- const uchar_t *ntresp, size_t resplen)
-{
- uchar_t sesskey[16];
-
- if (vcp->vc_mackey != NULL) {
- SMBSDEBUG("Already have MAC key!\n");
- return (0);
- }
-
- /* session key uses only 1st 16 bytes of ntresp */
- HMACT64(v2hash, 16, ntresp, (size_t)16, sesskey);
-
- vcp->vc_mackeylen = 16 + resplen;
- vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP);
- /* Free in: smb_vc_free, smb_smb_negotiate */
-
- bcopy(sesskey, vcp->vc_mackey, 16);
- bcopy(ntresp, vcp->vc_mackey + 16, (int)resplen);
-
-#ifdef DTRACE_PROBE
- DTRACE_PROBE2(smb_mac_key, (char *), vcp->vc_mackey,
- int, vcp->vc_mackeylen);
-#endif
-
- return (0);
-}
-
-/*
- * Calculate message authentication code (MAC) key for virtual circuit.
- * The MAC key is the concatenation of the 16 byte session key
- * and the 24 byte challenge response.
- */
-/*ARGSUSED*/
-int
-smb_calcmackey(struct smb_vc *vcp, const uchar_t *v2hash,
- const uchar_t *ntresp, size_t resplen)
-{
- MD4_CTX md4;
-
- if (vcp->vc_mackey != NULL) {
- SMBSDEBUG("Already have MAC key!\n");
- return (0);
- }
-
- vcp->vc_mackeylen = 16 + 24;
- vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP);
- /* Free in: smb_vc_free, smb_smb_negotiate */
-
- /*
- * Calculate session key:
- */
- MD4Init(&md4);
- MD4Update(&md4, vcp->vc_nthash, 16);
- MD4Final(vcp->vc_mackey, &md4);
-
- /* Response to challenge. */
- bcopy(ntresp, vcp->vc_mackey + 16, 24);
-
-#ifdef DTRACE_PROBE
- DTRACE_PROBE2(smb_mac_key, (char *), vcp->vc_mackey,
- int, vcp->vc_mackeylen);
-#endif
-
- return (0);
-}
-
-#define SMBSIGLEN 8 /* SMB signature length */
-#define SMBSIGOFF 14 /* SMB signature offset */
-
-/*
- * Compute HMAC-MD5 of packet data, using the stored MAC key.
- *
- * See similar code for the server side:
- * uts/common/fs/smbsrv/smb_signing.c : smb_sign_calc
- */
-static int
-smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
- uint32_t seqno, uchar_t *signature)
-{
- crypto_context_t crypto_ctx;
- crypto_data_t key;
- crypto_data_t data;
- crypto_data_t digest;
- uchar_t mac[16];
- int status;
- /*
- * This union is a little bit of trickery to:
- * (1) get the sequence number int aligned, and
- * (2) reduce the number of digest calls, at the
- * cost of a copying 32 bytes instead of 8.
- * Both sides of this union are 2+32 bytes.
- */
- union {
- struct {
- uint8_t skip[2]; /* not used - just alignment */
- uint8_t raw[SMB_HDRLEN]; /* header length (32) */
- } r;
- struct {
- uint8_t skip[2]; /* not used - just alignment */
- uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
- uint32_t sig[2]; /* MAC signature, aligned! */
- uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
- } s;
- } smbhdr;
-
- ASSERT(mp != NULL);
- ASSERT(MBLKL(mp) >= SMB_HDRLEN);
- ASSERT(vcp->vc_mackey != NULL);
-
- /*
- * Make an aligned copy of the SMB header
- * and fill in the sequence number.
- */
- bcopy(mp->b_rptr, smbhdr.r.raw, SMB_HDRLEN);
- smbhdr.s.sig[0] = htolel(seqno);
- smbhdr.s.sig[1] = 0;
-
- /*
- * Compute the MAC: MD5(concat(Key, message))
- */
- if (crypto_mech_md5.cm_type == CRYPTO_MECH_INVALID) {
- SMBSDEBUG("crypto_mech_md5 invalid\n");
- return (CRYPTO_MECHANISM_INVALID);
- }
- status = crypto_digest_init(&crypto_mech_md5, &crypto_ctx, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
-
- /* Digest the MAC Key */
- key.cd_format = CRYPTO_DATA_RAW;
- key.cd_offset = 0;
- key.cd_length = vcp->vc_mackeylen;
- key.cd_miscdata = 0;
- key.cd_raw.iov_base = (char *)vcp->vc_mackey;
- key.cd_raw.iov_len = vcp->vc_mackeylen;
- status = crypto_digest_update(crypto_ctx, &key, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
-
- /* Digest the (copied) SMB header */
- data.cd_format = CRYPTO_DATA_RAW;
- data.cd_offset = 0;
- data.cd_length = SMB_HDRLEN;
- data.cd_miscdata = 0;
- data.cd_raw.iov_base = (char *)smbhdr.r.raw;
- data.cd_raw.iov_len = SMB_HDRLEN;
- status = crypto_digest_update(crypto_ctx, &data, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
-
- /* Digest rest of the SMB message. */
- data.cd_format = CRYPTO_DATA_MBLK;
- data.cd_offset = SMB_HDRLEN;
- data.cd_length = msgdsize(mp) - SMB_HDRLEN;
- data.cd_miscdata = 0;
- data.cd_mp = mp;
- status = crypto_digest_update(crypto_ctx, &data, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
-
- /* Final */
- digest.cd_format = CRYPTO_DATA_RAW;
- digest.cd_offset = 0;
- digest.cd_length = sizeof (mac);
- digest.cd_miscdata = 0;
- digest.cd_raw.iov_base = (char *)mac;
- digest.cd_raw.iov_len = sizeof (mac);
- status = crypto_digest_final(crypto_ctx, &digest, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
-
- /*
- * Finally, store the signature.
- * (first 8 bytes of the mac)
- */
- if (signature)
- bcopy(mac, signature, SMBSIGLEN);
-
- return (0);
-}
-
-/*
- * Sign a request with HMAC-MD5.
- */
-int
-smb_rq_sign(struct smb_rq *rqp)
-{
- struct smb_vc *vcp = rqp->sr_vc;
- mblk_t *mp = rqp->sr_rq.mb_top;
- uint8_t *sigloc;
- int status;
-
- /*
- * Our mblk allocation ensures this,
- * but just in case...
- */
- if (MBLKL(mp) < SMB_HDRLEN) {
- if (!pullupmsg(mp, SMB_HDRLEN))
- return (0);
- }
- sigloc = mp->b_rptr + SMBSIGOFF;
-
- if (vcp->vc_mackey == NULL) {
- /*
- * Signing is required, but we have no key yet
- * fill in with the magic fake signing value.
- * This happens with SPNEGO, NTLMSSP, ...
- */
- bcopy("BSRSPLY", sigloc, 8);
- return (0);
- }
-
- /*
- * This will compute the MAC and store it
- * directly into the message at sigloc.
- */
- status = smb_compute_MAC(vcp, mp, rqp->sr_seqno, sigloc);
- if (status != CRYPTO_SUCCESS) {
- SMBSDEBUG("Crypto error %d", status);
- bzero(sigloc, SMBSIGLEN);
- return (ENOTSUP);
- }
- return (0);
-}
-
-/*
- * Verify reply signature.
- */
-int
-smb_rq_verify(struct smb_rq *rqp)
-{
- struct smb_vc *vcp = rqp->sr_vc;
- mblk_t *mp = rqp->sr_rp.md_top;
- uint8_t sigbuf[SMBSIGLEN];
- uint8_t *sigloc;
- int status;
- int fudge;
-
- /*
- * Note vc_mackey and vc_mackeylen gets initialized by
- * smb_smb_ssnsetup.
- */
- if (vcp->vc_mackey == NULL) {
- SMBSDEBUG("no mac key\n");
- return (0);
- }
-
- /*
- * Let caller deal with empty reply or short messages by
- * returning zero. Caller will fail later, in parsing.
- */
- if (mp == NULL) {
- SMBSDEBUG("empty reply\n");
- return (0);
- }
- if (MBLKL(mp) < SMB_HDRLEN) {
- if (!pullupmsg(mp, SMB_HDRLEN))
- return (0);
- }
- sigloc = mp->b_rptr + SMBSIGOFF;
-
- SMBSDEBUG("sr_rseqno = 0x%x\n", rqp->sr_rseqno);
-
- status = smb_compute_MAC(vcp, mp, rqp->sr_rseqno, sigbuf);
- if (status != CRYPTO_SUCCESS) {
- SMBSDEBUG("Crypto error %d", status);
- /*
- * If we can't compute a MAC, then there's
- * no point trying other seqno values.
- */
- return (EBADRPC);
- }
-
- /*
- * Compare the computed signature with the
- * one found in the message (at sigloc)
- */
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
- return (0);
-
- SMBSDEBUG("BAD signature, MID=0x%x\n", rqp->sr_mid);
-
-#ifdef DEBUG
- /*
- * For diag purposes, we check whether the client/server idea
- * of the sequence # has gotten a bit out of sync.
- */
- for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) {
- smb_compute_MAC(vcp, mp, rqp->sr_rseqno + fudge, sigbuf);
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
- break;
- smb_compute_MAC(vcp, mp, rqp->sr_rseqno - fudge, sigbuf);
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) {
- fudge = -fudge;
- break;
- }
- }
- if (fudge <= nsmb_signing_fudge) {
- SMBSDEBUG("sr_rseqno=%d, but %d would have worked\n",
- rqp->sr_rseqno, rqp->sr_rseqno + fudge);
- }
-#endif
- return (EBADRPC);
-}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
index 29795281f4..8ec7daef1c 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -114,6 +114,8 @@ static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp);
static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp);
static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
cred_t *credp, int *rvalp);
+static int nsmb_close2(smb_dev_t *sdp, cred_t *cr);
+
/* smbfs cb_ops */
static struct cb_ops nsmb_cbops = {
nsmb_open, /* open */
@@ -165,7 +167,7 @@ static struct dev_ops nsmb_ops = {
static struct modldrv nsmb_modldrv = {
&mod_driverops, /* Driver module */
- "SMBFS network driver v" NSMB_VER_STR,
+ "SMBFS network driver",
&nsmb_ops /* Driver ops */
};
@@ -350,26 +352,11 @@ nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
/*ARGSUSED*/
static int
-nsmb_ioctl(dev_t dev,
- int cmd,
- intptr_t arg,
- int mode,
- cred_t *credp,
- int *rvalp)
+nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */
+ cred_t *cr, int *rvalp)
{
smb_dev_t *sdp;
- struct smb_vc *vcp = NULL;
- struct smb_share *ssp = NULL;
- struct smb_cred scred;
- int err, error;
- uid_t uid;
-
- /* Free any+all of these at end of switch. */
- smbioc_lookup_t *sioc = NULL;
- smbioc_rq_t *srq = NULL;
- smbioc_rw_t *rwrq = NULL;
- smbioc_t2rq_t *strq = NULL;
- smbioc_pk_t *pk = NULL;
+ int err;
sdp = ddi_get_soft_state(statep, getminor(dev));
if (sdp == NULL) {
@@ -386,413 +373,85 @@ nsmb_ioctl(dev_t dev,
*/
if (sdp->zoneid != getzoneid())
return (EIO);
- if (cmd != SMBIOC_TDIS &&
- zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN)
- return (EIO);
+ /*
+ * We have a zone_shutdown call back that kills all the VCs
+ * in a zone that's shutting down. That action will cause
+ * all of these ioctls to fail on such VCs, so no need to
+ * check the zone status here on every ioctl call.
+ */
- error = 0;
- smb_credinit(&scred, curproc, credp);
+ err = 0;
switch (cmd) {
- case SMBIOC_GETVERS:
- ddi_copyout(&nsmb_version, (void *)arg,
- sizeof (nsmb_version), mode);
- break;
-
- case SMBIOC_REQUEST:
- if (sdp->sd_share == NULL) {
- error = ENOTCONN;
- break;
- }
- srq = kmem_alloc(sizeof (*srq), KM_SLEEP);
- if (ddi_copyin((void *) arg, srq,
- sizeof (*srq), mode)) {
- error = EFAULT;
- break;
- }
- error = smb_usr_simplerequest(sdp->sd_share,
- srq, &scred);
- ddi_copyout(srq, (void *)arg,
- SMBIOC_RQ_COPYOUT_SIZE, mode);
- break;
-
- case SMBIOC_T2RQ:
- if (sdp->sd_share == NULL) {
- error = ENOTCONN;
- break;
- }
- strq = kmem_alloc(sizeof (*strq), KM_SLEEP);
- if (ddi_copyin((void *)arg, strq,
- sizeof (*strq), mode)) {
- error = EFAULT;
- break;
- }
- error = smb_usr_t2request(sdp->sd_share, strq, &scred);
- ddi_copyout(strq, (void *)arg,
- SMBIOC_T2RQ_COPYOUT_SIZE, mode);
- break;
-
- case SMBIOC_READ:
- case SMBIOC_WRITE:
- if ((ssp = sdp->sd_share) == NULL) {
- error = ENOTCONN;
- break;
- }
- rwrq = kmem_alloc(sizeof (*rwrq), KM_SLEEP);
- if (ddi_copyin((void *)arg, rwrq,
- sizeof (*rwrq), mode)) {
- error = EFAULT;
- break;
- }
- error = smb_usr_rw(ssp, rwrq, cmd, &scred);
- ddi_copyout(rwrq, (void *)arg,
- SMBIOC_RW_COPYOUT_SIZE, mode);
- break;
-
- case SMBIOC_FINDVC:
- /* Should be no VC and no share */
- if (sdp->sd_vc || sdp->sd_share) {
- error = EISCONN;
- break;
- }
- sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
- if (ddi_copyin((void *)arg, sioc,
- sizeof (*sioc), mode)) {
- error = EFAULT;
- break;
- }
- vcp = NULL;
- ssp = NULL;
- error = smb_usr_findvc(sioc, &scred, &vcp);
- if (error)
- break;
- if (vcp) {
- /*
- * The VC has a hold from _findvc
- * which we keep until nsmb_close().
- */
- sdp->sd_level = SMBL_VC;
- sdp->sd_vc = vcp;
- }
- (void) ddi_copyout(sioc, (void *)arg,
- SMBIOC_LOOK_COPYOUT_SIZE, mode);
-
- break;
-
- case SMBIOC_NEGOTIATE:
- /* Should be no VC (and no share) */
- if (sdp->sd_vc || sdp->sd_share) {
- error = EISCONN;
- break;
- }
- sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
- if (ddi_copyin((void *)arg, sioc,
- sizeof (*sioc), mode)) {
- error = EFAULT;
- break;
- }
- vcp = NULL;
- ssp = NULL;
- error = smb_usr_negotiate(sioc, &scred, &vcp);
- if (error)
- break;
- if (vcp) {
- /*
- * The VC has a hold from _negotiate
- * which we keep until nsmb_close().
- */
- sdp->sd_level = SMBL_VC;
- sdp->sd_vc = vcp;
- /*
- * If we just created this VC, and
- * this minor is doing the setup,
- * keep track of that fact here.
- */
- if (vcp->vc_state < SMBIOD_ST_VCACTIVE)
- sdp->sd_flags |= NSMBFL_NEWVC;
-
- }
- /*
- * Copyout the "out token" (security blob).
- *
- * This code used to be near the end of
- * smb_usr_negotiate(). Moved the copyout
- * calls here so we know the "mode"
- */
- if (vcp->vc_outtok) {
- /*
- * Note: will copyout sioc below
- * including sioc.vc_outtoklen,
- * so we no longer put the length
- * at the start of the outtok data.
- */
- sioc->ioc_ssn.ioc_outtoklen =
- vcp->vc_outtoklen;
- err = ddi_copyout(
- vcp->vc_outtok,
- sioc->ioc_ssn.ioc_outtok,
- vcp->vc_outtoklen, mode);
- if (err) {
- error = EFAULT;
- break;
- }
- /*
- * Save this blob in vc_negtok.
- * We need it in case we have to
- * reconnect.
- *
- * Set vc_negtok = vc_outtok
- * but free vc_negtok first.
- */
- if (vcp->vc_negtok) {
- kmem_free(
- vcp->vc_negtok,
- vcp->vc_negtoklen);
- vcp->vc_negtok = NULL;
- vcp->vc_negtoklen = 0;
- }
- vcp->vc_negtok = vcp->vc_outtok;
- vcp->vc_negtoklen = vcp->vc_outtoklen;
- vcp->vc_outtok = NULL;
- vcp->vc_outtoklen = 0;
- }
- /*
- * Added copyout here of (almost)
- * the whole struct, even though
- * the lib only needs _outtoklen.
- * We may put other things in this
- * struct that user-land needs.
- */
- err = ddi_copyout(sioc, (void *)arg,
- SMBIOC_LOOK_COPYOUT_SIZE, mode);
- if (err)
- error = EFAULT;
- break;
-
- case SMBIOC_SSNSETUP:
- /* Must have a VC, but no share. */
- if (sdp->sd_share) {
- error = EISCONN;
- break;
- }
- if (!sdp->sd_vc) {
- error = ENOTCONN;
- break;
- }
- sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
- if (ddi_copyin((void *)arg, sioc,
- sizeof (*sioc), mode)) {
- error = EFAULT;
- break;
- }
- vcp = sdp->sd_vc;
- ssp = NULL;
- error = smb_usr_ssnsetup(sioc, &scred, vcp);
- if (error)
- break;
- /*
- * If this minor has finished ssn setup,
- * turn off the NEWVC flag, otherwise we
- * will kill this VC when we close.
- */
- if (vcp->vc_state == SMBIOD_ST_VCACTIVE)
- sdp->sd_flags &= ~NSMBFL_NEWVC;
- /*
- * Copyout the "out token" (security blob).
- *
- * This code used to be near the end of
- * smb_usr_ssnsetup(). Moved the copyout
- * calls here so we know the "mode"
- */
- if (vcp->vc_outtok) {
- /*
- * Note: will copyout sioc below
- * including sioc.vc_outtoklen,
- * so we no longer put the length
- * at the start of the outtok data.
- */
- sioc->ioc_ssn.ioc_outtoklen =
- vcp->vc_outtoklen;
- err = ddi_copyout(
- vcp->vc_outtok,
- sioc->ioc_ssn.ioc_outtok,
- vcp->vc_outtoklen, mode);
- if (err) {
- error = EFAULT;
- break;
- }
- /*
- * Done with vc_outtok. Similar,
- * but NOT the same as after the
- * smb_usr_negotiate call above.
- */
- kmem_free(
- vcp->vc_outtok,
- vcp->vc_outtoklen);
- vcp->vc_outtok = NULL;
- vcp->vc_outtoklen = 0;
- }
- /* Added copyout here... (see above) */
- err = ddi_copyout(sioc, (void *)arg,
- SMBIOC_LOOK_COPYOUT_SIZE, mode);
- if (err)
- error = EFAULT;
- break;
-
- case SMBIOC_TCON:
- /* Must have a VC, but no share. */
- if (sdp->sd_share) {
- error = EISCONN;
- break;
- }
- if (!sdp->sd_vc) {
- error = ENOTCONN;
- break;
- }
- sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
- if (ddi_copyin((void *)arg, sioc,
- sizeof (*sioc), mode)) {
- error = EFAULT;
- break;
- }
- vcp = sdp->sd_vc;
- ssp = NULL;
- error = smb_usr_tcon(sioc, &scred, vcp, &ssp);
- if (error)
- break;
- if (ssp) {
- /*
- * The share has a hold from _tcon
- * which we keep until nsmb_close()
- * or the SMBIOC_TDIS below.
- */
- sdp->sd_share = ssp;
- sdp->sd_level = SMBL_SHARE;
- }
- /* No need for copyout here. */
- break;
+ case SMBIOC_GETVERS:
+ ddi_copyout(&nsmb_version, (void *)arg,
+ sizeof (nsmb_version), flags);
+ break;
- case SMBIOC_TDIS:
- if (sdp->sd_share == NULL) {
- error = ENOTCONN;
- break;
- }
- smb_share_rele(sdp->sd_share);
- sdp->sd_share = NULL;
- sdp->sd_level = SMBL_VC;
- break;
- case SMBIOC_FLAGS2:
- if (sdp->sd_share == NULL) {
- error = ENOTCONN;
- break;
- }
- if (!sdp->sd_vc) {
- error = ENOTCONN;
- break;
- }
- vcp = sdp->sd_vc;
- /*
- * Return the flags2 value.
- */
- ddi_copyout(&vcp->vc_hflags2, (void *)arg,
- sizeof (u_int16_t), mode);
- break;
+ case SMBIOC_FLAGS2:
+ err = smb_usr_get_flags2(sdp, arg, flags);
+ break;
- case SMBIOC_PK_ADD:
- pk = kmem_alloc(sizeof (*pk), KM_SLEEP);
- if (ddi_copyin((void *)arg, pk,
- sizeof (*pk), mode)) {
- error = EFAULT;
- break;
- }
- error = smb_pkey_add(pk, credp);
- break;
+ case SMBIOC_GETSSNKEY:
+ err = smb_usr_get_ssnkey(sdp, arg, flags);
+ break;
- case SMBIOC_PK_DEL:
- pk = kmem_alloc(sizeof (*pk), KM_SLEEP);
- if (ddi_copyin((void *)arg, pk,
- sizeof (*pk), mode)) {
- error = EFAULT;
- break;
- }
- error = smb_pkey_del(pk, credp);
- break;
+ case SMBIOC_REQUEST:
+ err = smb_usr_simplerq(sdp, arg, flags, cr);
+ break;
- case SMBIOC_PK_CHK:
- pk = kmem_alloc(sizeof (*pk), KM_SLEEP);
- if (ddi_copyin((void *)arg, pk,
- sizeof (*pk), mode)) {
- error = EFAULT;
- break;
- }
- error = smb_pkey_check(pk, credp);
- /*
- * Note: Intentionally DO NOT copyout
- * the pasword here. It can only be
- * retrieved by internal calls. This
- * ioctl only tells the caller if the
- * keychain entry exists.
- */
- break;
+ case SMBIOC_T2RQ:
+ err = smb_usr_t2request(sdp, arg, flags, cr);
+ break;
- case SMBIOC_PK_DEL_OWNER:
- uid = crgetruid(credp);
- error = smb_pkey_deluid(uid, credp);
- break;
+ case SMBIOC_READ:
+ case SMBIOC_WRITE:
+ err = smb_usr_rw(sdp, cmd, arg, flags, cr);
+ break;
- case SMBIOC_PK_DEL_EVERYONE:
- uid = (uid_t)-1;
- error = smb_pkey_deluid(uid, credp);
- break;
+ case SMBIOC_SSN_CREATE:
+ case SMBIOC_SSN_FIND:
+ err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
+ break;
- default:
- error = ENODEV;
- }
+ case SMBIOC_SSN_KILL:
+ case SMBIOC_SSN_RELE:
+ err = smb_usr_drop_ssn(sdp, cmd);
+ break;
- /*
- * Let's just do all the kmem_free stuff HERE,
- * instead of at every switch break.
- */
+ case SMBIOC_TREE_CONNECT:
+ case SMBIOC_TREE_FIND:
+ err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
+ break;
- /* SMBIOC_REQUEST */
- if (srq)
- kmem_free(srq, sizeof (*srq));
+ case SMBIOC_TREE_KILL:
+ case SMBIOC_TREE_RELE:
+ err = smb_usr_drop_tree(sdp, cmd);
+ break;
- /* SMBIOC_T2RQ */
- if (strq)
- kmem_free(strq, sizeof (*strq));
+ case SMBIOC_IOD_WORK:
+ err = smb_usr_iod_work(sdp, arg, flags, cr);
+ break;
- /* SMBIOC_READ */
- /* SMBIOC_WRITE */
- if (rwrq)
- kmem_free(rwrq, sizeof (*rwrq));
+ case SMBIOC_IOD_IDLE:
+ case SMBIOC_IOD_RCFAIL:
+ err = smb_usr_iod_ioctl(sdp, cmd, arg, flags);
+ break;
- /* SMBIOC_FINDVC */
- /* SMBIOC_NEGOTIATE */
- /* SMBIOC_SSNSETUP */
- /* SMBIOC_TCON */
- if (sioc) {
- /*
- * This data structure may contain
- * cleartext passwords, so zap it.
- */
- bzero(sioc, sizeof (*sioc));
- kmem_free(sioc, sizeof (*sioc));
- }
+ case SMBIOC_PK_ADD:
+ case SMBIOC_PK_DEL:
+ case SMBIOC_PK_CHK:
+ case SMBIOC_PK_DEL_OWNER:
+ case SMBIOC_PK_DEL_EVERYONE:
+ err = smb_pkey_ioctl(cmd, arg, flags, cr);
+ break;
- /* SMBIOC_PK_... */
- if (pk) {
- /*
- * This data structure may contain
- * cleartext passwords, so zap it.
- */
- bzero(pk, sizeof (*pk));
- kmem_free(pk, sizeof (*pk));
+ default:
+ err = ENOTTY;
+ break;
}
- smb_credrele(&scred);
-
- return (error);
+ return (err);
}
/*ARGSUSED*/
@@ -879,11 +538,9 @@ nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr)
static int
nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
{
- struct smb_vc *vcp;
- struct smb_share *ssp;
- struct smb_cred scred;
minor_t inst = getminor(dev);
smb_dev_t *sdp;
+ int err;
mutex_enter(&dev_lck);
/*
@@ -892,79 +549,90 @@ nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
* 3. Can close the minor number.
* 4. Deallocate any resources allocated in open() call.
*/
- smb_credinit(&scred, curproc, cr);
sdp = ddi_get_soft_state(statep, inst);
+ if (sdp != NULL)
+ err = nsmb_close2(sdp, cr);
+ else
+ err = ENXIO;
/*
- * time to call ddi_get_soft_state()
+ * Free the instance
*/
+ ddi_soft_state_free(statep, inst);
+ mutex_exit(&dev_lck);
+ return (err);
+}
+
+static int
+nsmb_close2(smb_dev_t *sdp, cred_t *cr)
+{
+ struct smb_vc *vcp;
+ struct smb_share *ssp;
+ struct smb_cred scred;
+
+ smb_credinit(&scred, cr);
ssp = sdp->sd_share;
if (ssp != NULL)
smb_share_rele(ssp);
vcp = sdp->sd_vc;
if (vcp != NULL) {
/*
- * If this dev minor was doing session setup
- * and failed to authenticate (or whatever)
- * then we need to put the VC in a state that
- * allows later commands to try again.
+ * If this dev minor was opened by smbiod,
+ * mark this VC as "dead" because it now
+ * will have no IOD to service it.
*/
- if (sdp->sd_flags & NSMBFL_NEWVC)
+ if (sdp->sd_flags & NSMBFL_IOD)
smb_iod_disconnect(vcp);
smb_vc_rele(vcp);
}
- smb_credrele(&scred);
- /*
- * Free the instance
- */
- ddi_soft_state_free(statep, inst);
- mutex_exit(&dev_lck);
+ smb_credrele(&scred);
return (0);
}
int
smb_dev2share(int fd, struct smb_share **sspp)
{
- register vnode_t *vp;
+ file_t *fp = NULL;
+ vnode_t *vp;
smb_dev_t *sdp;
- struct smb_share *ssp;
+ smb_share_t *ssp;
dev_t dev;
- file_t *fp;
+ int err;
if ((fp = getf(fd)) == NULL)
- return (set_errno(EBADF));
+ return (EBADF);
+
vp = fp->f_vnode;
dev = vp->v_rdev;
- if (dev == NULL) {
- releasef(fd);
- return (EBADF);
+ if (dev == 0 || dev == NODEV ||
+ getmajor(dev) != nsmb_major) {
+ err = EBADF;
+ goto out;
}
+
sdp = ddi_get_soft_state(statep, getminor(dev));
if (sdp == NULL) {
- releasef(fd);
- return (DDI_FAILURE);
+ err = EINVAL;
+ goto out;
}
+
ssp = sdp->sd_share;
if (ssp == NULL) {
- releasef(fd);
- return (ENOTCONN);
+ err = ENOTCONN;
+ goto out;
}
+
/*
- * The share is already locked and referenced by the TCON ioctl
- * We NULL to hand off share to caller (mount)
- * This allows further ioctls against connection, for instance
- * another tree connect and mount, in the automounter case
- *
- * We're effectively giving our reference to the mount.
- *
- * XXX: I'm not sure I like this. I'd rather see the ioctl
- * caller do something explicit to give up this reference,
- * (i.e. SMBIOC_TDIS above) and increment the hold here.
+ * Our caller gains a ref. to this share.
*/
- sdp->sd_share = NULL;
- releasef(fd);
*sspp = ssp;
- return (0);
+ smb_share_hold(ssp);
+ err = 0;
+
+out:
+ if (fp)
+ releasef(fd);
+ return (err);
}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
index b1c9c1d342..8f6e95de23 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -47,6 +47,7 @@
#include <sys/atomic.h>
#include <sys/proc.h>
#include <sys/thread.h>
+#include <sys/file.h>
#include <sys/kmem.h>
#include <sys/unistd.h>
#include <sys/mount.h>
@@ -76,7 +77,8 @@
#include <netsmb/smb_tran.h>
#include <netsmb/smb_trantcp.h>
-#ifdef NEED_SMBFS_CALLBACKS
+int smb_iod_send_echo(smb_vc_t *);
+
/*
* This is set/cleared when smbfs loads/unloads
* No locks should be necessary, because smbfs
@@ -89,28 +91,28 @@ smb_fscb_set(smb_fscb_t *cb)
fscb = cb;
return (0);
}
-#endif /* NEED_SMBFS_CALLBACKS */
-static void smb_iod_sendall(struct smb_vc *);
-static void smb_iod_recvall(struct smb_vc *);
-static void smb_iod_main(struct smb_vc *);
+static void
+smb_iod_share_disconnected(smb_share_t *ssp)
+{
+ smb_share_invalidate(ssp);
-#define SMBIOD_SLEEP_TIMO 2
-#define SMBIOD_PING_TIMO 60 /* seconds */
+ /* smbfs_dead() */
+ if (fscb && fscb->fscb_disconn) {
+ fscb->fscb_disconn(ssp);
+ }
+}
/*
- * After this many seconds we want an unresponded-to request to trigger
- * some sort of UE (dialogue). If the connection hasn't responded at all
- * in this many seconds then the dialogue is of the "connection isn't
- * responding would you like to force unmount" variety. If the connection
- * has been responding (to other requests that is) then we need a dialogue
- * of the "operation is still pending do you want to cancel it" variety.
- * At present this latter dialogue does not exist so we have no UE and
- * just keep waiting for the slow operation.
+ * State changes are important and infrequent.
+ * Make them easily observable via dtrace.
*/
-#define SMBUETIMEOUT 8 /* seconds */
-
+void
+smb_iod_newstate(struct smb_vc *vcp, int state)
+{
+ vcp->vc_state = state;
+}
/* Lock Held version of the next function. */
static inline void
@@ -153,130 +155,45 @@ smb_iod_invrq(struct smb_vc *vcp)
rw_exit(&vcp->iod_rqlock);
}
-#ifdef SMBTP_UPCALL
-static void
-smb_iod_sockwakeup(struct smb_vc *vcp)
-{
- /* note: called from socket upcall... */
-}
-#endif
-
/*
- * Called after we fail to send or recv.
- * Called with no locks held.
+ * Called by smb_vc_rele, smb_vc_kill, and by the driver
+ * close entry point if the IOD closes its dev handle.
+ *
+ * Forcibly kill the connection and IOD.
*/
-static void
-smb_iod_dead(struct smb_vc *vcp)
+int
+smb_iod_disconnect(struct smb_vc *vcp)
{
+ /*
+ * Inform everyone of the state change.
+ */
SMB_VC_LOCK(vcp);
- vcp->vc_state = SMBIOD_ST_DEAD;
- cv_broadcast(&vcp->vc_statechg);
-
-#ifdef NEED_SMBFS_CALLBACKS
- if (fscb != NULL) {
- struct smb_connobj *co;
- /*
- * Walk the share list, notify...
- * Was: smbfs_dead(...share->ss_mount);
- * XXX: Ok to hold vc_lock here?
- * XXX: More to do here?
- */
- SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
- /* smbfs_dead() */
- fscb->fscb_dead(CPTOSS(co));
- }
+ if (vcp->vc_state != SMBIOD_ST_DEAD) {
+ smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
+ cv_broadcast(&vcp->vc_statechg);
}
-#endif /* NEED_SMBFS_CALLBACKS */
-
SMB_VC_UNLOCK(vcp);
- smb_iod_invrq(vcp);
-}
-
-int
-smb_iod_connect(struct smb_vc *vcp)
-{
- struct proc *p = curproc;
- int error;
-
- if (vcp->vc_state != SMBIOD_ST_RECONNECT)
- return (EINVAL);
-
- if (vcp->vc_laddr) {
- error = SMB_TRAN_BIND(vcp, vcp->vc_laddr, p);
- if (error)
- goto errout;
- }
-
-#ifdef SMBTP_SELECTID
- SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, vcp);
-#endif
-#ifdef SMBTP_UPCALL
- SMB_TRAN_SETPARAM(vcp, SMBTP_UPCALL, (void *)smb_iod_sockwakeup);
-#endif
-
- error = SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, p);
- if (error) {
- SMBIODEBUG("connection to %s error %d\n",
- vcp->vc_srvname, error);
- goto errout;
- }
-
- /* Success! */
- return (0);
-
-errout:
-
- return (error);
-}
-
-/*
- * Called by smb_vc_rele, smb_vc_kill
- * Make the connection go away, and
- * the IOD (reader) thread too!
- */
-int
-smb_iod_disconnect(struct smb_vc *vcp)
-{
-
/*
* Let's be safe here and avoid doing any
* call across the network while trying to
* shut things down. If we just disconnect,
* the server will take care of the logoff.
*/
-#if 0
- if (vcp->vc_state == SMBIOD_ST_VCACTIVE) {
- smb_smb_ssnclose(vcp, &vcp->vc_scred);
- vcp->vc_state = SMBIOD_ST_TRANACTIVE;
- }
- vcp->vc_smbuid = SMB_UID_UNKNOWN;
-#endif
-
- /*
- * Used to call smb_iod_closetran here,
- * which did both disconnect and close.
- * We now do the close in smb_vc_free,
- * so we always have a valid vc_tdata.
- * Now just send the disconnect here.
- * Extra disconnect calls are ignored.
- */
- SMB_TRAN_DISCONNECT(vcp, curproc);
+ SMB_TRAN_DISCONNECT(vcp);
/*
- * If we have an IOD, let it handle the
- * state change when it receives the ACK
- * from the disconnect we just sent.
- * Otherwise set the state here, i.e.
- * after failing session setup.
+ * If we have an IOD, it should immediately notice
+ * that its connection has closed. But in case
+ * it doesn't, let's also send it a signal.
+ * (but don't shoot our own foot!)
+ * Note: the iod calls smb_iod_invrq on its way out.
*/
- SMB_VC_LOCK(vcp);
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- vcp->vc_state = SMBIOD_ST_DEAD;
- cv_broadcast(&vcp->vc_statechg);
+ if (vcp->iod_thr != NULL &&
+ vcp->iod_thr != curthread) {
+ tsignal(vcp->iod_thr, SIGKILL);
}
- SMB_VC_UNLOCK(vcp);
return (0);
}
@@ -290,9 +207,7 @@ smb_iod_disconnect(struct smb_vc *vcp)
static int
smb_iod_sendrq(struct smb_rq *rqp)
{
- struct proc *p = curproc;
struct smb_vc *vcp = rqp->sr_vc;
- struct smb_share *ssp = rqp->sr_share;
mblk_t *m;
int error;
@@ -301,66 +216,36 @@ smb_iod_sendrq(struct smb_rq *rqp)
ASSERT(RW_READ_HELD(&vcp->iod_rqlock));
/*
- * Note: requests with sr_flags & SMBR_INTERNAL
- * need to pass here with these states:
- * SMBIOD_ST_TRANACTIVE: smb_negotiate
- * SMBIOD_ST_NEGOACTIVE: smb_ssnsetup
+ * Note: Anything special for SMBR_INTERNAL here?
*/
- SMBIODEBUG("vc_state = %d\n", vcp->vc_state);
- switch (vcp->vc_state) {
- case SMBIOD_ST_NOTCONN:
- smb_iod_rqprocessed(rqp, ENOTCONN, 0);
- return (0);
- case SMBIOD_ST_DEAD:
- /* This is what keeps the iod itself from sending more */
- smb_iod_rqprocessed(rqp, ENOTCONN, 0);
- return (0);
- case SMBIOD_ST_RECONNECT:
- return (0);
- default:
- break;
+ if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+ return (ENOTCONN);
}
+
+ /*
+ * On the first send, set the MID and (maybe)
+ * the signing sequence numbers. The increments
+ * here are serialized by vc_sendlock
+ */
if (rqp->sr_sendcnt == 0) {
- *rqp->sr_rquid = htoles(vcp->vc_smbuid);
- /*
- * XXX: Odd place for all this...
- * Would expect these values in vc_smbuid
- * and/or the request before we get here.
- * I think most of this mess is due to having
- * the initial UID set to SMB_UID_UKNOWN when
- * it should have been initialized to zero!
- * REVIST this later. XXX -gwr
- *
- * This is checking for the case where
- * "vc_smbuid" was set to 0 in "smb_smb_ssnsetup()";
- * that happens for requests that occur
- * after that's done but before we get back the final
- * session setup reply, where the latter is what
- * gives us the UID. (There can be an arbitrary # of
- * session setup packet exchanges to complete
- * "extended security" authentication.)
- *
- * However, if the server gave us a UID of 0 in a
- * Session Setup andX reply, and we then do a
- * Tree Connect andX and get back a TID, we should
- * use that TID, not 0, in subsequent references to
- * that tree (e.g., in NetShareEnum RAP requests).
- *
- * So, for now, we forcibly zero out the TID only if we're
- * doing extended security, as that's the only time
- * that "vc_smbuid" should be explicitly zeroed.
- *
- * note we must and do use SMB_TID_UNKNOWN for SMB_COM_ECHO
- */
- if (!vcp->vc_smbuid &&
- (vcp->vc_hflags2 & SMB_FLAGS2_EXT_SEC))
- *rqp->sr_rqtid = htoles(0);
- else
- *rqp->sr_rqtid =
- htoles(ssp ? ssp->ss_tid : SMB_TID_UNKNOWN);
- mb_fixhdr(&rqp->sr_rq);
+ rqp->sr_mid = vcp->vc_next_mid++;
+
+ if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
+ /*
+ * We're signing requests and verifying
+ * signatures on responses. Set the
+ * sequence numbers of the request and
+ * response here, used in smb_rq_verify.
+ */
+ rqp->sr_seqno = vcp->vc_next_seq++;
+ rqp->sr_rseqno = vcp->vc_next_seq++;
+ }
+
+ /* Fill in UID, TID, MID, etc. */
+ smb_rq_fillhdr(rqp);
/*
* Sign the message now that we're finally done
@@ -394,8 +279,13 @@ smb_iod_sendrq(struct smb_rq *rqp)
#endif
m_dumpm(m);
- error = rqp->sr_lerror = m ? SMB_TRAN_SEND(vcp, m, p) : ENOBUFS;
- m = 0; /* consumed by SEND */
+ if (m != NULL) {
+ error = SMB_TRAN_SEND(vcp, m);
+ m = 0; /* consumed by SEND */
+ } else
+ error = ENOBUFS;
+
+ rqp->sr_lerror = error;
if (error == 0) {
SMBRQ_LOCK(rqp);
rqp->sr_flags |= SMBR_SENT;
@@ -430,14 +320,13 @@ smb_iod_sendrq(struct smb_rq *rqp)
static int
smb_iod_recv1(struct smb_vc *vcp, mblk_t **mpp)
{
- struct proc *p = curproc;
mblk_t *m;
uchar_t *hp;
int error;
top:
m = NULL;
- error = SMB_TRAN_RECV(vcp, &m, p);
+ error = SMB_TRAN_RECV(vcp, &m);
if (error == EAGAIN)
goto top;
if (error)
@@ -469,38 +358,50 @@ top:
* while in state SMBIOD_ST_VCACTIVE. The loop now
* simply blocks in the socket recv until either a
* message arrives, or a disconnect.
+ *
+ * Any non-zero error means the IOD should terminate.
*/
-static void
+int
smb_iod_recvall(struct smb_vc *vcp)
{
struct smb_rq *rqp;
mblk_t *m;
uchar_t *hp;
ushort_t mid;
- int error;
+ int error = 0;
int etime_count = 0; /* for "server not responding", etc. */
for (;;) {
+ /*
+ * Check whether someone "killed" this VC,
+ * or is asking the IOD to terminate.
+ */
if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
- error = EIO;
+ error = 0;
break;
}
if (vcp->iod_flags & SMBIOD_SHUTDOWN) {
SMBIODEBUG("SHUTDOWN set\n");
- error = EIO;
+ /* This IOD thread will terminate. */
+ SMB_VC_LOCK(vcp);
+ smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
+ cv_broadcast(&vcp->vc_statechg);
+ SMB_VC_UNLOCK(vcp);
+ error = EINTR;
break;
}
m = NULL;
error = smb_iod_recv1(vcp, &m);
- if ((error == ETIME) && vcp->iod_rqwaiting) {
+ if (error == ETIME &&
+ vcp->iod_rqlist.tqh_first != NULL) {
/*
- * Nothing received for 15 seconds,
- * and we have requests waiting.
+ * Nothing received for 15 seconds and
+ * we have requests in the queue.
*/
etime_count++;
@@ -509,7 +410,10 @@ smb_iod_recvall(struct smb_vc *vcp)
* and print the warning message.
*/
if (etime_count == 1) {
- smb_iod_notify_down(vcp);
+ /* Was: smb_iod_notify_down(vcp); */
+ if (fscb && fscb->fscb_down)
+ smb_vc_walkshares(vcp,
+ fscb->fscb_down);
zprintf(vcp->vc_zoneid,
"SMB server %s not responding\n",
vcp->vc_srvname);
@@ -517,38 +421,27 @@ smb_iod_recvall(struct smb_vc *vcp)
/*
* At 30 sec. try sending an echo, and then
- * once a minute thereafter. It's tricky to
- * do a send from the IOD thread because
- * we don't want to block here.
- *
- * Using tmo=SMBNOREPLYWAIT in the request
- * so smb_rq_reply will skip smb_iod_waitrq.
- * The smb_smb_echo call uses SMBR_INTERNAL
- * to avoid calling smb_iod_sendall().
+ * once a minute thereafter.
*/
if ((etime_count & 3) == 2) {
- smb_smb_echo(vcp, &vcp->vc_scred,
- SMBNOREPLYWAIT);
+ (void) smb_iod_send_echo(vcp);
}
continue;
- } /* ETIME && iod_rqwaiting */
+ } /* ETIME && requests in queue */
if (error == ETIME) {
/*
* If the IOD thread holds the last reference
- * to this VC, disconnect, release, terminate.
- * Usually can avoid the lock/unlock here.
- * Note, in-line: _vc_kill ... _vc_gone
+ * to this VC, let the IOD thread terminate.
*/
if (vcp->vc_co.co_usecount > 1)
continue;
SMB_VC_LOCK(vcp);
- if (vcp->vc_co.co_usecount == 1 &&
- (vcp->vc_flags & SMBV_GONE) == 0) {
- vcp->vc_flags |= SMBV_GONE;
+ if (vcp->vc_co.co_usecount == 1) {
+ smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
SMB_VC_UNLOCK(vcp);
- smb_iod_disconnect(vcp);
+ error = 0;
break;
}
SMB_VC_UNLOCK(vcp);
@@ -557,9 +450,22 @@ smb_iod_recvall(struct smb_vc *vcp)
if (error) {
/*
+ * The recv. above returned some error
+ * we can't continue from i.e. ENOTCONN.
* It's dangerous to continue here.
* (possible infinite loop!)
+ *
+ * If we have requests enqueued, next
+ * state is reconnecting, else idle.
*/
+ int state;
+ SMB_VC_LOCK(vcp);
+ state = (vcp->iod_rqlist.tqh_first != NULL) ?
+ SMBIOD_ST_RECONNECT : SMBIOD_ST_IDLE;
+ smb_iod_newstate(vcp, state);
+ cv_broadcast(&vcp->vc_statechg);
+ SMB_VC_UNLOCK(vcp);
+ error = 0;
break;
}
@@ -572,7 +478,9 @@ smb_iod_recvall(struct smb_vc *vcp)
zprintf(vcp->vc_zoneid, "SMB server %s OK\n",
vcp->vc_srvname);
- smb_iod_notify_up(vcp);
+ /* Was: smb_iod_notify_up(vcp); */
+ if (fscb && fscb->fscb_up)
+ smb_vc_walkshares(vcp, fscb->fscb_up);
}
/*
@@ -582,7 +490,7 @@ smb_iod_recvall(struct smb_vc *vcp)
*/
hp = mtod(m, uchar_t *);
/*LINTED*/
- mid = SMB_HDRMID(hp);
+ mid = letohs(SMB_HDRMID(hp));
SMBIODEBUG("mid %04x\n", (uint_t)mid);
rw_enter(&vcp->iod_rqlock, RW_READER);
@@ -625,70 +533,31 @@ smb_iod_recvall(struct smb_vc *vcp)
rw_exit(&vcp->iod_rqlock);
}
-#ifdef APPLE
- /*
- * check for interrupts
- * On Solaris, handle in smb_iod_waitrq
- */
- rw_enter(&vcp->iod_rqlock, RW_READER);
- TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
- if (smb_sigintr(rqp->sr_cred->scr_vfsctx))
- smb_iod_rqprocessed(rqp, EINTR, 0);
- }
- rw_exit(&vcp->iod_rqlock);
-#endif
+
+ return (error);
}
/*
- * Looks like we don't need these callbacks,
- * but keep the code for now (for Apple).
+ * The IOD receiver thread has requests pending and
+ * has not received anything in a while. Try to
+ * send an SMB echo request. It's tricky to do a
+ * send from the IOD thread because we can't block.
+ *
+ * Using tmo=SMBNOREPLYWAIT in the request
+ * so smb_rq_reply will skip smb_iod_waitrq.
+ * The smb_smb_echo call uses SMBR_INTERNAL
+ * to avoid calling smb_iod_sendall().
*/
-/*ARGSUSED*/
-void
-smb_iod_notify_down(struct smb_vc *vcp)
-{
-#ifdef NEED_SMBFS_CALLBACKS
- struct smb_connobj *co;
-
- if (fscb == NULL)
- return;
-
- /*
- * Walk the share list, notify...
- * Was: smbfs_down(...share->ss_mount);
- * XXX: Ok to hold vc_lock here?
- */
- SMB_VC_LOCK(vcp);
- SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
- /* smbfs_down() */
- fscb->fscb_down(CPTOSS(co));
- }
- SMB_VC_UNLOCK(vcp);
-#endif /* NEED_SMBFS_CALLBACKS */
-}
-
-/*ARGSUSED*/
-void
-smb_iod_notify_up(struct smb_vc *vcp)
+int
+smb_iod_send_echo(smb_vc_t *vcp)
{
-#ifdef NEED_SMBFS_CALLBACKS
- struct smb_connobj *co;
-
- if (fscb == NULL)
- return;
+ smb_cred_t scred;
+ int err;
- /*
- * Walk the share list, notify...
- * Was: smbfs_up(...share->ss_mount);
- * XXX: Ok to hold vc_lock here?
- */
- SMB_VC_LOCK(vcp);
- SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
- /* smbfs_up() */
- fscb->fscb_up(CPTOSS(co));
- }
- SMB_VC_UNLOCK(vcp);
-#endif /* NEED_SMBFS_CALLBACKS */
+ smb_credinit(&scred, NULL);
+ err = smb_smb_echo(vcp, &scred, SMBNOREPLYWAIT);
+ smb_credrele(&scred);
+ return (err);
}
/*
@@ -706,33 +575,35 @@ smb_iod_addrq(struct smb_rq *rqp)
struct smb_vc *vcp = rqp->sr_vc;
int error, save_newrq;
- SMBIODEBUG("entry, mid=%d\n", rqp->sr_mid);
-
ASSERT(rqp->sr_cred);
- /* This helps a little with debugging. */
+ /*
+ * State should be correct after the check in
+ * smb_rq_enqueue(), but we dropped locks...
+ */
+ if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+ return (ENOTCONN);
+ }
+
+ /*
+ * Requests from the IOD itself are marked _INTERNAL,
+ * and get some special treatment to avoid blocking
+ * the reader thread (so we don't deadlock).
+ * The request is not yet on the queue, so we can
+ * modify it's state here without locks.
+ * Only thing using this now is ECHO.
+ */
rqp->sr_owner = curthread;
+ if (rqp->sr_owner == vcp->iod_thr) {
+ rqp->sr_flags |= SMBR_INTERNAL;
- if (rqp->sr_flags & SMBR_INTERNAL) {
/*
- * This is some kind of internal request,
- * i.e. negotiate, session setup, echo...
- * Allow vc_state < SMBIOD_ST_VCACTIVE, and
- * always send directly from this thread.
- * May be called by the IOD thread (echo).
+ * This is a request from the IOD thread.
+ * Always send directly from this thread.
* Note lock order: iod_rqlist, vc_sendlock
*/
rw_enter(&vcp->iod_rqlock, RW_WRITER);
- if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- /*
- * We're signing requests and verifying
- * signatures on responses. Set the
- * sequence numbers of the request and
- * response here, used in smb_rq_verify.
- */
- rqp->sr_seqno = vcp->vc_seqno++;
- rqp->sr_rseqno = vcp->vc_seqno++;
- }
TAILQ_INSERT_HEAD(&vcp->iod_rqlist, rqp, sr_link);
rw_downgrade(&vcp->iod_rqlock);
@@ -741,52 +612,31 @@ smb_iod_addrq(struct smb_rq *rqp)
* so take that here, but carefully:
* Never block the IOD thread here.
*/
- if (curthread == vcp->iod_thr) {
- if (sema_tryp(&vcp->vc_sendlock) == 0) {
- SMBIODEBUG("sendlock busy\n");
- error = EAGAIN;
- } else {
- /* Have vc_sendlock */
- error = smb_iod_sendrq(rqp);
- sema_v(&vcp->vc_sendlock);
- }
+ if (sema_tryp(&vcp->vc_sendlock) == 0) {
+ SMBIODEBUG("sendlock busy\n");
+ error = EAGAIN;
} else {
- sema_p(&vcp->vc_sendlock);
+ /* Have vc_sendlock */
error = smb_iod_sendrq(rqp);
sema_v(&vcp->vc_sendlock);
}
rw_exit(&vcp->iod_rqlock);
+
+ /*
+ * In the non-error case, _removerq
+ * is done by either smb_rq_reply
+ * or smb_iod_waitrq.
+ */
if (error)
smb_iod_removerq(rqp);
return (error);
}
- /*
- * Normal request from the driver or smbfs.
- * State should be correct after the check in
- * smb_rq_enqueue(), but we dropped locks...
- */
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
- return (ENOTCONN);
- }
-
rw_enter(&vcp->iod_rqlock, RW_WRITER);
- if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- /*
- * We're signing requests and verifying
- * signatures on responses. Set the
- * sequence numbers of the request and
- * response here, used in smb_rq_verify.
- */
- rqp->sr_seqno = vcp->vc_seqno++;
- rqp->sr_rseqno = vcp->vc_seqno++;
- }
TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link);
-
/* iod_rqlock/WRITER protects iod_newrq */
save_newrq = vcp->iod_newrq;
vcp->iod_newrq++;
@@ -855,8 +705,6 @@ smb_iod_removerq(struct smb_rq *rqp)
{
struct smb_vc *vcp = rqp->sr_vc;
- SMBIODEBUG("entry, mid=%d\n", rqp->sr_mid);
-
rw_enter(&vcp->iod_rqlock, RW_WRITER);
#ifdef QUEUEDEBUG
/*
@@ -873,111 +721,10 @@ smb_iod_removerq(struct smb_rq *rqp)
}
-/*
- * Internal version of smb_iod_waitrq.
- *
- * This is used when there is no reader thread,
- * so we have to do the recv here. The request
- * must have the SMBR_INTERNAL flag set.
- */
-static int
-smb_iod_waitrq_internal(struct smb_rq *rqp)
-{
- struct smb_vc *vcp = rqp->sr_vc;
- mblk_t *m;
- uchar_t *hp;
- int error;
- uint16_t mid;
- uint8_t cmd;
-
- /* Make sure it's an internal request. */
- if ((rqp->sr_flags & SMBR_INTERNAL) == 0) {
- SMBIODEBUG("not internal\n");
- return (EINVAL);
- }
-
- /* Only simple requests allowed. */
- if (rqp->sr_flags & SMBR_MULTIPACKET) {
- SMBIODEBUG("multipacket\n");
- return (EINVAL);
- }
-
- /* Should not already have a response. */
- if (rqp->sr_rp.md_top) {
- DEBUG_ENTER("smb_iod_waitrq again?\n");
- return (0);
- }
-
- /*
- * The message recv loop. Terminates when we
- * receive the message we're looking for.
- * Drop others, with complaints.
- * Scaled-down version of smb_iod_recvall
- */
- for (;;) {
- m = NULL;
- error = smb_iod_recv1(vcp, &m);
- if (error) {
- /*
- * It's dangerous to continue here.
- * (possible infinite loop!)
- */
-#if 0
- if (SMB_TRAN_FATAL(vcp, error)) {
- return (error);
- }
- continue;
-#endif
- return (error);
- }
-
- hp = mtod(m, uchar_t *);
- cmd = SMB_HDRCMD(hp);
- /*LINTED*/
- mid = SMB_HDRMID(hp);
-
- SMBIODEBUG("cmd 0x%02x mid %04x\n",
- (uint_t)cmd, (uint_t)mid);
- m_dumpm(m);
-
- /*
- * Normally, the MID will match.
- * For internal requests, also
- * match on the cmd to be safe.
- */
- if (mid == rqp->sr_mid)
- break;
- if (cmd == rqp->sr_cmd) {
- SMBIODEBUG("cmd match but not mid!\n");
- break;
- }
-
- SMBIODEBUG("drop nomatch\n");
- m_freem(m);
- }
-
- /*
- * Have the response we were waiting for.
- * Simplified version of the code from
- * smb_iod_recvall
- */
- SMBRQ_LOCK(rqp);
- if (rqp->sr_rp.md_top == NULL) {
- md_initm(&rqp->sr_rp, m);
- } else {
- SMBIODEBUG("drop duplicate\n");
- m_freem(m);
- }
- SMBRQ_UNLOCK(rqp);
-
- return (0);
-}
-
/*
* Wait for a request to complete.
*
- * For internal requests, see smb_iod_waitrq_internal.
* For normal requests, we need to deal with
* ioc_muxcnt dropping below vc_maxmux by
* making arrangements to send more...
@@ -989,23 +736,18 @@ smb_iod_waitrq(struct smb_rq *rqp)
clock_t tr, tmo1, tmo2;
int error, rc;
- SMBIODEBUG("entry, cmd=0x%02x mid=0x%04x\n",
- (uint_t)rqp->sr_cmd, (uint_t)rqp->sr_mid);
-
if (rqp->sr_flags & SMBR_INTERNAL) {
ASSERT((rqp->sr_flags & SMBR_MULTIPACKET) == 0);
- error = smb_iod_waitrq_internal(rqp);
smb_iod_removerq(rqp);
- return (error);
+ return (EAGAIN);
}
/*
* Make sure this is NOT the IOD thread,
- * or the wait below will always timeout.
+ * or the wait below will stop the reader.
*/
ASSERT(curthread != vcp->iod_thr);
- atomic_inc_uint(&vcp->iod_rqwaiting);
SMBRQ_LOCK(rqp);
/*
@@ -1031,7 +773,7 @@ smb_iod_waitrq(struct smb_rq *rqp)
rc = cv_wait_sig(&rqp->sr_cond, &rqp->sr_lock);
rqp->sr_flags &= ~SMBR_SENDWAIT;
if (rc == 0) {
- SMBIODEBUG("EINTR in sendwait, mid=%u\n", rqp->sr_mid);
+ SMBIODEBUG("EINTR in sendwait, rqp=%p\n", rqp);
error = EINTR;
goto out;
}
@@ -1120,7 +862,6 @@ smb_iod_waitrq(struct smb_rq *rqp)
out:
SMBRQ_UNLOCK(rqp);
- atomic_dec_uint(&vcp->iod_rqwaiting);
/*
* MULTIPACKET request must stay in the list.
@@ -1168,8 +909,8 @@ smb_iod_shutdown_share(struct smb_share *ssp)
* Send all requests that need sending.
* Called from _addrq, _multirq, _waitrq
*/
-static void
-smb_iod_sendall(struct smb_vc *vcp)
+void
+smb_iod_sendall(smb_vc_t *vcp)
{
struct smb_rq *rqp;
int error, save_newrq, muxcnt;
@@ -1208,7 +949,7 @@ smb_iod_sendall(struct smb_vc *vcp)
error = muxcnt = 0;
TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
- if (vcp->vc_state == SMBIOD_ST_DEAD) {
+ if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
error = ENOTCONN; /* stop everything! */
break;
}
@@ -1236,167 +977,204 @@ smb_iod_sendall(struct smb_vc *vcp)
sema_v(&vcp->vc_sendlock);
rw_exit(&vcp->iod_rqlock);
-
- if (error == ENOTCONN)
- smb_iod_dead(vcp);
-
}
-
-/*
- * "main" function for smbiod daemon thread
- */
-void
-smb_iod_main(struct smb_vc *vcp)
+int
+smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
{
- kthread_t *thr = curthread;
+ struct file *fp = NULL;
+ int err = 0;
- SMBIODEBUG("entry\n");
+ /*
+ * This is called by the one-and-only
+ * IOD thread for this VC.
+ */
+ ASSERT(vcp->iod_thr == curthread);
- SMBIODEBUG("Running, thr=0x%p\n", thr);
+ /*
+ * Get the network transport file pointer,
+ * and "loan" it to our transport module.
+ */
+ if ((fp = getf(vcp->vc_tran_fd)) == NULL) {
+ err = EBADF;
+ goto out;
+ }
+ if ((err = SMB_TRAN_LOAN_FP(vcp, fp, cr)) != 0)
+ goto out;
/*
- * Prevent race with thread that created us.
- * After we get this lock iod_thr is set.
+ * In case of reconnect, tell any enqueued requests
+ * then can GO!
*/
SMB_VC_LOCK(vcp);
- ASSERT(thr == vcp->iod_thr);
-
- /* Redundant with iod_thr, but may help debugging. */
- vcp->iod_flags |= SMBIOD_RUNNING;
+ vcp->vc_genid++; /* possibly new connection */
+ smb_iod_newstate(vcp, SMBIOD_ST_VCACTIVE);
+ cv_broadcast(&vcp->vc_statechg);
SMB_VC_UNLOCK(vcp);
/*
- * OK, this is a new reader thread.
- * In case of reconnect, tell any
- * old requests they can restart.
+ * The above cv_broadcast should be sufficient to
+ * get requests going again.
+ *
+ * If we have a callback function, run it.
+ * Was: smb_iod_notify_connected()
*/
- smb_iod_invrq(vcp);
+ if (fscb && fscb->fscb_connect)
+ smb_vc_walkshares(vcp, fscb->fscb_connect);
/*
* Run the "reader" loop.
*/
- smb_iod_recvall(vcp);
+ err = smb_iod_recvall(vcp);
/*
- * The reader loop function returns only when
- * there's been a fatal error on the connection.
+ * The reader loop returned, so we must have a
+ * new state. (disconnected or reconnecting)
+ *
+ * Notify shares of the disconnect.
+ * Was: smb_iod_notify_disconnect()
*/
- smb_iod_dead(vcp);
+ smb_vc_walkshares(vcp, smb_iod_share_disconnected);
/*
- * The reader thread is going away. Clear iod_thr,
- * and wake up anybody waiting for us to quit.
+ * The reader loop function returns only when
+ * there's been an error on the connection, or
+ * this VC has no more references. It also
+ * updates the state before it returns.
+ *
+ * Tell any requests to give up or restart.
*/
- SMB_VC_LOCK(vcp);
- vcp->iod_flags &= ~SMBIOD_RUNNING;
- vcp->iod_thr = NULL;
- cv_broadcast(&vcp->iod_exit);
- SMB_VC_UNLOCK(vcp);
+ smb_iod_invrq(vcp);
+
+out:
+ /* Recall the file descriptor loan. */
+ (void) SMB_TRAN_LOAN_FP(vcp, NULL, cr);
+ if (fp != NULL) {
+ releasef(vcp->vc_tran_fd);
+ }
+
+ return (err);
+}
+
+/*
+ * Wait around for someone to ask to use this VC.
+ * If the VC has only the IOD reference, then
+ * wait only a minute or so, then drop it.
+ */
+int
+smb_iod_vc_idle(struct smb_vc *vcp)
+{
+ clock_t tr, tmo;
+ int err = 0;
/*
- * This hold was taken in smb_iod_create()
- * when this thread was created.
+ * This is called by the one-and-only
+ * IOD thread for this VC.
*/
- smb_vc_rele(vcp);
+ ASSERT(vcp->iod_thr == curthread);
+
+ SMB_VC_LOCK(vcp);
+ while (vcp->vc_state == SMBIOD_ST_IDLE) {
+ tmo = lbolt + SEC_TO_TICK(15);
+ tr = cv_timedwait_sig(&vcp->iod_idle, &vcp->vc_lock, tmo);
+ if (tr == 0) {
+ err = EINTR;
+ break;
+ }
+ if (tr < 0) {
+ /* timeout */
+ if (vcp->vc_co.co_usecount == 1) {
+ /* Let this IOD terminate. */
+ smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
+ /* nobody to cv_broadcast */
+ break;
+ }
+ }
+ }
+ SMB_VC_UNLOCK(vcp);
- SMBIODEBUG("Exiting, p=0x%p\n", curproc);
- zthread_exit();
+ return (err);
}
/*
- * Create the reader thread.
- *
- * This happens when we are just about to
- * enter vc_state = SMBIOD_ST_VCACTIVE;
- * See smb_sm_ssnsetup()
+ * After a failed reconnect attempt, smbiod will
+ * call this to make current requests error out.
*/
int
-smb_iod_create(struct smb_vc *vcp)
+smb_iod_vc_rcfail(struct smb_vc *vcp)
{
- kthread_t *thr = NULL;
- int error;
+ clock_t tr, tmo;
+ int err = 0;
/*
- * Take a hold on the VC for the IOD thread.
- * This hold will be released when the IOD
- * thread terminates. (or on error below)
+ * This is called by the one-and-only
+ * IOD thread for this VC.
*/
- smb_vc_hold(vcp);
+ ASSERT(vcp->iod_thr == curthread);
+
+ if (vcp->vc_state != SMBIOD_ST_RECONNECT)
+ return (EINVAL);
SMB_VC_LOCK(vcp);
- if (vcp->iod_thr != NULL) {
- SMBIODEBUG("aready have an IOD?");
- error = EIO;
- goto out;
- }
+ smb_iod_newstate(vcp, SMBIOD_ST_RCFAILED);
+ cv_broadcast(&vcp->vc_statechg);
/*
- * Darwin code used: IOCreateThread(...)
- * In Solaris, we use...
+ * Short wait here for two reasons:
+ * (1) Give requests a chance to error out.
+ * (2) Prevent immediate retry.
*/
- thr = zthread_create(
- NULL, /* stack */
- 0, /* stack size (default) */
- smb_iod_main, /* entry func... */
- vcp, /* ... and arg */
- 0, /* len (of what?) */
- minclsyspri); /* priority */
- if (thr == NULL) {
- SMBERROR("can't start smbiod\n");
- error = ENOMEM;
- goto out;
- }
+ tmo = lbolt + SEC_TO_TICK(5);
+ tr = cv_timedwait_sig(&vcp->iod_idle, &vcp->vc_lock, tmo);
+ if (tr == 0)
+ err = EINTR;
- /* Success! */
- error = 0;
- vcp->iod_thr = thr;
+ smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
+ cv_broadcast(&vcp->vc_statechg);
-out:
SMB_VC_UNLOCK(vcp);
- if (error)
- smb_vc_rele(vcp);
-
- return (error);
+ return (err);
}
/*
- * Called from smb_vc_free to do any
- * cleanup of our IOD (reader) thread.
+ * Ask the IOD to reconnect (if not already underway)
+ * then wait for the reconnect to finish.
*/
int
-smb_iod_destroy(struct smb_vc *vcp)
+smb_iod_reconnect(struct smb_vc *vcp)
{
- clock_t tmo;
+ int err = 0, rv;
- /*
- * Let's try to make sure the IOD thread
- * goes away, by waiting for it to exit.
- * Normally, it's gone by now.
- *
- * Only wait for a second, because we're in the
- * teardown path and don't want to get stuck here.
- * Should not take long, or things are hosed...
- */
SMB_VC_LOCK(vcp);
- if (vcp->iod_thr) {
- vcp->iod_flags |= SMBIOD_SHUTDOWN;
- tmo = lbolt + hz;
- tmo = cv_timedwait(&vcp->iod_exit, &vcp->vc_lock, tmo);
- if (tmo == -1) {
- SMBERROR("IOD thread for %s did not exit?\n",
- vcp->vc_srvname);
+again:
+ switch (vcp->vc_state) {
+
+ case SMBIOD_ST_IDLE:
+ smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT);
+ cv_signal(&vcp->iod_idle);
+ /* FALLTHROUGH */
+
+ case SMBIOD_ST_RECONNECT:
+ rv = cv_wait_sig(&vcp->vc_statechg, &vcp->vc_lock);
+ if (rv == 0) {
+ err = EINTR;
+ break;
}
+ goto again;
+
+ case SMBIOD_ST_VCACTIVE:
+ err = 0; /* success! */
+ break;
+
+ case SMBIOD_ST_RCFAILED:
+ case SMBIOD_ST_DEAD:
+ default:
+ err = ENOTCONN;
+ break;
}
- if (vcp->iod_thr) {
- /* This should not happen. */
- SMBIODEBUG("IOD thread did not exit!\n");
- /* Try harder? */
- tsignal(vcp->iod_thr, SIGKILL);
- }
- SMB_VC_UNLOCK(vcp);
- return (0);
+ SMB_VC_UNLOCK(vcp);
+ return (err);
}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.c
index c78c0e61b1..4079482538 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Password Keychain storage mechanism.
*/
@@ -57,6 +55,7 @@
#include <sys/mkdev.h>
#include <sys/avl.h>
#include <sys/avl_impl.h>
+#include <sys/u8_textprep.h>
#include <netsmb/smb_osdep.h>
@@ -97,6 +96,9 @@ avl_tree_t smb_ptd; /* AVL password tree descriptor */
unsigned int smb_list_len = 0; /* No. of elements in the tree. */
kmutex_t smb_ptd_lock; /* Mutex lock for controlled access */
+int smb_pkey_check(smbioc_pk_t *pk, cred_t *cr);
+int smb_pkey_deluid(uid_t ioc_uid, cred_t *cr);
+
/*
* This routine is called by AVL tree calls when they want to find a
* node, find the next position in the tree to add or for deletion.
@@ -108,7 +110,7 @@ smb_pkey_cmp(const void *a, const void *b)
{
const smb_passid_t *pa = (smb_passid_t *)a;
const smb_passid_t *pb = (smb_passid_t *)b;
- int duser, dsrv;
+ int duser, dsrv, error;
ASSERT(MUTEX_HELD(&smb_ptd_lock));
@@ -128,12 +130,14 @@ smb_pkey_cmp(const void *a, const void *b)
return (-1);
if (pa->zoneid > pb->zoneid)
return (+1);
- dsrv = strcasecmp(pa->srvdom, pb->srvdom);
+ dsrv = u8_strcmp(pa->srvdom, pb->srvdom, 0,
+ U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error);
if (dsrv < 0)
return (-1);
if (dsrv > 0)
return (+1);
- duser = strcasecmp(pa->username, pb->username);
+ duser = u8_strcmp(pa->username, pb->username, 0,
+ U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error);
if (duser < 0)
return (-1);
if (duser > 0)
@@ -157,11 +161,12 @@ smb_pkey_init()
/*
* Destroy the full AVL tree.
+ * Called just before unload.
*/
void
smb_pkey_fini()
{
- smb_pkey_deluid((uid_t)-1, CRED());
+ smb_pkey_deluid((uid_t)-1, kcred);
avl_destroy(&smb_ptd);
mutex_destroy(&smb_ptd_lock);
}
@@ -187,8 +192,8 @@ smb_node_delete(smb_passid_t *tmp)
{
ASSERT(MUTEX_HELD(&smb_ptd_lock));
avl_remove(&smb_ptd, tmp);
- smb_strfree(tmp->srvdom);
- smb_strfree(tmp->username);
+ strfree(tmp->srvdom);
+ strfree(tmp->username);
kmem_free(tmp, sizeof (*tmp));
return (0);
}
@@ -287,10 +292,10 @@ smb_pkey_add(smbioc_pk_t *pk, cred_t *cr)
cpid = kmem_zalloc(sizeof (smb_passid_t), KM_SLEEP);
cpid->uid = uid;
cpid->zoneid = getzoneid();
- cpid->srvdom = smb_strdup(pk->pk_dom);
- cpid->username = smb_strdup(pk->pk_usr);
- smb_oldlm_hash(pk->pk_pass, cpid->lmhash);
- smb_ntlmv1hash(pk->pk_pass, cpid->nthash);
+ cpid->srvdom = strdup(pk->pk_dom);
+ cpid->username = strdup(pk->pk_usr);
+ bcopy(pk->pk_lmhash, cpid->lmhash, SMBIOC_HASH_SZ);
+ bcopy(pk->pk_nthash, cpid->nthash, SMBIOC_HASH_SZ);
/*
* XXX: Instead of calling smb_pkey_check here,
@@ -309,8 +314,8 @@ smb_pkey_add(smbioc_pk_t *pk, cred_t *cr)
if (tmp == NULL) {
avl_insert(t, cpid, where);
} else {
- smb_strfree(cpid->srvdom);
- smb_strfree(cpid->username);
+ strfree(cpid->srvdom);
+ strfree(cpid->username);
kmem_free(cpid, sizeof (smb_passid_t));
}
mutex_exit(&smb_ptd_lock);
@@ -320,7 +325,7 @@ smb_pkey_add(smbioc_pk_t *pk, cred_t *cr)
/*
* Determine if a node with uid,zoneid, uname & dname exists in the tree
- * given the information. Does NOT return the stored password.
+ * given the information, and if found, return the hashes.
*/
int
smb_pkey_check(smbioc_pk_t *pk, cred_t *cr)
@@ -346,46 +351,74 @@ smb_pkey_check(smbioc_pk_t *pk, cred_t *cr)
mutex_enter(&smb_ptd_lock);
tmp = (smb_passid_t *)avl_find(t, cpid, &where);
- if (tmp != NULL)
- error = 0;
mutex_exit(&smb_ptd_lock);
+ if (tmp != NULL) {
+ bcopy(tmp->lmhash, pk->pk_lmhash, SMBIOC_HASH_SZ);
+ bcopy(tmp->nthash, pk->pk_nthash, SMBIOC_HASH_SZ);
+ error = 0;
+ }
+
kmem_free(cpid, sizeof (smb_passid_t));
return (error);
}
-/*
- * Interface function between the keychain mechanism and SMB password
- * handling during Session Setup. Internal form of smb_pkey_check().
- * Copies the password hashes into the VC.
- */
+
int
-smb_pkey_getpwh(struct smb_vc *vcp, cred_t *cr)
+smb_pkey_ioctl(int cmd, intptr_t arg, int flags, cred_t *cr)
{
- avl_tree_t *t = &smb_ptd;
- avl_index_t where;
- smb_passid_t *tmp, *cpid;
- int error = ENOENT;
+ smbioc_pk_t *pk;
+ uid_t uid;
+ int err = 0;
+
+ pk = kmem_alloc(sizeof (*pk), KM_SLEEP);
+
+ switch (cmd) {
+ case SMBIOC_PK_ADD:
+ case SMBIOC_PK_DEL:
+ case SMBIOC_PK_CHK:
+ if (ddi_copyin((void *)arg, pk,
+ sizeof (*pk), flags)) {
+ err = EFAULT;
+ goto out;
+ }
+ /* Make strlen (etc) on these safe. */
+ pk->pk_dom[SMBIOC_MAX_NAME-1] = '\0';
+ pk->pk_usr[SMBIOC_MAX_NAME-1] = '\0';
+ break;
+ }
- cpid = kmem_alloc(sizeof (smb_passid_t), KM_SLEEP);
- cpid->uid = crgetruid(cr);
- cpid->zoneid = getzoneid();
- cpid->username = vcp->vc_username;
+ switch (cmd) {
+ case SMBIOC_PK_ADD:
+ err = smb_pkey_add(pk, cr);
+ break;
- if (vcp->vc_vopt & SMBVOPT_KC_DOMAIN)
- cpid->srvdom = vcp->vc_domain;
- else
- cpid->srvdom = vcp->vc_srvname;
+ case SMBIOC_PK_DEL:
+ err = smb_pkey_del(pk, cr);
+ break;
- mutex_enter(&smb_ptd_lock);
- tmp = (smb_passid_t *)avl_find(t, cpid, &where);
- if (tmp != NULL) {
- bcopy(tmp->lmhash, vcp->vc_lmhash, SMB_PWH_MAX);
- bcopy(tmp->nthash, vcp->vc_nthash, SMB_PWH_MAX);
- error = 0;
+ case SMBIOC_PK_CHK:
+ err = smb_pkey_check(pk, cr);
+ /* This is just a hash now. */
+ (void) ddi_copyout(pk, (void *)arg,
+ sizeof (*pk), flags);
+ break;
+
+ case SMBIOC_PK_DEL_OWNER:
+ uid = crgetruid(cr);
+ err = smb_pkey_deluid(uid, cr);
+ break;
+
+ case SMBIOC_PK_DEL_EVERYONE:
+ uid = (uid_t)-1;
+ err = smb_pkey_deluid(uid, cr);
+ break;
+
+ default:
+ err = ENODEV;
}
- mutex_exit(&smb_ptd_lock);
- kmem_free(cpid, sizeof (smb_passid_t));
- return (error);
+out:
+ kmem_free(pk, sizeof (*pk));
+ return (err);
}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
index d4147798ba..f4ebf9a573 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SMB_PASS_H
#define _SMB_PASS_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Password keychains interface
*/
@@ -46,21 +44,14 @@ typedef struct smb_passid {
zoneid_t zoneid; /* Future Use */
char *srvdom; /* Windows Domain (or server) */
char *username; /* Windows User name */
- uchar_t lmhash[SMB_PWH_MAX];
- uchar_t nthash[SMB_PWH_MAX];
+ uchar_t lmhash[SMBIOC_HASH_SZ];
+ uchar_t nthash[SMBIOC_HASH_SZ];
} smb_passid_t;
/* Called from smb_dev.c */
void smb_pkey_init(void);
void smb_pkey_fini(void);
int smb_pkey_idle(void);
-int smb_pkey_add(smbioc_pk_t *pk, cred_t *cr);
-int smb_pkey_del(smbioc_pk_t *pk, cred_t *cr);
-int smb_pkey_check(smbioc_pk_t *pk, cred_t *cr);
-int smb_pkey_deluid(uid_t uid, cred_t *cr);
-
-/* Called from smb_usr.c */
-struct smb_vc;
-int smb_pkey_getpwh(struct smb_vc *vcp, cred_t *cr);
+int smb_pkey_ioctl(int, intptr_t, int, cred_t *);
#endif /* _SMB_PASS_H */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
index e73b159e1b..5199127d47 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -44,6 +44,7 @@
#include <sys/lock.h>
#include <sys/socket.h>
#include <sys/mount.h>
+#include <sys/sunddi.h>
#include <sys/cmn_err.h>
#include <sys/sdt.h>
@@ -55,6 +56,18 @@
#include <netsmb/smb_tran.h>
#include <netsmb/smb_rq.h>
+/*
+ * How long to wait before restarting a request (after reconnect)
+ */
+#define SMB_RCNDELAY 2 /* seconds */
+
+/*
+ * leave this zero - we can't ssecond guess server side effects of
+ * duplicate ops, this isn't nfs!
+ */
+#define SMBMAXRESTARTS 0
+
+
static int smb_rq_reply(struct smb_rq *rqp);
static int smb_rq_enqueue(struct smb_rq *rqp);
static int smb_rq_getenv(struct smb_connobj *layer,
@@ -64,6 +77,27 @@ static int smb_t2_reply(struct smb_t2rq *t2p);
static int smb_nt_reply(struct smb_ntrq *ntp);
+/*
+ * Done with a request object. Free its contents.
+ * If it was allocated (SMBR_ALLOCED) free it too.
+ * Some of these are stack locals, not allocated.
+ *
+ * No locks here - this is the last ref.
+ */
+void
+smb_rq_done(struct smb_rq *rqp)
+{
+
+ /*
+ * No smb_vc_rele() here - see smb_rq_init()
+ */
+ mb_done(&rqp->sr_rq);
+ md_done(&rqp->sr_rp);
+ mutex_destroy(&rqp->sr_lock);
+ cv_destroy(&rqp->sr_cond);
+ if (rqp->sr_flags & SMBR_ALLOCED)
+ kmem_free(rqp, sizeof (*rqp));
+}
int
smb_rq_alloc(struct smb_connobj *layer, uchar_t cmd, struct smb_cred *scred,
@@ -85,9 +119,8 @@ smb_rq_alloc(struct smb_connobj *layer, uchar_t cmd, struct smb_cred *scred,
return (0);
}
-
int
-smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer, uchar_t cmd,
+smb_rq_init(struct smb_rq *rqp, struct smb_connobj *co, uchar_t cmd,
struct smb_cred *scred)
{
int error;
@@ -96,78 +129,106 @@ smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer, uchar_t cmd,
mutex_init(&rqp->sr_lock, NULL, MUTEX_DRIVER, NULL);
cv_init(&rqp->sr_cond, NULL, CV_DEFAULT, NULL);
- error = smb_rq_getenv(layer, &rqp->sr_vc, &rqp->sr_share);
+ error = smb_rq_getenv(co, &rqp->sr_vc, &rqp->sr_share);
if (error)
return (error);
+ /*
+ * We copied a VC pointer (vcp) into rqp->sr_vc,
+ * but we do NOT do a smb_vc_hold here. Instead,
+ * the caller is responsible for the hold on the
+ * share or the VC as needed. For smbfs callers,
+ * the hold is on the share, via the smbfs mount.
+ * For nsmb ioctl callers, the hold is done when
+ * the driver handle gets VC or share references.
+ * This design avoids frequent hold/rele activity
+ * when creating and completing requests.
+ */
+
rqp->sr_rexmit = SMBMAXRESTARTS;
- rqp->sr_cred = scred; /* XXX no ref hold */
- rqp->sr_mid = smb_vc_nextmid(rqp->sr_vc);
+ rqp->sr_cred = scred; /* Note: ref hold done by caller. */
+ rqp->sr_pid = (uint16_t)ddi_get_pid();
error = smb_rq_new(rqp, cmd);
- if (!error) {
- rqp->sr_flags |= SMBR_VCREF;
- smb_vc_hold(rqp->sr_vc);
- }
+
return (error);
}
static int
smb_rq_new(struct smb_rq *rqp, uchar_t cmd)
{
- struct smb_vc *vcp = rqp->sr_vc;
struct mbchain *mbp = &rqp->sr_rq;
+ struct smb_vc *vcp = rqp->sr_vc;
int error;
- static char tzero[12];
- caddr_t ptr;
- pid_t pid;
ASSERT(rqp != NULL);
- ASSERT(rqp->sr_cred != NULL);
- pid = rqp->sr_cred->vc_pid;
+
rqp->sr_sendcnt = 0;
rqp->sr_cmd = cmd;
+
mb_done(mbp);
md_done(&rqp->sr_rp);
error = mb_init(mbp);
if (error)
return (error);
- mb_put_mem(mbp, SMB_SIGNATURE, SMB_SIGLEN, MB_MSYSTEM);
- mb_put_uint8(mbp, cmd);
- mb_put_uint32le(mbp, 0);
- rqp->sr_rqflags = vcp->vc_hflags;
- mb_put_uint8(mbp, rqp->sr_rqflags);
+
+ /*
+ * Is this the right place to save the flags?
+ */
+ rqp->sr_rqflags = vcp->vc_hflags;
rqp->sr_rqflags2 = vcp->vc_hflags2;
- mb_put_uint16le(mbp, rqp->sr_rqflags2);
- mb_put_mem(mbp, tzero, 12, MB_MSYSTEM);
- ptr = mb_reserve(mbp, sizeof (u_int16_t));
- /*LINTED*/
- ASSERT(ptr == (caddr_t)((u_int16_t *)ptr));
- /*LINTED*/
- rqp->sr_rqtid = (u_int16_t *)ptr;
- mb_put_uint16le(mbp, (u_int16_t)(pid));
- ptr = mb_reserve(mbp, sizeof (u_int16_t));
- /*LINTED*/
- ASSERT(ptr == (caddr_t)((u_int16_t *)ptr));
- /*LINTED*/
- rqp->sr_rquid = (u_int16_t *)ptr;
- mb_put_uint16le(mbp, rqp->sr_mid);
+
+ /*
+ * The SMB header is filled in later by
+ * smb_rq_fillhdr (see below)
+ * Just reserve space here.
+ */
+ mb_put_mem(mbp, NULL, SMB_HDRLEN, MB_MZERO);
+
return (0);
}
+/*
+ * Given a request with it's body already composed,
+ * rewind to the start and fill in the SMB header.
+ * This is called after the request is enqueued,
+ * so we have the final MID, seq num. etc.
+ */
void
-smb_rq_done(struct smb_rq *rqp)
+smb_rq_fillhdr(struct smb_rq *rqp)
{
- /* No locks. Last ref. here. */
- if (rqp->sr_flags & SMBR_VCREF) {
- rqp->sr_flags &= ~SMBR_VCREF;
- smb_vc_rele(rqp->sr_vc);
- }
- mb_done(&rqp->sr_rq);
- md_done(&rqp->sr_rp);
- mutex_destroy(&rqp->sr_lock);
- cv_destroy(&rqp->sr_cond);
- if (rqp->sr_flags & SMBR_ALLOCED)
- kmem_free(rqp, sizeof (*rqp));
+ struct mbchain mbtmp, *mbp = &mbtmp;
+ mblk_t *m;
+
+ /*
+ * Fill in the SMB header using a dup of the first mblk,
+ * which points at the same data but has its own wptr,
+ * so we can rewind without trashing the message.
+ */
+ m = dupb(rqp->sr_rq.mb_top);
+ m->b_wptr = m->b_rptr; /* rewind */
+ mb_initm(mbp, m);
+
+ mb_put_mem(mbp, SMB_SIGNATURE, 4, MB_MSYSTEM);
+ mb_put_uint8(mbp, rqp->sr_cmd);
+ mb_put_uint32le(mbp, 0); /* status */
+ mb_put_uint8(mbp, rqp->sr_rqflags);
+ mb_put_uint16le(mbp, rqp->sr_rqflags2);
+ mb_put_uint16le(mbp, 0); /* pid-high */
+ mb_put_mem(mbp, NULL, 8, MB_MZERO); /* MAC sig. (later) */
+ mb_put_uint16le(mbp, 0); /* reserved */
+ mb_put_uint16le(mbp, rqp->sr_rqtid);
+ mb_put_uint16le(mbp, rqp->sr_pid);
+ mb_put_uint16le(mbp, rqp->sr_rquid);
+ mb_put_uint16le(mbp, rqp->sr_mid);
+
+ /* This will free the mblk from dupb. */
+ mb_done(mbp);
+}
+
+int
+smb_rq_simple(struct smb_rq *rqp)
+{
+ return (smb_rq_simple_timed(rqp, smb_timo_default));
}
/*
@@ -199,7 +260,7 @@ smb_rq_simple_timed(struct smb_rq *rqp, int timeout)
if (rqp->sr_rexmit <= 0)
break;
SMBRQ_LOCK(rqp);
- if (rqp->sr_share && rqp->sr_share->ss_mount) {
+ if (rqp->sr_share) {
cv_timedwait(&rqp->sr_cond, &(rqp)->sr_lock,
lbolt + (hz * SMB_RCNDELAY));
@@ -216,12 +277,6 @@ smb_rq_simple_timed(struct smb_rq *rqp, int timeout)
}
-int
-smb_rq_simple(struct smb_rq *rqp)
-{
- return (smb_rq_simple_timed(rqp, smb_timo_default));
-}
-
static int
smb_rq_enqueue(struct smb_rq *rqp)
{
@@ -230,56 +285,50 @@ smb_rq_enqueue(struct smb_rq *rqp)
int error = 0;
/*
- * Unfortunate special case needed for
- * tree disconnect, which needs sr_share
- * but should skip the reconnect check.
+ * Normal requests may initiate a reconnect,
+ * and/or wait for state changes to finish.
+ * Some requests set the NORECONNECT flag
+ * to avoid all that (i.e. tree discon)
*/
- if (rqp->sr_cmd == SMB_COM_TREE_DISCONNECT)
- ssp = NULL;
-
- /*
- * If this is an "internal" request, bypass any
- * wait for connection state changes, etc.
- * This request is making those changes.
- */
- if (rqp->sr_flags & SMBR_INTERNAL) {
- ASSERT(ssp == NULL);
- goto just_doit;
+ if (rqp->sr_flags & SMBR_NORECONNECT) {
+ if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ SMBSDEBUG("bad vc_state=%d\n", vcp->vc_state);
+ return (ENOTCONN);
+ }
+ if (ssp != NULL &&
+ ((ssp->ss_flags & SMBS_CONNECTED) == 0))
+ return (ENOTCONN);
+ goto ok_out;
}
/*
- * Wait for VC reconnect to finish...
- * XXX: Deal with reconnect later.
- * Just bail out for now.
- *
- * MacOS might check vfs_isforce() here.
+ * If we're not connected, initiate a reconnect
+ * and/or wait for an existing one to finish.
*/
if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- SMBSDEBUG("bad vc_state=%d\n", vcp->vc_state);
- return (ENOTCONN);
+ error = smb_iod_reconnect(vcp);
+ if (error != 0)
+ return (error);
}
/*
- * If this request has a "share" object:
- * 1: Deny access if share is _GONE (unmounted)
- * 2: Wait for state changes in that object,
- * Initiate share (re)connect if needed.
- * XXX: Not really doing 2 yet.
+ * If this request has a "share" object
+ * that needs a tree connect, do it now.
*/
- if (ssp) {
- if (ssp->ss_flags & SMBS_GONE)
- return (ENOTCONN);
- SMB_SS_LOCK(ssp);
- if (!smb_share_valid(ssp)) {
- error = smb_share_tcon(ssp);
- }
- SMB_SS_UNLOCK(ssp);
+ if (ssp != NULL && (ssp->ss_flags & SMBS_CONNECTED) == 0) {
+ error = smb_share_tcon(ssp, rqp->sr_cred);
+ if (error)
+ return (error);
}
- if (!error) {
- just_doit:
- error = smb_iod_addrq(rqp);
- }
+ /*
+ * We now know what UID + TID to use.
+ * Store them in the request.
+ */
+ok_out:
+ rqp->sr_rquid = vcp->vc_smbuid;
+ rqp->sr_rqtid = ssp ? ssp->ss_tid : SMB_TID_UNKNOWN;
+ error = smb_iod_addrq(rqp);
return (error);
}
@@ -358,23 +407,6 @@ smb_rq_intr(struct smb_rq *rqp)
return (EINTR);
return (0);
-#ifdef APPLE
- return (smb_sigintr(rqp->sr_cred->scr_vfsctx));
-#endif
-}
-
-int
-smb_rq_getrequest(struct smb_rq *rqp, struct mbchain **mbpp)
-{
- *mbpp = &rqp->sr_rq;
- return (0);
-}
-
-int
-smb_rq_getreply(struct smb_rq *rqp, struct mdchain **mbpp)
-{
- *mbpp = &rqp->sr_rp;
- return (0);
}
static int
@@ -383,7 +415,7 @@ smb_rq_getenv(struct smb_connobj *co,
{
struct smb_vc *vcp = NULL;
struct smb_share *ssp = NULL;
- int error = 0;
+ int error = EINVAL;
if (co->co_flags & SMBO_GONE) {
SMBSDEBUG("zombie CO\n");
@@ -392,27 +424,28 @@ smb_rq_getenv(struct smb_connobj *co,
}
switch (co->co_level) {
+ case SMBL_SHARE:
+ ssp = CPTOSS(co);
+ if ((co->co_flags & SMBO_GONE) ||
+ co->co_parent == NULL) {
+ SMBSDEBUG("zombie share %s\n", ssp->ss_name);
+ break;
+ }
+ /* instead of recursion... */
+ co = co->co_parent;
+ /* FALLTHROUGH */
case SMBL_VC:
vcp = CPTOVC(co);
- if (co->co_parent == NULL) {
+ if ((co->co_flags & SMBO_GONE) ||
+ co->co_parent == NULL) {
SMBSDEBUG("zombie VC %s\n", vcp->vc_srvname);
- error = EINVAL;
break;
}
+ error = 0;
break;
- case SMBL_SHARE:
- ssp = CPTOSS(co);
- if (co->co_parent == NULL) {
- SMBSDEBUG("zombie share %s\n", ssp->ss_name);
- error = EINVAL;
- break;
- }
- error = smb_rq_getenv(co->co_parent, &vcp, NULL);
- break;
default:
SMBSDEBUG("invalid level %d passed\n", co->co_level);
- error = EINVAL;
}
out:
@@ -433,7 +466,6 @@ static int
smb_rq_reply(struct smb_rq *rqp)
{
struct mdchain *mdp = &rqp->sr_rp;
- u_int32_t tdw;
u_int8_t tb;
int error, rperror = 0;
@@ -457,7 +489,7 @@ smb_rq_reply(struct smb_rq *rqp)
/*
* Parse the SMB header
*/
- error = md_get_uint32(mdp, &tdw);
+ error = md_get_uint32le(mdp, NULL);
if (error)
return (error);
error = md_get_uint8(mdp, &tb);
@@ -493,9 +525,9 @@ smb_rq_reply(struct smb_rq *rqp)
} else
rqp->sr_flags &= ~SMBR_MOREDATA;
- error = md_get_uint32(mdp, &tdw);
- error = md_get_uint32(mdp, &tdw);
- error = md_get_uint32(mdp, &tdw);
+ error = md_get_uint32le(mdp, NULL);
+ error = md_get_uint32le(mdp, NULL);
+ error = md_get_uint32le(mdp, NULL);
error = md_get_uint16le(mdp, &rqp->sr_rptid);
error = md_get_uint16le(mdp, &rqp->sr_rppid);
@@ -528,8 +560,6 @@ smb_t2_alloc(struct smb_connobj *layer, ushort_t setup, struct smb_cred *scred,
if (t2p == NULL)
return (ENOMEM);
error = smb_t2_init(t2p, layer, &setup, 1, scred);
- mutex_init(&t2p->t2_lock, NULL, MUTEX_DRIVER, NULL);
- cv_init(&t2p->t2_cond, NULL, CV_DEFAULT, NULL);
t2p->t2_flags |= SMBT2_ALLOCED;
if (error) {
smb_t2_done(t2p);
@@ -569,6 +599,9 @@ smb_t2_init(struct smb_t2rq *t2p, struct smb_connobj *source, ushort_t *setup,
int error;
bzero(t2p, sizeof (*t2p));
+ mutex_init(&t2p->t2_lock, NULL, MUTEX_DRIVER, NULL);
+ cv_init(&t2p->t2_cond, NULL, CV_DEFAULT, NULL);
+
t2p->t2_source = source;
t2p->t2_setupcount = (u_int16_t)setupcnt;
t2p->t2_setupdata = t2p->t2_setup;
@@ -733,7 +766,7 @@ smb_t2_reply(struct smb_t2rq *t2p)
md_get_uint8(mdp, NULL); /* Reserved2 */
tmp = wc;
while (tmp--)
- md_get_uint16(mdp, NULL);
+ md_get_uint16le(mdp, NULL);
if ((error2 = md_get_uint16le(mdp, &bc)) != 0)
break;
@@ -859,7 +892,7 @@ smb_nt_reply(struct smb_ntrq *ntp)
md_get_uint8(mdp, &wc); /* SetupCount */
tmp = wc;
while (tmp--)
- md_get_uint16(mdp, NULL);
+ md_get_uint16le(mdp, NULL);
if ((error2 = md_get_uint16le(mdp, &bc)) != 0)
break;
@@ -1375,7 +1408,7 @@ smb_t2_request(struct smb_t2rq *t2p)
if (++i > SMBMAXRESTARTS)
break;
mutex_enter(&(t2p)->t2_lock);
- if (t2p->t2_share && t2p->t2_share->ss_mount) {
+ if (t2p->t2_share) {
cv_timedwait(&t2p->t2_cond, &(t2p)->t2_lock,
lbolt + (hz * SMB_RCNDELAY));
} else {
@@ -1408,7 +1441,7 @@ smb_nt_request(struct smb_ntrq *ntp)
if (++i > SMBMAXRESTARTS)
break;
mutex_enter(&(ntp)->nt_lock);
- if (ntp->nt_share && ntp->nt_share->ss_mount) {
+ if (ntp->nt_share) {
cv_timedwait(&ntp->nt_cond, &(ntp)->nt_lock,
lbolt + (hz * SMB_RCNDELAY));
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
index 7359b42049..1aeefcedd7 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -50,11 +50,12 @@
#define SMBR_RESTART 0x0010 /* req should be repeated if possible */
#define SMBR_NORESTART 0x0020 /* request is not restartable */
#define SMBR_MULTIPACKET 0x0040 /* multiple pkts can be sent/received */
-#define SMBR_INTERNAL 0x0080 /* request is internal to netsmb */
+#define SMBR_INTERNAL 0x0080 /* request enqueued by the IOD! */
#define SMBR_NOINTR_SEND 0x0100 /* no interrupt in send wait */
#define SMBR_NOINTR_RECV 0x0200 /* no interrupt in recv wait */
#define SMBR_SENDWAIT 0x0400 /* waiting for send to complete */
-#define SMBR_VCREF 0x4000 /* took vc reference */
+#define SMBR_NORECONNECT 0x0800 /* do not reconnect for this */
+/* SMBR_VCREF 0x4000 * took vc reference (obsolete) */
#define SMBR_MOREDATA 0x8000 /* our buffer was too small */
#define SMBT2_ALLSENT 0x0001 /* all data and params are sent */
@@ -67,7 +68,6 @@
#define SMBRQ_LOCK(rqp) mutex_enter(&(rqp)->sr_lock)
#define SMBRQ_UNLOCK(rqp) mutex_exit(&(rqp)->sr_lock)
-
enum smbrq_state {
SMBRQ_NOTSENT, /* rq have data to send */
SMBRQ_SENT, /* send procedure completed */
@@ -85,13 +85,16 @@ struct smb_rq {
struct smb_vc *sr_vc;
struct smb_share *sr_share;
struct _kthread *sr_owner;
- ushort_t sr_mid;
uint32_t sr_seqno; /* Seq. no. of request */
uint32_t sr_rseqno; /* Seq. no. of reply */
struct mbchain sr_rq;
uchar_t sr_cmd;
uint8_t sr_rqflags;
uint16_t sr_rqflags2;
+ uint16_t sr_rqtid;
+ uint16_t sr_pid;
+ uint16_t sr_rquid;
+ uint16_t sr_mid;
uchar_t *sr_wcount;
uchar_t *sr_bcount;
struct mdchain sr_rp;
@@ -105,8 +108,6 @@ struct smb_rq {
int sr_sendcnt;
struct timespec sr_timesent;
int sr_lerror;
- uint16_t *sr_rqtid;
- uint16_t *sr_rquid;
uint8_t sr_errclass;
uint16_t sr_serror;
uint32_t sr_error;
@@ -124,7 +125,7 @@ struct smb_t2rq {
kcondvar_t t2_cond;
uint16_t t2_setupcount;
uint16_t *t2_setupdata;
- uint16_t t2_setup[SMB_MAXSETUPWORDS];
+ uint16_t t2_setup[SMBIOC_T2RQ_MAXSETUP];
uint8_t t2_maxscount; /* max setup words to return */
uint16_t t2_maxpcount; /* max param bytes to return */
uint16_t t2_maxdcount; /* max data bytes to return */
@@ -174,13 +175,18 @@ struct smb_ntrq {
};
typedef struct smb_ntrq smb_ntrq_t;
+#define smb_rq_getrequest(RQ, MBPP) \
+ *(MBPP) = &(RQ)->sr_rq
+#define smb_rq_getreply(RQ, MDPP) \
+ *(MDPP) = &(RQ)->sr_rp
+
+void smb_rq_done(struct smb_rq *rqp);
int smb_rq_alloc(struct smb_connobj *layer, uchar_t cmd,
struct smb_cred *scred, struct smb_rq **rqpp);
int smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer,
uchar_t cmd, struct smb_cred *scred);
-void smb_rq_done(struct smb_rq *rqp);
-int smb_rq_getrequest(struct smb_rq *rqp, struct mbchain **mbpp);
-int smb_rq_getreply(struct smb_rq *rqp, struct mdchain **mbpp);
+
+void smb_rq_fillhdr(struct smb_rq *rqp);
void smb_rq_wstart(struct smb_rq *rqp);
void smb_rq_wend(struct smb_rq *rqp);
void smb_rq_bstart(struct smb_rq *rqp);
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
new file mode 100644
index 0000000000..91c450bb23
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
@@ -0,0 +1,311 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Support for SMB "signing" (message integrity)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <sys/md4.h>
+#include <sys/md5.h>
+#include <sys/des.h>
+#include <sys/kmem.h>
+#include <sys/crypto/api.h>
+#include <sys/crypto/common.h>
+#include <sys/cmn_err.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/sdt.h>
+
+#include <netsmb/smb_osdep.h>
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_dev.h>
+#include <netsmb/smb_rq.h>
+
+#ifdef DEBUG
+/*
+ * Set this to a small number to debug sequence numbers
+ * that seem to get out of step.
+ */
+int nsmb_signing_fudge = 0;
+#endif
+
+/* Mechanism definitions */
+static crypto_mechanism_t crypto_mech_md5 = { CRYPTO_MECH_INVALID };
+
+void
+smb_crypto_mech_init(void)
+{
+ crypto_mech_md5.cm_type = crypto_mech2id(SUN_CKM_MD5);
+}
+
+
+
+#define SMBSIGLEN 8 /* SMB signature length */
+#define SMBSIGOFF 14 /* SMB signature offset */
+
+/*
+ * Compute HMAC-MD5 of packet data, using the stored MAC key.
+ *
+ * See similar code for the server side:
+ * uts/common/fs/smbsrv/smb_signing.c : smb_sign_calc
+ */
+static int
+smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
+ uint32_t seqno, uchar_t *signature)
+{
+ crypto_context_t crypto_ctx;
+ crypto_data_t key;
+ crypto_data_t data;
+ crypto_data_t digest;
+ uchar_t mac[16];
+ int status;
+ /*
+ * This union is a little bit of trickery to:
+ * (1) get the sequence number int aligned, and
+ * (2) reduce the number of digest calls, at the
+ * cost of a copying 32 bytes instead of 8.
+ * Both sides of this union are 2+32 bytes.
+ */
+ union {
+ struct {
+ uint8_t skip[2]; /* not used - just alignment */
+ uint8_t raw[SMB_HDRLEN]; /* header length (32) */
+ } r;
+ struct {
+ uint8_t skip[2]; /* not used - just alignment */
+ uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
+ uint32_t sig[2]; /* MAC signature, aligned! */
+ uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
+ } s;
+ } smbhdr;
+
+ ASSERT(mp != NULL);
+ ASSERT(MBLKL(mp) >= SMB_HDRLEN);
+ ASSERT(vcp->vc_mackey != NULL);
+
+ /*
+ * Make an aligned copy of the SMB header
+ * and fill in the sequence number.
+ */
+ bcopy(mp->b_rptr, smbhdr.r.raw, SMB_HDRLEN);
+ smbhdr.s.sig[0] = htolel(seqno);
+ smbhdr.s.sig[1] = 0;
+
+ /*
+ * Compute the MAC: MD5(concat(Key, message))
+ */
+ if (crypto_mech_md5.cm_type == CRYPTO_MECH_INVALID) {
+ SMBSDEBUG("crypto_mech_md5 invalid\n");
+ return (CRYPTO_MECHANISM_INVALID);
+ }
+ status = crypto_digest_init(&crypto_mech_md5, &crypto_ctx, 0);
+ if (status != CRYPTO_SUCCESS)
+ return (status);
+
+ /* Digest the MAC Key */
+ key.cd_format = CRYPTO_DATA_RAW;
+ key.cd_offset = 0;
+ key.cd_length = vcp->vc_mackeylen;
+ key.cd_miscdata = 0;
+ key.cd_raw.iov_base = (char *)vcp->vc_mackey;
+ key.cd_raw.iov_len = vcp->vc_mackeylen;
+ status = crypto_digest_update(crypto_ctx, &key, 0);
+ if (status != CRYPTO_SUCCESS)
+ return (status);
+
+ /* Digest the (copied) SMB header */
+ data.cd_format = CRYPTO_DATA_RAW;
+ data.cd_offset = 0;
+ data.cd_length = SMB_HDRLEN;
+ data.cd_miscdata = 0;
+ data.cd_raw.iov_base = (char *)smbhdr.r.raw;
+ data.cd_raw.iov_len = SMB_HDRLEN;
+ status = crypto_digest_update(crypto_ctx, &data, 0);
+ if (status != CRYPTO_SUCCESS)
+ return (status);
+
+ /* Digest rest of the SMB message. */
+ data.cd_format = CRYPTO_DATA_MBLK;
+ data.cd_offset = SMB_HDRLEN;
+ data.cd_length = msgdsize(mp) - SMB_HDRLEN;
+ data.cd_miscdata = 0;
+ data.cd_mp = mp;
+ status = crypto_digest_update(crypto_ctx, &data, 0);
+ if (status != CRYPTO_SUCCESS)
+ return (status);
+
+ /* Final */
+ digest.cd_format = CRYPTO_DATA_RAW;
+ digest.cd_offset = 0;
+ digest.cd_length = sizeof (mac);
+ digest.cd_miscdata = 0;
+ digest.cd_raw.iov_base = (char *)mac;
+ digest.cd_raw.iov_len = sizeof (mac);
+ status = crypto_digest_final(crypto_ctx, &digest, 0);
+ if (status != CRYPTO_SUCCESS)
+ return (status);
+
+ /*
+ * Finally, store the signature.
+ * (first 8 bytes of the mac)
+ */
+ if (signature)
+ bcopy(mac, signature, SMBSIGLEN);
+
+ return (0);
+}
+
+/*
+ * Sign a request with HMAC-MD5.
+ */
+int
+smb_rq_sign(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ mblk_t *mp = rqp->sr_rq.mb_top;
+ uint8_t *sigloc;
+ int status;
+
+ /*
+ * Our mblk allocation ensures this,
+ * but just in case...
+ */
+ if (MBLKL(mp) < SMB_HDRLEN) {
+ if (!pullupmsg(mp, SMB_HDRLEN))
+ return (0);
+ }
+ sigloc = mp->b_rptr + SMBSIGOFF;
+
+ if (vcp->vc_mackey == NULL) {
+ /*
+ * Signing is required, but we have no key yet
+ * fill in with the magic fake signing value.
+ * This happens with SPNEGO, NTLMSSP, ...
+ */
+ bcopy("BSRSPLY", sigloc, 8);
+ return (0);
+ }
+
+ /*
+ * This will compute the MAC and store it
+ * directly into the message at sigloc.
+ */
+ status = smb_compute_MAC(vcp, mp, rqp->sr_seqno, sigloc);
+ if (status != CRYPTO_SUCCESS) {
+ SMBSDEBUG("Crypto error %d", status);
+ bzero(sigloc, SMBSIGLEN);
+ return (ENOTSUP);
+ }
+ return (0);
+}
+
+/*
+ * Verify reply signature.
+ */
+int
+smb_rq_verify(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ mblk_t *mp = rqp->sr_rp.md_top;
+ uint8_t sigbuf[SMBSIGLEN];
+ uint8_t *sigloc;
+ int status;
+ int fudge;
+
+ /*
+ * Note vc_mackey and vc_mackeylen gets filled in by
+ * smb_usr_iod_work as the connection comes in.
+ */
+ if (vcp->vc_mackey == NULL) {
+ SMBSDEBUG("no mac key\n");
+ return (0);
+ }
+
+ /*
+ * Let caller deal with empty reply or short messages by
+ * returning zero. Caller will fail later, in parsing.
+ */
+ if (mp == NULL) {
+ SMBSDEBUG("empty reply\n");
+ return (0);
+ }
+ if (MBLKL(mp) < SMB_HDRLEN) {
+ if (!pullupmsg(mp, SMB_HDRLEN))
+ return (0);
+ }
+ sigloc = mp->b_rptr + SMBSIGOFF;
+
+ SMBSDEBUG("sr_rseqno = 0x%x\n", rqp->sr_rseqno);
+
+ status = smb_compute_MAC(vcp, mp, rqp->sr_rseqno, sigbuf);
+ if (status != CRYPTO_SUCCESS) {
+ SMBSDEBUG("Crypto error %d", status);
+ /*
+ * If we can't compute a MAC, then there's
+ * no point trying other seqno values.
+ */
+ return (EBADRPC);
+ }
+
+ /*
+ * Compare the computed signature with the
+ * one found in the message (at sigloc)
+ */
+ if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
+ return (0);
+
+ SMBSDEBUG("BAD signature, MID=0x%x\n", rqp->sr_mid);
+
+#ifdef DEBUG
+ /*
+ * For diag purposes, we check whether the client/server idea
+ * of the sequence # has gotten a bit out of sync.
+ */
+ for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) {
+ smb_compute_MAC(vcp, mp, rqp->sr_rseqno + fudge, sigbuf);
+ if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
+ break;
+ smb_compute_MAC(vcp, mp, rqp->sr_rseqno - fudge, sigbuf);
+ if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) {
+ fudge = -fudge;
+ break;
+ }
+ }
+ if (fudge <= nsmb_signing_fudge) {
+ SMBSDEBUG("sr_rseqno=%d, but %d would have worked\n",
+ rqp->sr_rseqno, rqp->sr_rseqno + fudge);
+ }
+#endif
+ return (EBADRPC);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
index 3412109a68..fce18f74ff 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -105,19 +105,6 @@ struct smb_dialect {
const char *d_name;
};
-smb_unichar smb_unieol = 0;
-
-static struct smb_dialect smb_dialects[] = {
- {SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"},
- {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"},
- {SMB_DIALECT_LANMAN2_0, "LM1.2X002"},
- {SMB_DIALECT_LANMAN2_1, "LANMAN2.1"},
- {SMB_DIALECT_NTLM0_12, "NT LM 0.12"},
- {-1, NULL}
-};
-
-#define SMB_DIALECT_MAX \
- (sizeof (smb_dialects) / sizeof (struct smb_dialect) - 2)
/*
* Number of seconds between 1970 and 1601 year
@@ -177,1346 +164,143 @@ extern int iconv_open(const char *to, const char *from, void **handle);
extern int iconv_close(void *handle);
#endif
-int
-smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
-{
- struct smb_dialect *dp;
- struct smb_sopt *sp = NULL;
- struct smb_rq *rqp;
- struct mbchain *mbp;
- struct mdchain *mdp;
- u_int8_t wc, stime[8], sblen;
- u_int16_t dindex, tw, tw1, swlen, bc;
- int error;
- int unicode = 0;
- char *servercs;
- void *servercshandle = NULL;
- void *localcshandle = NULL;
- int negotiated_signing = 0;
- u_int16_t toklen;
-
- /*
- * We set various flags below to keep track of
- * interesting things we learn from negotiation.
- * Clear all the flags except these two, which
- * are operational rather than protocol info.
- */
- SMB_VC_LOCK(vcp);
- vcp->vc_flags &= (SMBV_GONE | SMBV_RECONNECTING);
- SMB_VC_UNLOCK(vcp);
-
- /*
- * Now vc_hflags and vc_hflags2. Careful with this:
- * Leave SMB_FLAGS2_UNICODE off so mb_put_dstring
- * marshalls the dialect strings in plain ascii.
- * We'll turn that on below, if appropriate.
- *
- * Note: These flags are marshalled into the request
- * when we call smb_rq_alloc, so changing them after
- * this point does not affect THIS request.
- */
- vcp->vc_hflags = SMB_FLAGS_CASELESS;
- vcp->vc_hflags2 = (SMB_FLAGS2_ERR_STATUS |
- SMB_FLAGS2_KNOWS_LONG_NAMES);
-
- /* User-level may ask for extended security. */
- if (vcp->vc_vopt & SMBVOPT_EXT_SEC)
- vcp->vc_hflags2 |= SMB_FLAGS2_EXT_SEC;
-
- /* Also clear any old key (for reconnect) */
- if (vcp->vc_mackey != NULL) {
- kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
- vcp->vc_mackey = NULL;
- vcp->vc_mackeylen = 0;
- vcp->vc_seqno = 0;
- }
-
- sp = &vcp->vc_sopt;
- bzero(sp, sizeof (struct smb_sopt));
- error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- for (dp = smb_dialects; dp->d_id != -1; dp++) {
- mb_put_uint8(mbp, SMB_DT_DIALECT);
- smb_put_dstring(mbp, vcp, dp->d_name, SMB_CS_NONE);
- }
- smb_rq_bend(rqp);
-
- /*
- * This request should not wait for
- * connection state changes, etc.
- */
- rqp->sr_flags |= SMBR_INTERNAL;
- error = smb_rq_simple(rqp);
- SMBSDEBUG("%d\n", error);
- if (error)
- goto bad;
-
- smb_rq_getreply(rqp, &mdp);
- do {
- error = md_get_uint8(mdp, &wc);
- if (error)
- break;
- error = md_get_uint16le(mdp, &dindex);
- if (error)
- break;
- error = EBADRPC;
- if (dindex > SMB_DIALECT_MAX) {
- SMBERROR(
- "Don't know how to talk with server %s (%d)\n",
- vcp->vc_srvname, dindex);
- break;
- }
- dp = smb_dialects + dindex;
- if (dindex < SMB_DIALECT_MAX) {
- SMBERROR(
- "Server %s negotiated old dialect (%s)\n",
- vcp->vc_srvname, dp->d_name);
- }
- sp->sv_proto = dp->d_id;
- SMBSDEBUG("Dialect %s (%d, %d)\n", dp->d_name, dindex, wc);
- if (dp->d_id >= SMB_DIALECT_NTLM0_12) {
- if (wc != 17)
- break;
- md_get_uint8(mdp, &sp->sv_sm);
- md_get_uint16le(mdp, &sp->sv_maxmux);
- md_get_uint16le(mdp, &sp->sv_maxvcs);
- md_get_uint32le(mdp, &sp->sv_maxtx);
- md_get_uint32le(mdp, &sp->sv_maxraw);
- md_get_uint32le(mdp, &sp->sv_skey);
- md_get_uint32le(mdp, &sp->sv_caps);
- md_get_mem(mdp, (char *)stime, 8, MB_MSYSTEM);
- md_get_uint16le(mdp, (u_int16_t *)&sp->sv_tz);
- md_get_uint8(mdp, &sblen);
- error = md_get_uint16le(mdp, &bc);
- if (error)
- break;
-
- /* BEGIN CSTYLED */
- /*
- * Will we do SMB signing? Or block the connection?
- * The table below describes this logic. References:
- * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3]
- * http://msdn.microsoft.com/en-us/library/cc212511.aspx
- * http://msdn.microsoft.com/en-us/library/cc212929.aspx
- *
- * Srv/Cli | Required | Enabled | If Required | Disabled
- * ------------+----------+------------+-------------+-----------
- * Required | Signed | Signed | Signed | Blocked [1]
- * ------------+----------+------------+-------------+-----------
- * Enabled | Signed | Signed | Not Signed | Not Signed
- * ------------+----------+------------+-------------+-----------
- * If Required | Signed | Not Signed | Not Signed | Not Signed
- * ------------+----------+------------+-------------+-----------
- * Disabled | Blocked | Not Signed | Not Signed | Not Signed
- *
- * [1] Like Windows 2003 and later, we don't really implement
- * the "Disabled" setting. Instead we implement "If Required",
- * so we always sign if the server requires signing.
- */
- /* END CSTYLED */
-
- if (sp->sv_sm & SMB_SM_SIGS_REQUIRE) {
- /*
- * Server requires signing.
- */
- negotiated_signing = 1;
- } else if (sp->sv_sm & SMB_SM_SIGS) {
- /*
- * Server enables signing (client's option).
- * If enabled locally, do signing.
- */
- if (vcp->vc_vopt & SMBVOPT_SIGNING_ENABLED)
- negotiated_signing = 1;
- /* else not signing. */
- } else {
- /*
- * Server does not support signing.
- * If we "require" it, bail now.
- */
- if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
- SMBERROR("Client requires signing "
- "but server has it disabled.\n");
- error = EBADRPC;
- break;
- }
- }
- SMBSDEBUG("Security signatures: %d\n",
- negotiated_signing);
- if (negotiated_signing) {
- SMB_VC_LOCK(vcp);
- vcp->vc_flags |= SMBV_WILL_SIGN;
- SMB_VC_UNLOCK(vcp);
- }
-
- if (sp->sv_caps & SMB_CAP_UNICODE) {
- SMB_VC_LOCK(vcp);
- vcp->vc_flags |= SMBV_UNICODE;
- SMB_VC_UNLOCK(vcp);
- unicode = 1;
- }
- if (!(sp->sv_caps & SMB_CAP_STATUS32)) {
- /*
- * They don't do NT error codes.
- *
- * If we send requests with
- * SMB_FLAGS2_ERR_STATUS set in
- * Flags2, Windows 98, at least,
- * appears to send replies with that
- * bit set even though it sends back
- * DOS error codes. (They probably
- * just use the request header as
- * a template for the reply header,
- * and don't bother clearing that bit.)
- *
- * Therefore, we clear that bit in
- * our vc_hflags2 field.
- */
- vcp->vc_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
- }
- if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
- sp->sv_maxtx < 4096 &&
- (sp->sv_caps & SMB_CAP_NT_SMBS) == 0) {
- SMB_VC_LOCK(vcp);
- vcp->vc_flags |= SMBV_WIN95;
- SMB_VC_UNLOCK(vcp);
- SMBSDEBUG("Win95 detected\n");
- }
-
- /*
- * 3 cases here:
- *
- * 1) Extended security.
- * Read bc bytes below for security blob.
- * Note that we DON'T put the Caps flag in outtok.
- * outtoklen = bc
- *
- * 2) No extended security, have challenge data and
- * possibly a domain name (which might be zero
- * bytes long, meaning "missing").
- * Copy challenge stuff to vcp->vc_ch (sblen bytes),
- * then copy Cap flags and domain name (bc-sblen
- * bytes) to outtok.
- * outtoklen = bc-sblen+4, where the 4 is for the
- * Caps flag.
- *
- * 3) No extended security, no challenge data, just
- * possibly a domain name.
- * Copy Capsflags and domain name (bc) to outtok.
- * outtoklen = bc+4, where 4 is for the Caps flag
- */
-
- /*
- * Sanity check: make sure the challenge length
- * isn't bigger than the byte count.
- */
- if (sblen > bc) {
- error = EBADRPC;
- break;
- }
- toklen = bc;
-
- if (sblen && sblen <= SMB_MAXCHALLENGELEN &&
- sp->sv_sm & SMB_SM_ENCRYPT) {
- error = md_get_mem(mdp,
- (char *)vcp->vc_challenge,
- sblen, MB_MSYSTEM);
- if (error)
- break;
- vcp->vc_chlen = sblen;
- toklen -= sblen;
-
- SMB_VC_LOCK(vcp);
- vcp->vc_flags |= SMBV_ENCRYPT;
- SMB_VC_UNLOCK(vcp);
- }
-
- /*
- * For servers that don't support unicode
- * there are 2 things we could do:
- * 1) Pass the server Caps flags up to the
- * user level so the logic up there will
- * know whether the domain name is unicode
- * (this is what I did).
- * 2) Try to convert the non-unicode string
- * to unicode. This doubles the length of
- * the outtok buffer and would be guessing that
- * the string was single-byte ascii, and that
- * might be wrong. Why ask for trouble?
- */
-
- /* Warning: NetApp may omit the GUID */
-
- if (!(sp->sv_caps & SMB_CAP_EXT_SECURITY)) {
- /*
- * No extended security.
- * Stick domain name, if present,
- * and caps in outtok.
- */
- toklen = toklen + 4; /* space for Caps flags */
- vcp->vc_outtoklen = toklen;
- vcp->vc_outtok = kmem_alloc(toklen, KM_SLEEP);
- /* first store server capability bits */
- /*LINTED*/
- ASSERT(vcp->vc_outtok ==
- (caddr_t)(((u_int32_t *)vcp->vc_outtok)));
- /*LINTED*/
- *(u_int32_t *)(vcp->vc_outtok) = sp->sv_caps;
-
- /*
- * Then store the domain name if present;
- * be sure to subtract 4 from the length
- * for the Caps flag.
- */
- if (toklen > 4) {
- error = md_get_mem(mdp,
- vcp->vc_outtok+4, toklen-4,
- MB_MSYSTEM);
- }
- } else {
- /*
- * Extended security.
- * Stick the rest of the buffer in outtok.
- */
- vcp->vc_outtoklen = toklen;
- vcp->vc_outtok = kmem_alloc(toklen, KM_SLEEP);
- error = md_get_mem(mdp, vcp->vc_outtok, toklen,
- MB_MSYSTEM);
- }
- break;
- }
- vcp->vc_hflags2 &= ~(SMB_FLAGS2_EXT_SEC|SMB_FLAGS2_DFS|
- SMB_FLAGS2_ERR_STATUS|SMB_FLAGS2_UNICODE);
- if (dp->d_id > SMB_DIALECT_CORE) {
- md_get_uint16le(mdp, &tw);
- sp->sv_sm = (uchar_t)tw;
- md_get_uint16le(mdp, &tw);
- sp->sv_maxtx = tw;
- md_get_uint16le(mdp, &sp->sv_maxmux);
- md_get_uint16le(mdp, &sp->sv_maxvcs);
- md_get_uint16le(mdp, &tw); /* rawmode */
- md_get_uint32le(mdp, &sp->sv_skey);
- if (wc == 13) { /* >= LANMAN1 */
- md_get_uint16(mdp, &tw); /* time */
- md_get_uint16(mdp, &tw1); /* date */
- md_get_uint16le(mdp, (u_int16_t *)&sp->sv_tz);
- md_get_uint16le(mdp, &swlen);
- if (swlen > SMB_MAXCHALLENGELEN)
- break;
- md_get_uint16(mdp, NULL); /* mbz */
- if (md_get_uint16le(mdp, &bc) != 0)
- break;
- if (bc < swlen)
- break;
- if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) {
- error = md_get_mem(mdp,
- (char *)vcp->vc_challenge,
- swlen, MB_MSYSTEM);
- if (error)
- break;
- vcp->vc_chlen = swlen;
-
- SMB_VC_LOCK(vcp);
- vcp->vc_flags |= SMBV_ENCRYPT;
- SMB_VC_UNLOCK(vcp);
- }
- }
- } else { /* an old CORE protocol */
- vcp->vc_hflags2 &= ~SMB_FLAGS2_KNOWS_LONG_NAMES;
- sp->sv_maxmux = 1;
- }
- error = 0;
- /*LINTED*/
- } while (0);
- if (error == 0) {
- uint32_t x;
-
- /*
- * Maximum outstanding requests.
- */
- if (vcp->vc_maxmux < 1)
- vcp->vc_maxmux = 1;
-
- /*
- * Max VCs between server and client.
- * We only use one.
- */
- vcp->vc_maxvcs = sp->sv_maxvcs;
- if (vcp->vc_maxvcs < 1)
- vcp->vc_maxvcs = 1;
-
- /*
- * Maximum transfer size.
- * Sanity checks:
- *
- * Spec. says lower limit is 1024. OK.
- *
- * Let's be conservative about an upper limit here.
- * Win2k uses 16644 (and others) so 32k should be a
- * reasonable sanity limit for this value.
- *
- * Note that this limit does NOT affect READX/WRITEX
- * with CAP_LARGE_xxx, which we nearly always use.
- */
- vcp->vc_txmax = sp->sv_maxtx;
- if (vcp->vc_txmax < 1024)
- vcp->vc_txmax = 1024;
- if (vcp->vc_txmax > 0x8000)
- vcp->vc_txmax = 0x8000;
-
- /*
- * Max read/write sizes, WITHOUT overhead.
- * This is just the payload size, so we must
- * leave room for the SMB headers, etc.
- * This is just the vc_txmax value, but
- * reduced and rounded down. Tricky bit:
- *
- * Servers typically give us a value that's
- * some nice "round" number, i.e 0x4000 plus
- * some overhead, i.e. Win2k: 16644==0x4104
- * Subtract for the SMB header (32) and the
- * SMB command word and byte vectors (34?),
- * then round down to a 512 byte multiple.
- */
- x = (vcp->vc_txmax - 68) & 0xFE00;
- vcp->vc_rxmax = x;
- vcp->vc_wxmax = x;
-
- SMBSDEBUG("TZ = %d\n", sp->sv_tz);
- SMBSDEBUG("CAPS = %x\n", sp->sv_caps);
-
- SMBSDEBUG("maxmux = %d\n", vcp->vc_maxmux);
- SMBSDEBUG("maxvcs = %d\n", vcp->vc_maxvcs);
- SMBSDEBUG("txmax = %d\n", vcp->vc_txmax);
- SMBSDEBUG("rxmax = %d\n", vcp->vc_rxmax);
- SMBSDEBUG("wxmax = %d\n", vcp->vc_wxmax);
- }
-
- /*
- * If the server supports Unicode, set up to use Unicode
- * when talking to them. Othewise, use code page 437.
- */
- if (unicode)
- servercs = "ucs-2";
- else {
- /*
- * todo: if we can't determine the server's encoding, we
- * need to try a best-guess here.
- */
- servercs = "cp437";
- }
-#if defined(NOICONVSUPPORT) || defined(lint)
- /*
- * REVISIT
- */
- error = iconv_open(servercs, "utf-8", &servercshandle);
- if (error != 0)
- goto bad;
- error = iconv_open("utf-8", servercs, &localcshandle);
- if (error != 0) {
- iconv_close(servercshandle);
- goto bad;
- }
- if (vcp->vc_toserver)
- iconv_close(vcp->vc_toserver);
- if (vcp->vc_tolocal)
- iconv_close(vcp->vc_tolocal);
- vcp->vc_toserver = servercshandle;
- vcp->vc_tolocal = localcshandle;
-#endif
- if (unicode)
- vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE;
-bad:
- smb_rq_done(rqp);
- return (error);
-}
-
-static void
-get_ascii_password(struct smb_vc *vcp, int upper, char *pbuf)
-{
- const char *pw = smb_vc_getpass(vcp);
- if (upper)
- smb_toupper(pw, pbuf, SMB_MAXPASSWORDLEN);
- else
- strncpy(pbuf, pw, SMB_MAXPASSWORDLEN);
- pbuf[SMB_MAXPASSWORDLEN] = '\0';
-}
-
-#ifdef APPLE
-static void
-get_unicode_password(struct smb_vc *vcp, char *pbuf)
-{
- strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN);
- pbuf[SMB_MAXPASSWORDLEN] = '\0';
-}
-#endif
-
-/*ARGSUSED*/
-static uchar_t *
-add_name_to_blob(uchar_t *blobnames, struct smb_vc *vcp, const uchar_t *name,
- size_t namelen, int nametype, int uppercase)
-{
- struct ntlmv2_namehdr namehdr;
- char *namebuf;
- u_int16_t *uninamebuf;
- size_t uninamelen;
-
- if (name != NULL) {
- uninamebuf = kmem_alloc(2 * namelen, KM_SLEEP);
- if (uppercase) {
- namebuf = kmem_alloc(namelen + 1, KM_SLEEP);
- smb_toupper((const char *)name, namebuf, namelen);
- namebuf[namelen] = '\0';
- uninamelen = smb_strtouni(uninamebuf, namebuf, namelen,
- UCONV_IGNORE_NULL);
- kmem_free(namebuf, namelen + 1);
- } else {
- uninamelen = smb_strtouni(uninamebuf, (char *)name,
- namelen, UCONV_IGNORE_NULL);
- }
- } else {
- uninamelen = 0;
- uninamebuf = NULL;
- }
- namehdr.type = htoles(nametype);
- namehdr.len = htoles(uninamelen);
- bcopy(&namehdr, blobnames, sizeof (namehdr));
- blobnames += sizeof (namehdr);
- if (uninamebuf != NULL) {
- bcopy(uninamebuf, blobnames, uninamelen);
- blobnames += uninamelen;
- kmem_free(uninamebuf, namelen * 2);
- }
- return (blobnames);
-}
-
-static uchar_t *
-make_ntlmv2_blob(struct smb_vc *vcp, u_int64_t client_nonce,
- size_t *bloblen, size_t *blob_allocsz)
-{
- uchar_t *blob;
- size_t blobsize;
- size_t domainlen, srvlen;
- struct ntlmv2_blobhdr *blobhdr;
- struct timespec now;
- u_int64_t timestamp;
- uchar_t *blobnames;
- ptrdiff_t diff;
-
- /*
- * XXX - the information at
- *
- * http://davenport.sourceforge.net/ntlm.html#theNtlmv2Response
- *
- * says that the "target information" comes from the Type 2 message,
- * but, as we're not doing NTLMSSP, we don't have that.
- *
- * Should we use the names from the NegProt response? Can we trust
- * the NegProt response? (I've seen captures where the primary
- * domain name has an extra byte in front of it.)
- *
- * For now, we don't trust it - we use vcp->vc_domain and
- * vcp->vc_srvname, instead. We upper-case them and convert
- * them to Unicode, as that's what's supposed to be in the blob.
- */
- domainlen = strlen(vcp->vc_domain);
- srvlen = strlen(vcp->vc_srvname);
- blobsize = sizeof (struct ntlmv2_blobhdr)
- + 3*sizeof (struct ntlmv2_namehdr) + 4 + 2*domainlen + 2*srvlen;
- *blob_allocsz = blobsize;
- blobhdr = kmem_zalloc(blobsize, KM_SLEEP);
- blob = (uchar_t *)blobhdr;
- blobhdr->header = htolel(0x00000101);
- gethrestime(&now);
- smb_time_local2NT(&now, 0, &timestamp);
- blobhdr->timestamp = htoleq(timestamp);
- blobhdr->client_nonce = client_nonce;
- blobnames = blob + sizeof (struct ntlmv2_blobhdr);
- blobnames = add_name_to_blob(blobnames, vcp, (uchar_t *)vcp->vc_domain,
- domainlen, NAMETYPE_DOMAIN_NB, 1);
- blobnames = add_name_to_blob(blobnames, vcp, (uchar_t *)vcp->vc_srvname,
- srvlen, NAMETYPE_MACHINE_NB, 1);
- blobnames = add_name_to_blob(blobnames, vcp, NULL, 0, NAMETYPE_EOL, 0);
- diff = (intptr_t)blobnames - (intptr_t)blob;
- ASSERT(diff == (ptrdiff_t)((size_t)diff));
- *bloblen = (size_t)diff;
- return (blob);
-}
-
/*
- * When not doing Kerberos, we can try, in order:
- *
- * NTLMv2
- * NTLM (and maybe LM)
- *
- * if the server supports encrypted passwords, or
- *
- * plain-text with the ASCII password not upper-cased
- * plain-text with the ASCII password upper-cased
- *
- * if it doesn't.
+ * Moved to user space helper:
+ * smb_smb_negotiate()
+ * smb_smb_ssnsetup()
+ * smb_smb_ssnclose()
+ * smb_share_typename()
*/
-typedef enum {
- ClearUC, /* Cleartext p/w, upper case */
- ClearMC, /* Cleartext p/w, mixed case */
- NTLMv1,
- NTLMv2,
- ExtSec, /* Extended Security (Kerberos) */
- NullSes /* Null session (keep last) */
-} authtype_t;
+
int
-smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
+smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
{
- struct smb_rq *rqp;
+ struct smb_vc *vcp;
+ struct smb_rq *rqp = NULL;
struct mbchain *mbp;
struct mdchain *mdp;
- u_int8_t wc;
- int minauth;
- smb_uniptr unipp = NULL, ntencpass = NULL;
- char *pp = NULL, *up = NULL, *ucup = NULL;
- char *ucdp = vcp->vc_domain; /* already upper case */
- char *encpass = NULL;
- int error = 0;
- size_t plen = 0, plen_alloc = 0;
- size_t uniplen = 0, uniplen_alloc = 0;
- size_t ucup_sl = 0;
- authtype_t authtype;
- size_t ntlmv2_bloblen, ntlmv2_blob_allocsz;
- uchar_t *ntlmv2_blob;
- u_int64_t client_nonce;
- u_int32_t caps;
- u_int16_t bl; /* BLOB length */
- u_int16_t bc; /* byte count */
- u_int16_t action;
- u_int16_t rpflags2;
- int declinedguest = 0;
- uchar_t v2hash[16];
- static const char NativeOS[] = "Solaris";
- static const char LanMan[] = "NETSMB";
- /*
- * Most of the "capability" bits we offer should be copied
- * from those offered by the server, with a mask applied.
- * This is the mask of capabilies copied from the server.
- * Some others get special handling below.
- */
- static const uint32_t caps_mask =
- SMB_CAP_UNICODE |
- SMB_CAP_LARGE_FILES |
- SMB_CAP_NT_SMBS |
- SMB_CAP_STATUS32;
+ char *pbuf, *unc_name = NULL;
+ int error, tlen, plen, unc_len;
+ uint16_t bcnt, options;
+ uint8_t wc;
- caps = vcp->vc_sopt.sv_caps & caps_mask;
- minauth = vcp->vc_vopt & SMBVOPT_MINAUTH;
+ vcp = SSTOVC(ssp);
/*
- * This function tries authentication types in a
- * sequence going stronger to weaker, until it
- * succeeds or runs into "minauth" and fails.
- *
- * Extended security is a special case because
- * fall-back requires a return to user-level and
- * a new connection, new SMB negotiate, etc.
- * Null session is also special - no fall-back.
+ * Make this a "VC-level" request, so it will have
+ * rqp->sr_share == NULL, and smb_iod_sendrq()
+ * will send it with TID = SMB_TID_UNKNOWN
*
- * Otherwise if the server supports encryption,
- * try NTLMv2, then NTLM, etc.
- */
- if (vcp->vc_intok)
- authtype = ExtSec;
- else if (vcp->vc_username[0] == '\0')
- authtype = NullSes;
- else if ((vcp->vc_sopt.sv_sm & SMB_SM_USER) == 0) {
- /* Share-level security. */
- authtype = NullSes;
- } else {
- /* Have SMB_SM_USER. Encryption? */
- if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
- if (nsmb_enable_ntlmv2)
- authtype = NTLMv2;
- else
- authtype = NTLMv1;
- } else {
- /*
- * This is normally disallowed
- * by the minauth check below.
- */
- authtype = ClearMC;
- }
- }
-
- /*
- * If server does not support encryption,
- * disable unicode too. (Spec. for this?)
- */
- if ((vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) == 0) {
- if (vcp->vc_flags & SMBV_UNICODE) {
- vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
- vcp->vc_toserver = 0;
- }
- }
-
-again:
- SMBSDEBUG("authtype = %d\n", authtype);
-
- /*
- * Now disallow auth. types that fall below
- * the minimum strength configured.
- * We hold no kmem here.
- */
- switch (minauth) {
-
- case SMBVOPT_MINAUTH_NONE:
- break;
-
- case SMBVOPT_MINAUTH_LM:
- case SMBVOPT_MINAUTH_NTLM:
- if (authtype < NTLMv1) {
- error = EAUTH;
- goto ssn_exit;
- }
- break;
-
- case SMBVOPT_MINAUTH_NTLMV2:
- if (authtype < NTLMv2) {
- error = EAUTH;
- goto ssn_exit;
- }
- break;
-
- case SMBVOPT_MINAUTH_KERBEROS:
- if (authtype < ExtSec) {
- error = EAUTH;
- goto ssn_exit;
- }
- break;
-
- default:
- SMBSDEBUG("bad minauth 0x%x\n", minauth);
- error = EAUTH;
- goto ssn_exit;
- }
-
- /*
- * See comment in smb_iod_sendrq()
- * about vc_smbuid initialization.
- */
- vcp->vc_smbuid = SMB_UID_UNKNOWN;
-
- /*
- * Within this switch, we may allocate either or both:
- * encpass, ntencpass (len: plen_alloc, uniplen_alloc)
- * and will free these below (see the label "bad")
+ * This also serves to bypass the wait for
+ * share state changes, which this call is
+ * trying to carry out.
*/
- switch (authtype) {
-
- case ExtSec:
- /*
- * With extended security, the whole blob is
- * passed in from user-level (vc_intok)
- */
- ASSERT(vcp->vc_intok != NULL);
- caps |= SMB_CAP_EXT_SECURITY;
- /* XXX Need Session Key */
- if (vcp->vc_intoklen > 65536 ||
- !(vcp->vc_hflags2 & SMB_FLAGS2_EXT_SEC) ||
- SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) {
- /* We hold no kmem here. */
- error = EINVAL;
- goto ssn_exit;
- }
- vcp->vc_smbuid = 0;
- break;
-
- case NullSes:
- pp = "";
- plen = 1;
- unipp = &smb_unieol;
- uniplen = sizeof (smb_unieol);
- break;
-
- case NTLMv2:
- /*
- * Compute the LMv2 and NTLMv2 responses,
- * derived from the challenge, the user name,
- * the domain/workgroup into which we're
- * logging, and the Unicode password.
- */
-
- /*
- * Construct the client nonce by getting
- * a bunch of random data.
- */
- (void) random_get_pseudo_bytes((void *)
- &client_nonce, sizeof (client_nonce));
-
- /*
- * Convert the user name to upper-case, as
- * that's what's used when computing LMv2
- * and NTLMv2 responses.
- */
- ucup_sl = strlen(vcp->vc_username);
- ucup = kmem_alloc(ucup_sl + 1, KM_SLEEP);
- smb_toupper((const char *)vcp->vc_username,
- ucup, ucup_sl);
- ucup[ucup_sl] = '\0';
-
- /*
- * Compute the NTLMv2 hash, which is
- * derived from the NTLMv1 hash and
- * the upper-case user + domain.
- */
- smb_ntlmv2hash(vcp->vc_nthash,
- ucup, ucdp, v2hash);
-
- /*
- * Compute the LMv2 response, derived from
- * the v2hash, the server challenge, and
- * the client nonce (random bits).
- * Note: kmem_alloc encpass (plen)
- */
- smb_ntlmv2response(v2hash,
- vcp->vc_challenge,
- (uchar_t *)&client_nonce, 8,
- (uchar_t **)&encpass, &plen);
- plen_alloc = plen;
- pp = encpass;
-
- /*
- * Construct the blob.
- * Note: kmem_alloc ntlmv2_blob
- */
- ntlmv2_blob = make_ntlmv2_blob(vcp,
- client_nonce, &ntlmv2_bloblen,
- &ntlmv2_blob_allocsz);
-
- /*
- * Compute the NTLMv2 response, derived
- * from the server challenge, the
- * user name, the domain/workgroup
- * into which we're logging, the
- * blob, and the v2 hash.
- * Note: kmem_alloc ntencpass (uniplen)
- */
- smb_ntlmv2response(v2hash,
- vcp->vc_challenge,
- ntlmv2_blob, ntlmv2_bloblen,
- (uchar_t **)&ntencpass, &uniplen);
- uniplen_alloc = uniplen;
- unipp = ntencpass;
-
- /*
- * If we negotiated signing, compute the MAC key
- * and start signing messages, but only on the
- * first non-null session login.
- */
- if ((vcp->vc_flags & SMBV_WILL_SIGN) &&
- !(vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)) {
- vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
- smb_calcv2mackey(vcp, v2hash,
- (uchar_t *)ntencpass, uniplen);
- }
- kmem_free(ucup, ucup_sl + 1);
- kmem_free(ntlmv2_blob, ntlmv2_blob_allocsz);
- break;
-
- case NTLMv1:
- /*
- * Compute the LM response, derived
- * from the challenge and the ASCII
- * password. (If minauth allows it.)
- */
- plen_alloc = plen = 24;
- encpass = kmem_zalloc(plen, KM_SLEEP);
- if (minauth < SMBVOPT_MINAUTH_NTLM) {
- smb_lmresponse(vcp->vc_lmhash,
- vcp->vc_challenge,
- (uchar_t *)encpass);
- }
- pp = encpass;
-
- /*
- * Compute the NTLM response, derived from
- * the challenge and the NT hash.
- */
- uniplen_alloc = uniplen = 24;
- ntencpass = kmem_alloc(uniplen, KM_SLEEP);
- smb_lmresponse(vcp->vc_nthash,
- vcp->vc_challenge,
- (uchar_t *)ntencpass);
- unipp = ntencpass;
-
- /*
- * If we negotiated signing, compute the MAC key
- * and start signing messages, but only on the
- * first non-null session login.
- */
- if ((vcp->vc_flags & SMBV_WILL_SIGN) &&
- !(vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)) {
- vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
- smb_calcmackey(vcp, vcp->vc_nthash,
- (uchar_t *)ntencpass, uniplen);
- }
- break;
-
- case ClearMC:
- case ClearUC:
- /*
- * We try w/o uppercasing first so Samba mixed case
- * passwords work. If that fails, we come back and
- * try uppercasing to satisfy OS/2 and Windows for
- * Workgroups.
- */
- plen_alloc = plen = SMB_MAXPASSWORDLEN + 1;
- encpass = kmem_zalloc(plen, KM_SLEEP);
- get_ascii_password(vcp, (authtype == ClearUC), encpass);
- plen = strlen(encpass) + 1;
- pp = encpass;
- uniplen_alloc = uniplen = plen * 2;
- ntencpass = kmem_alloc(uniplen, KM_SLEEP);
- (void) smb_strtouni(ntencpass, smb_vc_getpass(vcp), 0, 0);
- plen--;
- /*
- * The uniplen is zeroed because Samba cannot deal
- * with this 2nd cleartext password. This Samba
- * "bug" is actually a workaround for problems in
- * Microsoft clients.
- */
- uniplen = 0; /* -= 2 */
- unipp = ntencpass;
- break;
-
- default:
- ASSERT(0);
- error = EAUTH;
- goto ssn_exit;
-
- } /* switch authtype */
-
-
- error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX,
+ error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_CONNECT_ANDX,
scred, &rqp);
if (error)
- goto bad;
-
- /*
- * Build the request.
- */
- smb_rq_wstart(rqp);
- mbp = &rqp->sr_rq;
- up = vcp->vc_username;
- /*
- * If userid is null we are attempting anonymous browse login
- * so passwords must be zero length.
- */
- if (*up == '\0') {
- plen = uniplen = 0;
- }
- mb_put_uint8(mbp, 0xff);
- mb_put_uint8(mbp, 0);
- mb_put_uint16le(mbp, 0);
- mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx);
- mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux);
- mb_put_uint16le(mbp, vcp->vc_number);
- mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey);
- if ((SMB_DIALECT(vcp)) < SMB_DIALECT_NTLM0_12) {
- mb_put_uint16le(mbp, plen);
- mb_put_uint32le(mbp, 0);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
- smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* user */
- smb_put_dstring(mbp, vcp, ucdp, SMB_CS_NONE); /* domain */
- } else {
- if (vcp->vc_intok) {
- mb_put_uint16le(mbp, vcp->vc_intoklen);
- mb_put_uint32le(mbp, 0); /* reserved */
- mb_put_uint32le(mbp, caps); /* my caps */
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_mem(mbp, vcp->vc_intok, vcp->vc_intoklen,
- MB_MSYSTEM); /* security blob */
- } else {
- mb_put_uint16le(mbp, plen);
- mb_put_uint16le(mbp, uniplen);
- mb_put_uint32le(mbp, 0); /* reserved */
- mb_put_uint32le(mbp, caps); /* my caps */
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_mem(mbp, pp, plen, MB_MSYSTEM); /* password */
- mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM);
- smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* user */
- smb_put_dstring(mbp, vcp, ucdp, SMB_CS_NONE); /* dom */
- }
- }
- smb_put_dstring(mbp, vcp, NativeOS, SMB_CS_NONE); /* OS */
- smb_put_dstring(mbp, vcp, LanMan, SMB_CS_NONE); /* LAN Mgr */
- smb_rq_bend(rqp);
-
- /*
- * This request should not wait for
- * connection state changes, etc.
- */
- rqp->sr_flags |= SMBR_INTERNAL;
- error = smb_rq_simple_timed(rqp, SMBSSNSETUPTIMO);
- SMBSDEBUG("%d\n", error);
- if (error) {
- if (rqp->sr_errclass == ERRDOS &&
- rqp->sr_serror == ERRnoaccess)
- error = EAUTH;
- if (!(rqp->sr_errclass == ERRDOS &&
- rqp->sr_serror == ERRmoredata))
- goto bad;
- }
-
- /*
- * Parse the reply
- */
- rpflags2 = rqp->sr_rpflags2;
- vcp->vc_smbuid = rqp->sr_rpuid;
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto bad;
- error = EBADRPC;
- if (vcp->vc_intok) {
- if (wc != 4)
- goto bad;
- } else if (wc != 3)
- goto bad;
- md_get_uint8(mdp, NULL); /* secondary cmd */
- md_get_uint8(mdp, NULL); /* mbz */
- md_get_uint16le(mdp, NULL); /* andxoffset */
- md_get_uint16le(mdp, &action); /* action */
- if (vcp->vc_intok)
- md_get_uint16le(mdp, &bl); /* ext security */
- md_get_uint16le(mdp, &bc); /* byte count */
- if (vcp->vc_intok) {
- vcp->vc_outtoklen = bl;
- vcp->vc_outtok = kmem_alloc(bl, KM_SLEEP);
- error = md_get_mem(mdp, vcp->vc_outtok, bl, MB_MSYSTEM);
- if (error)
- goto bad;
- }
+ return (error);
/*
- * Server OS, LANMGR, & Domain follow here.
- * XXX: Should store these strings (later).
- *
- * Windows systems do not suport CAP_LARGE_...
- * when signing is enabled, so adjust sv_caps.
- * Match first 8 characters of server's OS
- * with the UCS-2LE string: "Windows "
+ * Build the UNC name, i.e. "//server/share"
+ * but with backslashes of course.
+ * size math: three slashes, one null.
*/
- if (bc > 16) {
- static const char WindowsU[16] =
- "W\0i\0n\0d\0o\0w\0s\0 ";
- char osbuf[16];
-
- /* align(2) */
- if (((uintptr_t)mdp->md_pos) & 1)
- md_get_uint8(mdp, NULL);
-
- bzero(osbuf, sizeof (osbuf));
- md_get_mem(mdp, osbuf, sizeof (osbuf), MB_MSYSTEM);
- if (0 == bcmp(WindowsU, osbuf, sizeof (osbuf))) {
- SMBSDEBUG("Server is Windows\n");
- if (vcp->vc_flags & SMBV_WILL_SIGN) {
- SMBSDEBUG("disable CAP_LARGE_(r/w)\n");
- vcp->vc_sopt.sv_caps &=
- ~(SMB_CAP_LARGE_READX
- | SMB_CAP_LARGE_WRITEX);
- }
- }
- }
-
- /* success! */
- error = 0;
-
-bad:
+ unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name);
+ unc_name = kmem_alloc(unc_len, KM_SLEEP);
+ snprintf(unc_name, unc_len, "\\\\%s\\%s",
+ vcp->vc_srvname, ssp->ss_name);
/*
- * When authentication fails and we're (possibly) doing
- * fall-back to another method, we have to reset things.
+ * The password is now pre-computed in the
+ * user-space helper process.
*/
- if (error && vcp->vc_mackey) {
- vcp->vc_hflags2 &= ~SMB_FLAGS2_SECURITY_SIGNATURE;
- kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
- vcp->vc_mackey = NULL;
- vcp->vc_mackeylen = 0;
- vcp->vc_seqno = 0;
- }
-
- if (rqp) {
- smb_rq_done(rqp);
- rqp = NULL;
- }
- if (encpass) {
- kmem_free(encpass, plen_alloc);
- encpass = NULL;
- }
- if (ntencpass) {
- kmem_free(ntencpass, uniplen_alloc);
- ntencpass = NULL;
- }
+ plen = ssp->ss_pwlen;
+ pbuf = ssp->ss_pass;
/*
- * Shall we try again with another auth type?
- * Note: We hold no kmem here.
+ * Build the request.
*/
- switch (authtype) {
-
- case NullSes:
- case ExtSec:
- /* Error or not, we're done. (no fallback) */
- break;
-
- case NTLMv2:
- /*
- * We're doing user-level authentication (so we are actually
- * sending authentication stuff over the wire), and we're
- * not doing extended security, and the stuff we tried
- * failed (or we we're trying to login a real user but
- * got granted guest access instead.)
- *
- * See radar 4134676. This check works around the way a
- * certain old server grants limited Guest access when we
- * try NTLMv2, but works fine with NTLM. The fingerprint
- * we are looking for is DOS error codes and no-Unicode.
- * Note XP grants Guest access but uses Unicode and
- * NT error codes.
- */
- if (error == 0 && (action & SMB_ACT_GUEST) &&
- !(rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
- !(rpflags2 & SMB_FLAGS2_UNICODE)) {
- /* force fallback */
- declinedguest = 1;
- error = EAUTH;
- }
- /* FALLTHROUGH */
- case NTLMv1:
- case ClearMC:
- if (error) {
- authtype = authtype - 1;
- goto again;
- }
- break;
-
- case ClearUC:
- default:
- /* no more fallbacks */
- break;
- }
-
-ssn_exit:
- if (error && declinedguest)
- SMBERROR("we declined ntlmv2 guest access. errno will be %d\n",
- error);
-
- return (error);
-}
-
-int
-smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred)
-{
- struct smb_rq *rqp;
- struct mbchain *mbp;
- int error;
-
- if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
- return (0);
-
- error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
- if (error)
- return (error);
mbp = &rqp->sr_rq;
smb_rq_wstart(rqp);
mb_put_uint8(mbp, 0xff);
mb_put_uint8(mbp, 0);
mb_put_uint16le(mbp, 0);
+ mb_put_uint16le(mbp, 0); /* Flags */
+ mb_put_uint16le(mbp, plen);
smb_rq_wend(rqp);
smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- /*
- * Run this with a relatively short timeout.
- * We don't really care about the result,
- * as we're just trying to play nice and
- * "say goodbye" before we hangup.
- * XXX: Add SMBLOGOFFTIMO somewhere?
- */
- error = smb_rq_simple_timed(rqp, 5);
- SMBSDEBUG("%d\n", error);
- smb_rq_done(rqp);
- return (error);
-}
-
-static char smb_any_share[] = "?????";
-
-static char *
-smb_share_typename(int stype)
-{
- char *pp;
-
- switch (stype) {
- case STYPE_DISKTREE:
- pp = "A:";
- break;
- case STYPE_PRINTQ:
- pp = smb_any_share; /* can't use LPT: here... */
- break;
- case STYPE_DEVICE:
- pp = "COMM";
- break;
- case STYPE_IPC:
- pp = "IPC";
- break;
- default:
- pp = smb_any_share;
- break;
- }
- return (pp);
-}
-int
-smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
-{
- struct smb_vc *vcp;
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- char *pp, *pbuf, *encpass;
- const char *pw;
- uchar_t hash[SMB_PWH_MAX];
- int error, plen, caseopt;
- int upper = 0;
+ /* Tree connect password, if any */
+ error = mb_put_mem(mbp, pbuf, plen, MB_MSYSTEM);
+ if (error)
+ goto out;
-again:
- vcp = SSTOVC(ssp);
+ /* UNC resource name */
+ error = smb_put_dstring(mbp, vcp, unc_name, SMB_CS_NONE);
+ if (error)
+ goto out;
/*
- * Make this a "VC-level" request, so it will have
- * rqp->sr_share == NULL, and smb_iod_sendrq()
- * will send it with TID = SMB_TID_UNKNOWN
- *
- * This also serves to bypass the wait for
- * share state changes, which this call is
- * trying to carry out.
- *
- * No longer need to set ssp->ss_tid
- * here, but it's harmless enough.
+ * Put the type string (always ASCII),
+ * including the null.
*/
- ssp->ss_tid = SMB_TID_UNKNOWN;
- error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_CONNECT_ANDX,
- scred, &rqp);
+ tlen = strlen(ssp->ss_type_req) + 1;
+ error = mb_put_mem(mbp, ssp->ss_type_req, tlen, MB_MSYSTEM);
if (error)
- return (error);
- caseopt = SMB_CS_NONE;
- if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
- plen = 1;
- pp = "";
- pbuf = NULL;
- encpass = NULL;
- } else {
- pbuf = kmem_alloc(SMB_MAXPASSWORDLEN + 1, KM_SLEEP);
- encpass = kmem_alloc(24, KM_SLEEP);
- pw = smb_share_getpass(ssp);
- /*
- * We try w/o uppercasing first so Samba mixed case
- * passwords work. If that fails we come back and try
- * uppercasing to satisfy OS/2 and Windows for Workgroups.
- */
- if (upper++) {
- smb_toupper(pw, pbuf, SMB_MAXPASSWORDLEN);
- smb_oldlm_hash(pw, hash);
- } else {
- strncpy(pbuf, pw, SMB_MAXPASSWORDLEN);
- smb_ntlmv1hash(pw, hash);
- }
- pbuf[SMB_MAXPASSWORDLEN] = '\0';
+ goto out;
-#ifdef NOICONVSUPPORT
- /*
- * We need to convert here to the server codeset.
- * Initially we will send the same stuff and see what happens
- * witout the conversion. REVISIT.
- */
- iconv_convstr(vcp->vc_toserver, pbuf, pbuf, SMB_MAXPASSWORDLEN);
-#endif
- if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
- plen = 24;
- smb_lmresponse(hash,
- vcp->vc_challenge,
- (uchar_t *)encpass);
- pp = encpass;
- } else {
- plen = strlen(pbuf) + 1;
- pp = pbuf;
- }
- }
- mbp = &rqp->sr_rq;
- smb_rq_wstart(rqp);
- mb_put_uint8(mbp, 0xff);
- mb_put_uint8(mbp, 0);
- mb_put_uint16le(mbp, 0);
- mb_put_uint16le(mbp, 0); /* Flags */
- mb_put_uint16le(mbp, plen);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- error = mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
- if (error) {
- SMBSDEBUG("error %d from mb_put_mem for pp\n", error);
- goto bad;
- }
- smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt, NULL);
- pp = vcp->vc_srvname;
- error = smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt, NULL);
- if (error) {
- SMBSDEBUG("error %d from smb_put_dmem for srvname\n", error);
- goto bad;
- }
- smb_put_dmem(mbp, vcp, "\\", 1, caseopt, NULL);
- pp = ssp->ss_name;
- error = smb_put_dstring(mbp, vcp, pp, caseopt);
- if (error) {
- SMBSDEBUG("error %d from smb_put_dstring for ss_name\n", error);
- goto bad;
- }
- /* The type name is always ASCII */
- pp = smb_share_typename(ssp->ss_type);
- error = mb_put_mem(mbp, pp, strlen(pp) + 1, MB_MSYSTEM);
- if (error) {
- SMBSDEBUG("error %d from mb_put_mem for ss_type\n", error);
- goto bad;
- }
smb_rq_bend(rqp);
+
/*
- * Don't want to risk missing a successful
- * tree connect response.
+ * Run the request.
+ *
+ * Using NOINTR_RECV because we don't want to risk
+ * missing a successful tree connect response,
+ * which would "leak" Tree IDs.
*/
rqp->sr_flags |= SMBR_NOINTR_RECV;
error = smb_rq_simple(rqp);
SMBSDEBUG("%d\n", error);
if (error)
- goto bad;
+ goto out;
+
+ /*
+ * Parse the TCON response
+ */
+ smb_rq_getreply(rqp, &mdp);
+ md_get_uint8(mdp, &wc);
+ if (wc != 3) {
+ error = EBADRPC;
+ goto out;
+ }
+ md_get_uint16le(mdp, NULL); /* AndX cmd */
+ md_get_uint16le(mdp, NULL); /* AndX off */
+ md_get_uint16le(mdp, &options); /* option bits (DFS, search) */
+ md_get_uint16le(mdp, &bcnt); /* byte count */
+
+ /*
+ * Get the returned share type string,
+ * i.e. "IPC" or whatever.
+ */
+ tlen = sizeof (ssp->ss_type_ret);
+ bzero(ssp->ss_type_ret, tlen--);
+ if (tlen > bcnt)
+ tlen = bcnt;
+ md_get_mem(mdp, ssp->ss_type_ret, tlen, MB_MSYSTEM);
/* Success! */
SMB_SS_LOCK(ssp);
ssp->ss_tid = rqp->sr_rptid;
ssp->ss_vcgenid = vcp->vc_genid;
+ ssp->ss_options = options;
ssp->ss_flags |= SMBS_CONNECTED;
SMB_SS_UNLOCK(ssp);
-bad:
- if (encpass)
- kmem_free(encpass, 24);
- if (pbuf)
- kmem_free(pbuf, SMB_MAXPASSWORDLEN + 1);
+out:
+ if (unc_name)
+ kmem_free(unc_name, unc_len);
smb_rq_done(rqp);
- if (error && upper == 1)
- goto again;
return (error);
}
@@ -1525,7 +309,6 @@ smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
{
struct smb_vc *vcp;
struct smb_rq *rqp;
- struct mbchain *mbp;
int error;
if (ssp->ss_tid == SMB_TID_UNKNOWN)
@@ -1543,10 +326,7 @@ smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
if (error)
return (error);
rqp->sr_share = ssp; /* by hand */
- mbp = &rqp->sr_rq;
-#ifdef lint
- mbp = mbp;
-#endif
+
smb_rq_wstart(rqp);
smb_rq_wend(rqp);
smb_rq_bstart(rqp);
@@ -1559,8 +339,9 @@ smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
* "leak" active tree IDs on interrupt or timeout.
* The NOINTR_SEND flag makes this request immune to
* interrupt or timeout until the send is done.
+ * Also, don't reconnect for this, of course!
*/
- rqp->sr_flags |= SMBR_NOINTR_SEND;
+ rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
error = smb_rq_simple_timed(rqp, 5);
SMBSDEBUG("%d\n", error);
smb_rq_done(rqp);
@@ -1632,10 +413,6 @@ smb_rwuio(struct smb_share *ssp, uint16_t fid, uio_rw_t rw,
while (uiop->uio_resid > 0) {
/* Lint: uio_resid may be 64-bits */
rlen = len = (uint32_t)min(maxlen, uiop->uio_resid);
-
- SMBSDEBUG("rw=%d, off %lld, len %d\n",
- rw, uiop->uio_loffset, len);
-
error = (*iofun)(ssp, fid, &rlen, uiop, scred, timo);
/*
@@ -1688,7 +465,7 @@ smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
mb_put_uint8(mbp, 0xff); /* no secondary command */
mb_put_uint8(mbp, 0); /* MBZ */
mb_put_uint16le(mbp, 0); /* offset to secondary */
- mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
+ mb_put_uint16le(mbp, fid);
mb_put_uint32le(mbp, offlo); /* offset (low part) */
mb_put_uint16le(mbp, lenlo); /* MaxCount */
mb_put_uint16le(mbp, 1); /* MinCount */
@@ -1775,7 +552,7 @@ smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
mb_put_uint8(mbp, 0xff); /* no secondary command */
mb_put_uint8(mbp, 0); /* MBZ */
mb_put_uint16le(mbp, 0); /* offset to secondary */
- mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
+ mb_put_uint16le(mbp, fid);
mb_put_uint32le(mbp, offlo); /* offset (low part) */
mb_put_uint32le(mbp, 0); /* MBZ (timeout) */
mb_put_uint16le(mbp, 0); /* !write-thru */
@@ -1842,7 +619,7 @@ smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
return (error);
smb_rq_getrequest(rqp, &mbp);
smb_rq_wstart(rqp);
- mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
+ mb_put_uint16le(mbp, fid);
mb_put_uint16le(mbp, cnt);
mb_put_uint32le(mbp, off32);
mb_put_uint16le(mbp, todo);
@@ -1915,7 +692,7 @@ smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
return (error);
smb_rq_getrequest(rqp, &mbp);
smb_rq_wstart(rqp);
- mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
+ mb_put_uint16le(mbp, fid);
mb_put_uint16le(mbp, cnt);
mb_put_uint32le(mbp, off32);
mb_put_uint16le(mbp, todo);
@@ -1972,44 +749,9 @@ smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
* this request must not wait for
* connection state changes, etc.
*/
- rqp->sr_flags |= SMBR_INTERNAL;
+ rqp->sr_flags |= SMBR_NORECONNECT;
error = smb_rq_simple_timed(rqp, timo);
SMBSDEBUG("%d\n", error);
smb_rq_done(rqp);
return (error);
}
-
-#ifdef APPLE
-int
-smb_smb_checkdir(struct smb_share *ssp, void *dnp, char *name,
- int nmlen, struct smb_cred *scred)
-{
- struct smb_rq *rqp;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CHECK_DIRECTORY, scred, &rqp);
- if (error)
- return (error);
-
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- /*
- * All we need to do is marshall the path: "\\"
- * (the root of the share) into this request.
- * We essentially in-line smbfs_fullpath() here,
- * except no mb_put_padbyte (already aligned).
- */
- smb_put_dstring(mbp, SSTOVC(ssp), "\\", SMB_CS_NONE);
- smb_rq_bend(rqp);
-
- error = smb_rq_simple(rqp);
- SMBSDEBUG("%d\n", error);
- smb_rq_done(rqp);
-
- return (error);
-}
-#endif /* APPLE */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
index 2ed6272a87..3edf4c4d9d 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -75,16 +75,6 @@ void m_dumpm(mblk_t *m);
#endif /* DEBUG or lint */
-#define SMB_SIGMASK \
- (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGKILL)| \
- sigmask(SIGHUP)|sigmask(SIGQUIT))
-
-#define SMB_STRFREE(p) do { \
- if (p) \
- smb_strfree(p); \
- _NOTE(CONSTCOND) \
-} while (0)
-
typedef uint16_t smb_unichar;
typedef smb_unichar *smb_uniptr;
@@ -106,20 +96,8 @@ extern int smb_timo_append;
#define EMOREDATA (0x7fff)
-#ifdef APPLE
-void smb_scred_init(struct smb_cred *scred, vfs_context_t vfsctx);
-int smb_sigintr(vfs_context_t);
-#endif
-void smb_credinit(struct smb_cred *scred, struct proc *p, cred_t *cr);
+void smb_credinit(struct smb_cred *scred, cred_t *cr);
void smb_credrele(struct smb_cred *scred);
-char *smb_strdup(const char *s);
-void *smb_memdup(const void *umem, int len);
-char *smb_strdupin(char *s, int maxlen);
-void *smb_memdupin(void *umem, int len);
-size_t smb_strtouni(uint16_t *dst, const char *src, size_t inlen, int flags);
-void smb_strfree(char *s);
-void smb_memfree(void *s);
-void *smb_zmalloc(unsigned long size);
void smb_oldlm_hash(const char *apwd, uchar_t *hash);
void smb_ntlmv1hash(const char *apwd, uchar_t *hash);
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
index 79eba6d6ba..98963b5583 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
@@ -32,7 +32,10 @@
* $Id: smb_subr.c,v 1.27.108.1 2005/06/02 00:55:39 lindak Exp $
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
#include <sys/param.h>
#include <sys/systm.h>
@@ -90,150 +93,27 @@ smb_toupper(const char *inbuf, char *outbuf, size_t outlen)
}
void
-smb_credinit(struct smb_cred *scred, struct proc *p, cred_t *icr)
+smb_credinit(struct smb_cred *scred, cred_t *cr)
{
- scred->vc_pid = p->p_pidp->pid_id;
- if (!icr)
- icr = p->p_cred;
+ /* cr arg is optional */
+ if (cr == NULL)
+ cr = ddi_get_cred();
if (is_system_labeled()) {
- icr = crdup(icr);
- (void) setpflags(NET_MAC_AWARE, 1, icr);
+ cr = crdup(cr);
+ (void) setpflags(NET_MAC_AWARE, 1, cr);
} else {
- crhold(icr);
+ crhold(cr);
}
- scred->vc_ucred = icr;
+ scred->scr_cred = cr;
}
void
smb_credrele(struct smb_cred *scred)
{
- crfree(scred->vc_ucred);
- scred->vc_ucred = NULL;
-}
-
-#ifdef APPLE
-/*ARGSUSED*/
-int
-smb_sigintr(vfs_context_t vfsctx)
-{
- /*
- * I cannot find something to match vfs_context_issignal.
- * It calls proc_pendingsignals() in Darwin code.
- */
- if (vfsctx && vfs_context_issignal(vfsctx, SMB_SIGMASK))
- return (EINTR);
- return (0);
-}
-#endif
-
-char *
-smb_strdup(const char *s)
-{
- char *p;
- int len;
-
- len = s ? strlen(s) + 1 : 1;
- p = kmem_alloc(len, KM_SLEEP);
- if (s)
- bcopy(s, p, len);
- else
- *p = 0;
- return (p);
-}
-
-/*
- * duplicate string from a user space.
- */
-char *
-smb_strdupin(char *s, int maxlen)
-{
- char *p, bt;
- int len = 0;
-
- for (p = s; ; p++) {
- if (copyin(p, &bt, 1))
- return (NULL);
- len++;
- if (maxlen && len > maxlen)
- return (NULL);
- if (bt == 0)
- break;
- }
- p = kmem_alloc(len, KM_SLEEP);
- copyin(s, p, len);
- return (p);
-}
-
-/*
- * duplicate memory block from a user space.
- */
-void *
-smb_memdupin(void *umem, int len)
-{
- char *p;
-
- if (len > 32 * 1024)
- return (NULL);
- p = kmem_alloc(len, KM_SLEEP);
- if (copyin(umem, p, len) == 0)
- return (p);
- kmem_free(p, len);
- return (NULL);
-}
-
-/*
- * duplicate memory block in the kernel space.
- */
-void *
-smb_memdup(const void *umem, int len)
-{
- char *p;
-
- if (len > 32 * 1024)
- return (NULL);
- p = kmem_alloc(len, KM_SLEEP);
- if (p == NULL)
- return (NULL);
- bcopy(umem, p, len);
- return (p);
-}
-
-void
-smb_strfree(char *s)
-{
- kmem_free(s, strlen(s) + 1);
-}
-
-void
-smb_memfree(void *s)
-{
- kmem_free(s, strlen(s));
-}
-
-void *
-smb_zmalloc(unsigned long size)
-{
- void *p = kmem_zalloc(size, KM_SLEEP);
- return (p);
-}
-
-size_t
-smb_strtouni(u_int16_t *dst, const char *src, size_t inlen, int flags)
-{
- size_t outlen = 0;
-
- if (!inlen)
- inlen = strlen(src);
-
- /* Force output format to little-endian. */
- flags &= ~UCONV_OUT_BIG_ENDIAN;
- flags |= UCONV_OUT_LITTLE_ENDIAN;
-
- outlen = inlen * 2;
- if (uconv_u8tou16((uchar_t *)src, &inlen, dst, &outlen, flags) != 0) {
- outlen = 0;
+ if (scred->scr_cred != NULL) {
+ crfree(scred->scr_cred);
+ scred->scr_cred = NULL;
}
- return (outlen * 2);
}
/*
@@ -290,7 +170,6 @@ m_dumpm(mblk_t *m)
}
#endif
-/* all these need review XXX */
#ifndef EPROTO
#define EPROTO ECONNABORTED
#endif
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
index d82e3d862b..052759f333 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
@@ -32,11 +32,14 @@
* $Id: smb_tran.h,v 1.2 2001/12/21 02:41:30 conrad Exp $
*/
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
#ifndef _NETSMB_SMB_TRAN_H_
#define _NETSMB_SMB_TRAN_H_
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/socket.h>
/*
@@ -50,43 +53,36 @@
#define SMBTP_SNDSZ 1 /* R - int */
#define SMBTP_RCVSZ 2 /* R - int */
#define SMBTP_TIMEOUT 3 /* RW - struct timespec */
-#ifndef __sun
-#define SMBTP_SELECTID 4 /* RW - (void *) */
-#define SMBTP_UPCALL 5 /* RW - (* void)(void *) */
-#endif
struct smb_tran_ops;
struct smb_tran_desc {
sa_family_t tr_type;
- int (*tr_create)(struct smb_vc *vcp, struct proc *p);
- int (*tr_done)(struct smb_vc *vcp, struct proc *p);
- int (*tr_bind)(struct smb_vc *vcp, struct sockaddr *sap,
- struct proc *p);
- int (*tr_connect)(struct smb_vc *vcp, struct sockaddr *sap,
- struct proc *p);
- int (*tr_disconnect)(struct smb_vc *vcp, struct proc *p);
- int (*tr_send)(struct smb_vc *vcp, mblk_t *m0, struct proc *p);
- int (*tr_recv)(struct smb_vc *vcp, mblk_t **mpp, struct proc *p);
- int (*tr_poll)(struct smb_vc *vcp, int ticks, struct proc *p);
+ int (*tr_create)(struct smb_vc *vcp, cred_t *cr);
+ int (*tr_done)(struct smb_vc *vcp);
+ int (*tr_bind)(struct smb_vc *vcp, struct sockaddr *sap);
+ int (*tr_connect)(struct smb_vc *vcp, struct sockaddr *sap);
+ int (*tr_disconnect)(struct smb_vc *vcp);
+ int (*tr_send)(struct smb_vc *vcp, mblk_t *m);
+ int (*tr_recv)(struct smb_vc *vcp, mblk_t **mpp);
+ int (*tr_poll)(struct smb_vc *vcp, int ticks);
+ int (*tr_loan_fp)(struct smb_vc *, struct file *, cred_t *cr);
int (*tr_getparam)(struct smb_vc *vcp, int param, void *data);
int (*tr_setparam)(struct smb_vc *vcp, int param, void *data);
int (*tr_fatal)(struct smb_vc *vcp, int error);
-#ifdef notyet
- int (*tr_cmpaddr)(void *addr1, void *addr2);
-#endif
LIST_ENTRY(smb_tran_desc) tr_link;
};
typedef struct smb_tran_desc smb_tran_desc_t;
-#define SMB_TRAN_CREATE(vcp, p) (vcp)->vc_tdesc->tr_create(vcp, p)
-#define SMB_TRAN_DONE(vcp, p) (vcp)->vc_tdesc->tr_done(vcp, p)
-#define SMB_TRAN_BIND(vcp, sap, p) (vcp)->vc_tdesc->tr_bind(vcp, sap, p)
-#define SMB_TRAN_CONNECT(vcp, sap, p) (vcp)->vc_tdesc->tr_connect(vcp, sap, p)
-#define SMB_TRAN_DISCONNECT(vcp, p) (vcp)->vc_tdesc->tr_disconnect(vcp, p)
-#define SMB_TRAN_SEND(vcp, m0, p) (vcp)->vc_tdesc->tr_send(vcp, m0, p)
-#define SMB_TRAN_RECV(vcp, m, p) (vcp)->vc_tdesc->tr_recv(vcp, m, p)
-#define SMB_TRAN_POLL(vcp, t, p) (vcp)->vc_tdesc->tr_poll(vcp, t, p)
+#define SMB_TRAN_CREATE(vcp, cr) (vcp)->vc_tdesc->tr_create(vcp, cr)
+#define SMB_TRAN_DONE(vcp) (vcp)->vc_tdesc->tr_done(vcp)
+#define SMB_TRAN_BIND(vcp, sap) (vcp)->vc_tdesc->tr_bind(vcp, sap)
+#define SMB_TRAN_CONNECT(vcp, sap) (vcp)->vc_tdesc->tr_connect(vcp, sap)
+#define SMB_TRAN_DISCONNECT(vcp) (vcp)->vc_tdesc->tr_disconnect(vcp)
+#define SMB_TRAN_SEND(vcp, m) (vcp)->vc_tdesc->tr_send(vcp, m)
+#define SMB_TRAN_RECV(vcp, m) (vcp)->vc_tdesc->tr_recv(vcp, m)
+#define SMB_TRAN_POLL(vcp, t) (vcp)->vc_tdesc->tr_poll(vcp, t)
+#define SMB_TRAN_LOAN_FP(vcp, f, cr) (vcp)->vc_tdesc->tr_loan_fp(vcp, f, cr)
#define SMB_TRAN_GETPARAM(vcp, par, data) \
(vcp)->vc_tdesc->tr_getparam(vcp, par, data)
#define SMB_TRAN_SETPARAM(vcp, par, data) \
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
index d3036a7c98..1cd73649c4 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
@@ -84,123 +84,12 @@
static int smb_tcpsndbuf = 0x20000;
static int smb_tcprcvbuf = 0x20000;
-static dev_t smb_tcp_dev;
-
static int nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
- uint8_t *rpcodep, struct proc *p);
+ uint8_t *rpcodep);
static int nb_disconnect(struct nbpcb *nbp);
/*
- * Internal set sockopt for int-sized options.
- * Is there a common Solaris function for this?
- * Code from uts/common/rpc/clnt_cots.c
- */
-static int
-nb_setsockopt_int(TIUSER *tiptr, int level, int name, int val)
-{
- int fmode;
- mblk_t *mp;
- struct opthdr *opt;
- struct T_optmgmt_req *tor;
- struct T_optmgmt_ack *toa;
- int *valp;
- int error, mlen;
-
- mlen = (sizeof (struct T_optmgmt_req) +
- sizeof (struct opthdr) + sizeof (int));
- if (!(mp = allocb_cred_wait(mlen, STR_NOSIG, &error, CRED(), NOPID)))
- return (error);
-
- mp->b_datap->db_type = M_PROTO;
- /*LINTED*/
- tor = (struct T_optmgmt_req *)mp->b_wptr;
- tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
- tor->MGMT_flags = T_NEGOTIATE;
- tor->OPT_length = sizeof (struct opthdr) + sizeof (int);
- tor->OPT_offset = sizeof (struct T_optmgmt_req);
- mp->b_wptr += sizeof (struct T_optmgmt_req);
-
- /*LINTED*/
- opt = (struct opthdr *)mp->b_wptr;
- opt->level = level;
- opt->name = name;
- opt->len = sizeof (int);
- mp->b_wptr += sizeof (struct opthdr);
-
- /* LINTED */
- valp = (int *)mp->b_wptr;
- *valp = val;
- mp->b_wptr += sizeof (int);
-
- fmode = tiptr->fp->f_flag;
- if ((error = tli_send(tiptr, mp, fmode)) != 0)
- return (error);
-
- /*
- * Wait for T_OPTMGMT_ACK
- */
- mp = NULL;
- fmode = 0; /* need to block */
- if ((error = tli_recv(tiptr, &mp, fmode)) != 0)
- return (error);
- /*LINTED*/
- toa = (struct T_optmgmt_ack *)mp->b_rptr;
- if (toa->PRIM_type != T_OPTMGMT_ACK)
- error = EPROTO;
- freemsg(mp);
-
- return (error);
-}
-
-static void
-nb_setopts(struct nbpcb *nbp)
-{
- int error;
- TIUSER *tiptr = NULL;
-
- tiptr = nbp->nbp_tiptr;
- if (tiptr == NULL) {
- NBDEBUG("no tiptr!\n");
- return;
- }
-
- /*
- * Set various socket/TCP options.
- * Failures here are not fatal -
- * just log a complaint.
- *
- * We don't need these two:
- * SO_RCVTIMEO, SO_SNDTIMEO
- */
-
- error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_SNDBUF,
- nbp->nbp_sndbuf);
- if (error)
- NBDEBUG("can't set SO_SNDBUF");
-
- error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_RCVBUF,
- nbp->nbp_rcvbuf);
- if (error)
- NBDEBUG("can't set SO_RCVBUF");
-
- error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_KEEPALIVE, 1);
- if (error)
- NBDEBUG("can't set SO_KEEPALIVE");
-
- error = nb_setsockopt_int(tiptr, IPPROTO_TCP, TCP_NODELAY, 1);
- if (error)
- NBDEBUG("can't set TCP_NODELAY");
-
- /* Set the connect timeout (in milliseconds). */
- error = nb_setsockopt_int(tiptr, IPPROTO_TCP,
- TCP_CONN_ABORT_THRESHOLD,
- nbp->nbp_timo.tv_sec * 1000);
- if (error)
- NBDEBUG("can't set connect timeout");
-}
-
-/*
* Get mblks into *mpp until the data length is at least mlen.
* Note that *mpp may already contain a fragment.
*
@@ -342,12 +231,14 @@ discon:
static int
nb_snddis(TIUSER *tiptr)
{
+ cred_t *cr;
mblk_t *mp;
struct T_discon_req *dreq;
int error, fmode, mlen;
+ cr = ddi_get_cred();
mlen = sizeof (struct T_discon_req);
- if (!(mp = allocb_cred_wait(mlen, STR_NOSIG, &error, CRED(), NOPID)))
+ if (!(mp = allocb_cred_wait(mlen, STR_NOSIG, &error, cr, NOPID)))
return (error);
mp->b_datap->db_type = M_PROTO;
@@ -367,14 +258,6 @@ nb_snddis(TIUSER *tiptr)
return (error);
}
-#ifdef APPLE
-static int
-nb_intr(struct nbpcb *nbp, struct proc *p)
-{
- return (0);
-}
-#endif
-
/*
* Stuff the NetBIOS header into space already prepended.
*/
@@ -393,211 +276,6 @@ nb_sethdr(mblk_t *m, uint8_t type, uint32_t len)
}
/*
- * Note: Moved name encoding into here.
- */
-static int
-nb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb)
-{
- int i, len;
- uchar_t ch, *p;
-
- /*
- * Do the NetBIOS "first-level encoding" here.
- * (RFC1002 explains this wierdness...)
- * See similar code in smbfs library:
- * lib/libsmbfs/smb/nb_name.c
- *
- * Here is what we marshall:
- * uint8_t NAME_LENGTH (always 32)
- * uint8_t ENCODED_NAME[32]
- * uint8_t SCOPE_LENGTH
- * XXX Scope should follow here, then another null,
- * if and when we support NetBIOS scopes.
- */
- len = 1 + (2 * NB_NAMELEN) + 1;
-
- p = mb_reserve(mbp, len);
- if (!p)
- return (ENOSR);
-
- /* NAME_LENGTH */
- *p++ = (2 * NB_NAMELEN);
-
- /* ENCODED_NAME */
- for (i = 0; i < NB_NAMELEN; i++) {
- ch = (uchar_t)snb->snb_name[i];
- *p++ = 'A' + ((ch >> 4) & 0xF);
- *p++ = 'A' + ((ch) & 0xF);
- }
-
- /* SCOPE_LENGTH */
- *p++ = 0;
-
- return (0);
-}
-
-static int
-nb_tcpopen(struct nbpcb *nbp, struct proc *p)
-{
- TIUSER *tiptr;
- int err, oflags = FREAD|FWRITE;
- cred_t *cr = p->p_cred;
-
- if (!smb_tcp_dev) {
- smb_tcp_dev = makedevice(
- clone_major, ddi_name_to_major("tcp"));
- }
-
- /*
- * This magic arranges for our network endpoint
- * to have the right "label" for operation in a
- * "trusted extensions" environment.
- */
- if (is_system_labeled()) {
- cr = crdup(cr);
- (void) setpflags(NET_MAC_AWARE, 1, cr);
- } else {
- crhold(cr);
- }
- err = t_kopen(NULL, smb_tcp_dev, oflags, &tiptr, cr);
- crfree(cr);
- if (err)
- return (err);
-
- /* Note: I_PUSH "timod" is done by t_kopen */
-
- /* Save the TPI handle we use everywhere. */
- nbp->nbp_tiptr = tiptr;
-
- /*
- * Internal ktli calls need the "fmode" flags
- * from the t_kopen call. XXX: Not sure if the
- * flags have the right bits set, or if we
- * always want the same block/non-block flags.
- * XXX: Look into this...
- */
- nbp->nbp_fmode = tiptr->fp->f_flag;
- return (0);
-}
-
-/*ARGSUSED*/
-static int
-nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct proc *p)
-{
- int error;
- TIUSER *tiptr = NULL;
- struct t_call call;
-
- tiptr = nbp->nbp_tiptr;
- if (tiptr == NULL)
- return (EBADF);
- if (nbp->nbp_flags & NBF_CONNECTED)
- return (EISCONN);
-
- /*
- * Setup (snd)call address (connect to).
- * Just pass NULL for the (rcv)call.
- */
- bzero(&call, sizeof (call));
- call.addr.len = sizeof (*to);
- call.addr.buf = (char *)to;
- /* call.opt - none */
- /* call.udata -- XXX: Should put NB session req here! */
-
- /* Send the connect, wait... */
- error = t_kconnect(tiptr, &call, NULL);
- if (error) {
- NBDEBUG("nb_connect_in: connect %d error", error);
- } else {
- mutex_enter(&nbp->nbp_lock);
- nbp->nbp_flags |= NBF_CONNECTED;
- mutex_exit(&nbp->nbp_lock);
- }
-
- return (error);
-}
-
-static int
-nbssn_rq_request(struct nbpcb *nbp, struct proc *p)
-{
- struct mbchain mb, *mbp = &mb;
- struct mdchain md, *mdp = &md;
- mblk_t *m0;
- struct sockaddr_in sin;
- ushort_t port;
- uint8_t rpcode;
- int error, rplen;
-
- error = mb_init(mbp);
- if (error)
- return (error);
-
- /*
- * Put a zero for the 4-byte NetBIOS header,
- * then let nb_sethdr() overwrite it.
- */
- mb_put_uint32le(mbp, 0);
- nb_put_name(mbp, nbp->nbp_paddr);
- nb_put_name(mbp, nbp->nbp_laddr);
- nb_sethdr(mbp->mb_top, NB_SSN_REQUEST, mb_fixhdr(mbp) - 4);
-
- m0 = mb_detach(mbp);
- error = tli_send(nbp->nbp_tiptr, m0, nbp->nbp_fmode);
- m0 = NULL; /* Note: _always_ consumed by tli_send */
- mb_done(mbp);
- if (error)
- return (error);
-
- nbp->nbp_state = NBST_RQSENT;
- error = nbssn_recv(nbp, &m0, &rplen, &rpcode, p);
- if (error == EWOULDBLOCK) { /* Timeout */
- NBDEBUG("initial request timeout\n");
- return (ETIMEDOUT);
- }
- if (error) {
- NBDEBUG("recv() error %d\n", error);
- return (error);
- }
- /*
- * Process NETBIOS reply
- */
- if (m0)
- md_initm(mdp, m0);
-
- error = 0;
- if (rpcode == NB_SSN_POSRESP) {
- mutex_enter(&nbp->nbp_lock);
- nbp->nbp_state = NBST_SESSION;
- mutex_exit(&nbp->nbp_lock);
- goto out;
- }
- if (rpcode != NB_SSN_RTGRESP) {
- error = ECONNABORTED;
- goto out;
- }
- if (rplen != 6) {
- error = ECONNABORTED;
- goto out;
- }
- md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM);
- md_get_uint16(mdp, &port);
- sin.sin_port = port;
- nbp->nbp_state = NBST_RETARGET;
- nb_disconnect(nbp);
- error = nb_connect_in(nbp, &sin, p);
- if (!error)
- error = nbssn_rq_request(nbp, p);
- if (error) {
- nb_disconnect(nbp);
- }
-
-out:
- if (m0)
- md_done(mdp);
- return (error);
-}
-
-/*
* Wait for up to 15 sec. for the next packet.
* Often return ETIME and do nothing else.
* When a packet header is available, check
@@ -648,7 +326,7 @@ nbssn_peekhdr(struct nbpcb *nbp, size_t *lenp, uint8_t *rpcodep)
return (EPIPE);
}
len &= 0x1ffff;
- if (len > SMB_MAXPKTLEN) {
+ if (len > NB_MAXPKTLEN) {
NBDEBUG("packet too long (%d)\n", len);
return (EFBIG);
}
@@ -667,7 +345,7 @@ nbssn_peekhdr(struct nbpcb *nbp, size_t *lenp, uint8_t *rpcodep)
/*ARGSUSED*/
static int
nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
- uint8_t *rpcodep, struct proc *p)
+ uint8_t *rpcodep)
{
TIUSER *tiptr = nbp->nbp_tiptr;
mblk_t *m0;
@@ -804,27 +482,14 @@ out:
/*
* SMB transport interface
*/
+/*ARGSUSED*/
static int
-smb_nbst_create(struct smb_vc *vcp, struct proc *p)
+smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
{
struct nbpcb *nbp;
- int error;
nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
- /*
- * We don't keep reference counts or otherwise
- * prevent nbp->nbp_tiptr from going away, so
- * do the TLI open here and keep it until the
- * last ref calls smb_nbst_done.
- * This does t_kopen (open endpoint)
- */
- error = nb_tcpopen(nbp, p);
- if (error) {
- kmem_free(nbp, sizeof (*nbp));
- return (error);
- }
-
nbp->nbp_timo.tv_sec = SMB_NBTIMO;
nbp->nbp_state = NBST_CLOSED; /* really IDLE */
nbp->nbp_vc = vcp;
@@ -833,14 +498,12 @@ smb_nbst_create(struct smb_vc *vcp, struct proc *p)
mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
vcp->vc_tdata = nbp;
- nb_setopts(nbp);
-
return (0);
}
/*ARGSUSED*/
static int
-smb_nbst_done(struct smb_vc *vcp, struct proc *p)
+smb_nbst_done(struct smb_vc *vcp)
{
struct nbpcb *nbp = vcp->vc_tdata;
@@ -856,7 +519,7 @@ smb_nbst_done(struct smb_vc *vcp, struct proc *p)
if (nbp->nbp_flags & NBF_CONNECTED)
nb_disconnect(nbp);
if (nbp->nbp_tiptr)
- t_kclose(nbp->nbp_tiptr, 1);
+ t_kclose(nbp->nbp_tiptr, 0);
if (nbp->nbp_laddr)
smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr);
if (nbp->nbp_paddr)
@@ -866,144 +529,58 @@ smb_nbst_done(struct smb_vc *vcp, struct proc *p)
return (0);
}
-/*ARGSUSED*/
static int
-smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
+smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr)
{
struct nbpcb *nbp = vcp->vc_tdata;
- struct sockaddr_nb *snb;
+ TIUSER *tiptr;
int error = 0;
- if (nbp->nbp_tiptr == NULL)
- return (EBADF);
-
- /*
- * Allow repeated bind calls on one endpoint.
- * This happens with reconnect.
- */
+ mutex_enter(&nbp->nbp_lock);
/*
- * Null name is an "anonymous" (NULL) bind request.
- * (Let the transport pick a local name.)
- * This transport does not support NULL bind,
- * because we require a local NetBIOS name.
+ * Un-loan the existing one, if any.
*/
- if (sap == NULL)
- return (EINVAL);
-
- /*LINTED*/
- snb = (struct sockaddr_nb *)smb_dup_sockaddr(sap);
- if (snb == NULL)
- return (ENOMEM);
-
- mutex_enter(&nbp->nbp_lock);
- if (nbp->nbp_laddr)
- smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr);
- nbp->nbp_laddr = snb;
+ if (nbp->nbp_tiptr != NULL) {
+ t_kclose(nbp->nbp_tiptr, 0);
+ nbp->nbp_tiptr = NULL;
+ nbp->nbp_flags &= ~NBF_CONNECTED;
+ nbp->nbp_state = NBST_CLOSED;
+ }
/*
- * Do local TCP bind with NULL (any address),
- * but just once (for multiple connect attempts)
- * or extra bind calls would cause errors.
+ * Loan the new one passed in.
*/
- if ((nbp->nbp_flags & NBF_LOCADDR) == 0) {
- error = t_kbind(nbp->nbp_tiptr, NULL, NULL);
- if (error) {
- NBDEBUG("t_kbind failed");
- } else {
- nbp->nbp_flags |= NBF_LOCADDR;
- }
+ if (fp != NULL && 0 == (error =
+ t_kopen(fp, 0, 0, &tiptr, cr))) {
+ nbp->nbp_tiptr = tiptr;
+ nbp->nbp_fmode = tiptr->fp->f_flag;
+ nbp->nbp_flags |= NBF_CONNECTED;
+ nbp->nbp_state = NBST_SESSION;
}
+
mutex_exit(&nbp->nbp_lock);
return (error);
}
+/*ARGSUSED*/
static int
-smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
+smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
{
- struct nbpcb *nbp = vcp->vc_tdata;
- struct sockaddr_in sin;
- struct sockaddr_nb *snb;
- int error;
-
- if (nbp->nbp_tiptr == NULL)
- return (EBADF);
- if (nbp->nbp_laddr == NULL)
- return (EINVAL);
-
- /*
- * Note: nbssn_rq_request() will call nbssn_recv(),
- * so set the RECVLOCK flag here. Otherwise we'll
- * hit an ASSERT for this flag in nbssn_recv().
- */
- mutex_enter(&nbp->nbp_lock);
- if (nbp->nbp_flags & NBF_RECVLOCK) {
- NBDEBUG("attempt to reenter session layer!\n");
- mutex_exit(&nbp->nbp_lock);
- return (EWOULDBLOCK);
- }
- nbp->nbp_flags |= NBF_RECVLOCK;
- mutex_exit(&nbp->nbp_lock);
-
- /*LINTED*/
- snb = (struct sockaddr_nb *)smb_dup_sockaddr(sap);
- if (snb == NULL) {
- error = ENOMEM;
- goto out;
- }
- if (nbp->nbp_paddr)
- smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr);
- nbp->nbp_paddr = snb;
-
- /*
- * Setup the remote IP address.
- * Try plain TCP first (port 445).
- */
- bzero(&sin, sizeof (sin));
- sin.sin_family = AF_INET;
- sin.sin_port = htons(IPPORT_SMB); /* port 445 */
- sin.sin_addr.s_addr = snb->snb_ipaddr;
-
-again:
- NBDEBUG("trying port %d\n", ntohs(sin.sin_port));
- error = nb_connect_in(nbp, &sin, p);
- switch (error) {
- case 0:
- break;
- case ECONNREFUSED:
- if (sin.sin_port != htons(IPPORT_NETBIOS_SSN)) {
- /* Try again w/ NetBIOS (port 139) */
- sin.sin_port = htons(IPPORT_NETBIOS_SSN);
- goto again;
- }
- /* FALLTHROUGH */
- default:
- goto out;
- }
-
- /*
- * If we connected via NetBIOS (port 139),
- * need to do a session request.
- */
- if (sin.sin_port == htons(IPPORT_NETBIOS_SSN)) {
- error = nbssn_rq_request(nbp, p);
- if (error)
- nb_disconnect(nbp);
- } else
- nbp->nbp_state = NBST_SESSION;
-
-out:
- mutex_enter(&nbp->nbp_lock);
- nbp->nbp_flags &= ~NBF_RECVLOCK;
- mutex_exit(&nbp->nbp_lock);
+ return (ENOTSUP);
+}
- return (error);
+/*ARGSUSED*/
+static int
+smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
+{
+ return (ENOTSUP);
}
/*ARGSUSED*/
static int
-smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p)
+smb_nbst_disconnect(struct smb_vc *vcp)
{
struct nbpcb *nbp = vcp->vc_tdata;
@@ -1036,7 +613,7 @@ nb_disconnect(struct nbpcb *nbp)
nb_snddis(tiptr);
if (nbp->nbp_state != NBST_RETARGET) {
- nbp->nbp_state = NBST_CLOSED; /* really IDLE */
+ nbp->nbp_state = NBST_CLOSED;
}
return (0);
}
@@ -1047,7 +624,7 @@ nb_disconnect(struct nbpcb *nbp)
*/
/*ARGSUSED*/
static int
-smb_nbst_send(struct smb_vc *vcp, mblk_t *m, struct proc *p)
+smb_nbst_send(struct smb_vc *vcp, mblk_t *m)
{
struct nbpcb *nbp = vcp->vc_tdata;
ptrdiff_t diff;
@@ -1080,6 +657,10 @@ smb_nbst_send(struct smb_vc *vcp, mblk_t *m, struct proc *p)
* some network drivers will apparently send
* each mblk in the chain as separate frames.
* (That's arguably a driver bug.)
+ *
+ * Not bothering with allocb_cred_wait below
+ * because the message we're prepending to
+ * should already have a db_credp.
*/
diff = MBLKHEAD(m);
@@ -1110,9 +691,8 @@ errout:
return (error);
}
-
static int
-smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp, struct proc *p)
+smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp)
{
struct nbpcb *nbp = vcp->vc_tdata;
uint8_t rpcode;
@@ -1126,7 +706,7 @@ smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp, struct proc *p)
}
nbp->nbp_flags |= NBF_RECVLOCK;
mutex_exit(&nbp->nbp_lock);
- error = nbssn_recv(nbp, mpp, &rplen, &rpcode, p);
+ error = nbssn_recv(nbp, mpp, &rplen, &rpcode);
mutex_enter(&nbp->nbp_lock);
nbp->nbp_flags &= ~NBF_RECVLOCK;
mutex_exit(&nbp->nbp_lock);
@@ -1140,7 +720,7 @@ smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp, struct proc *p)
*/
/*ARGSUSED*/
static int
-smb_nbst_poll(struct smb_vc *vcp, int ticks, struct proc *p)
+smb_nbst_poll(struct smb_vc *vcp, int ticks)
{
int error;
int events = 0;
@@ -1220,6 +800,7 @@ struct smb_tran_desc smb_tran_nbtcp_desc = {
smb_nbst_send,
smb_nbst_recv,
smb_nbst_poll,
+ smb_nbst_loan_fp,
smb_nbst_getparam,
smb_nbst_setparam,
smb_nbst_fatal,
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
index 3dffae55c8..19ef7bdc97 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -44,7 +44,9 @@
#include <sys/conf.h>
#include <sys/proc.h>
#include <sys/fcntl.h>
+#include <sys/file.h>
#include <sys/socket.h>
+#include <sys/sunddi.h>
#include <sys/cmn_err.h>
#include <netsmb/smb_osdep.h>
@@ -55,483 +57,758 @@
#include <netsmb/smb_subr.h>
#include <netsmb/smb_dev.h>
+static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg);
+
/*
- * helpers for nsmb device. Can be moved to the smb_dev.c file.
+ * Ioctl function for SMBIOC_FLAGS2
*/
-static void smb_usr_vcspec_free(struct smb_vcspec *spec);
+int
+smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags)
+{
+ struct smb_vc *vcp = NULL;
+
+ /* This ioctl requires a session. */
+ if ((vcp = sdp->sd_vc) == NULL)
+ return (ENOTCONN);
+
+ /*
+ * Return the flags2 value.
+ */
+ if (ddi_copyout(&vcp->vc_hflags2, (void *)arg,
+ sizeof (u_int16_t), flags))
+ return (EFAULT);
+
+ return (0);
+}
/*
- * Moved the access checks here, just becuase
- * this was a more convenient place to do it
- * than in every function calling this.
+ * Ioctl function for SMBIOC_GETSSNKEY
+ * Size copied out is SMBIOC_HASH_SZ.
+ *
+ * The RPC library needs this for encrypting things
+ * like "set password" requests. This is called
+ * with an active RPC binding, so the connection
+ * will already be active (but this checks).
*/
-static int
-smb_usr_ioc2vcspec(struct smbioc_ossn *dp, struct smb_vcspec *spec)
+int
+smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
{
- cred_t *cr = CRED();
- uid_t realuid;
+ struct smb_vc *vcp = NULL;
+
+ /* This ioctl requires an active session. */
+ if ((vcp = sdp->sd_vc) == NULL)
+ return (ENOTCONN);
+ if (vcp->vc_state != SMBIOD_ST_VCACTIVE)
+ return (ENOTCONN);
/*
- * Only superuser can specify a UID or GID.
+ * Return the session key.
*/
- realuid = crgetruid(cr);
- if (dp->ioc_owner == SMBM_ANY_OWNER)
- spec->owner = realuid;
- else {
- /*
- * Do we have the privilege to create with the
- * specified uid? (does uid == cr->cr_uid, etc.)
- * MacOS would want suser(), or similar here.
- */
- if (secpolicy_vnode_owner(cr, dp->ioc_owner))
- return (EPERM);
- spec->owner = dp->ioc_owner;
- }
- if (dp->ioc_group == SMBM_ANY_GROUP)
- spec->group = crgetgid(cr);
- else {
- /*
- * Do we have the privilege to create with the
- * specified gid? (one of our groups?)
- */
- if (groupmember(dp->ioc_group, cr) ||
- secpolicy_vnode_create_gid(cr) == 0)
- spec->group = dp->ioc_group;
- else
- return (EPERM);
+ if (ddi_copyout(vcp->vc_ssn_key, (void *)arg,
+ SMBIOC_HASH_SZ, flags))
+ return (EFAULT);
+
+ return (0);
+}
+
+/*
+ * Ioctl function for SMBIOC_REQUEST
+ */
+int
+smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
+{
+ struct smb_cred scred;
+ struct smb_share *ssp;
+ smbioc_rq_t *ioc = NULL;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint32_t rsz;
+ int err, mbseg;
+
+ /* This ioctl requires a share. */
+ if ((ssp = sdp->sd_share) == NULL)
+ return (ENOTCONN);
+
+ smb_credinit(&scred, cr);
+ ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
+ if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
+ err = EFAULT;
+ goto out;
}
- /*
- * Valid codesets? XXX
- */
- if (dp->ioc_localcs[0] == 0) {
- spec->localcs = "ISO8859-1";
-#ifdef NOTYETRESOLVED
- SMBERROR("no local charset ? dp->ioc_localcs[0]: %d\n",
- dp->ioc_localcs[0]);
- return (EINVAL);
-#endif
- } else
- spec->localcs = spec->localcs;
+ /* See ddi_copyin, ddi_copyout */
+ mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
/*
- * Check for valid sa_family.
- * XXX: Just NetBIOS for now.
+ * Lots of SMB commands could be safe, but
+ * these are the only ones used by libsmbfs.
*/
- if (dp->ioc_server.sa.sa_family != AF_NETBIOS)
- return (EINVAL);
- spec->sap = &dp->ioc_server.sa;
-
- if (dp->ioc_local.sa.sa_family) {
- /* If specified, local AF must be the same. */
- if (dp->ioc_local.sa.sa_family !=
- dp->ioc_server.sa.sa_family)
- return (EINVAL);
- spec->lap = &dp->ioc_local.sa;
+ switch (ioc->ioc_cmd) {
+ /* These are OK */
+ case SMB_COM_CLOSE:
+ case SMB_COM_FLUSH:
+ case SMB_COM_NT_CREATE_ANDX:
+ case SMB_COM_OPEN_PRINT_FILE:
+ case SMB_COM_CLOSE_PRINT_FILE:
+ break;
+
+ default:
+ err = EPERM;
+ goto out;
}
- if (dp->ioc_intok) {
- spec->tok = smb_memdupin(dp->ioc_intok, dp->ioc_intoklen);
- if (spec->tok == NULL)
- return (EFAULT);
- spec->toklen = dp->ioc_intoklen;
+ err = smb_rq_alloc(SSTOCP(ssp), ioc->ioc_cmd, &scred, &rqp);
+ if (err)
+ goto out;
+
+ mbp = &rqp->sr_rq;
+ err = mb_put_mem(mbp, ioc->ioc_tbuf, ioc->ioc_tbufsz, mbseg);
+
+ err = smb_rq_simple(rqp);
+ if (err == 0) {
+ /*
+ * This may have been an open, so save the
+ * generation ID of the share, which we
+ * check before trying read or write.
+ */
+ sdp->sd_vcgenid = ssp->ss_vcgenid;
+
+ /*
+ * Have reply data. to copyout.
+ * SMB header already parsed.
+ */
+ mdp = &rqp->sr_rp;
+ rsz = msgdsize(mdp->md_top) - SMB_HDRLEN;
+ if (ioc->ioc_rbufsz < rsz) {
+ err = EOVERFLOW;
+ goto out;
+ }
+ ioc->ioc_rbufsz = rsz;
+ err = md_get_mem(mdp, ioc->ioc_rbuf, rsz, mbseg);
+ if (err)
+ goto out;
+
}
- spec->srvname = dp->ioc_srvname;
- spec->pass = dp->ioc_password;
- spec->domain = dp->ioc_workgroup;
- spec->username = dp->ioc_user;
- spec->mode = dp->ioc_mode;
- spec->rights = dp->ioc_rights;
- spec->servercs = dp->ioc_servercs;
- spec->optflags = dp->ioc_opt;
+ ioc->ioc_errclass = rqp->sr_errclass;
+ ioc->ioc_serror = rqp->sr_serror;
+ ioc->ioc_error = rqp->sr_error;
+ ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
- return (0);
-}
+out:
+ if (rqp != NULL)
+ smb_rq_done(rqp); /* free rqp */
+ if (ioc != NULL)
+ kmem_free(ioc, sizeof (*ioc));
+ smb_credrele(&scred);
+
+ return (err);
-static void
-smb_usr_shspec_free(struct smb_sharespec *sspec)
-{
- kmem_free(sspec, sizeof (struct smb_sharespec));
}
-static void
-smb_usr_vcspec_free(struct smb_vcspec *spec)
+/*
+ * Ioctl function for SMBIOC_T2RQ
+ */
+int
+smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
{
+ struct smb_cred scred;
+ struct smb_share *ssp;
+ smbioc_t2rq_t *ioc = NULL;
+ struct smb_t2rq *t2p = NULL;
+ struct mdchain *mdp;
+ int err, len, mbseg;
+
+ /* This ioctl requires a share. */
+ if ((ssp = sdp->sd_share) == NULL)
+ return (ENOTCONN);
- if (spec->tok) {
- kmem_free(spec->tok, spec->toklen);
+ smb_credinit(&scred, cr);
+ ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
+ if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
+ err = EFAULT;
+ goto out;
}
- kmem_free(spec, sizeof (*spec));
+
+ /* See ddi_copyin, ddi_copyout */
+ mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
+
+ if (ioc->ioc_setupcnt > SMBIOC_T2RQ_MAXSETUP) {
+ err = EINVAL;
+ goto out;
+ }
+
+ t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
+ err = smb_t2_init(t2p, SSTOCP(ssp),
+ ioc->ioc_setup, ioc->ioc_setupcnt, &scred);
+ if (err)
+ goto out;
+ len = t2p->t2_setupcount = ioc->ioc_setupcnt;
+ if (len > 1)
+ t2p->t2_setupdata = ioc->ioc_setup;
+
+ /* This ioc member is a fixed-size array. */
+ if (ioc->ioc_name[0]) {
+ /* Get the name length - carefully! */
+ ioc->ioc_name[SMBIOC_T2RQ_MAXNAME-1] = '\0';
+ t2p->t_name_len = strlen(ioc->ioc_name);
+ t2p->t_name = ioc->ioc_name;
+ }
+ t2p->t2_maxscount = 0;
+ t2p->t2_maxpcount = ioc->ioc_rparamcnt;
+ t2p->t2_maxdcount = ioc->ioc_rdatacnt;
+
+ /* Transmit parameters */
+ err = smb_cpdatain(&t2p->t2_tparam,
+ ioc->ioc_tparamcnt, ioc->ioc_tparam, mbseg);
+ if (err)
+ goto out;
+
+ /* Transmit data */
+ err = smb_cpdatain(&t2p->t2_tdata,
+ ioc->ioc_tdatacnt, ioc->ioc_tdata, mbseg);
+ if (err)
+ goto out;
+
+ err = smb_t2_request(t2p);
+
+ /* Copyout returned parameters. */
+ mdp = &t2p->t2_rparam;
+ if (err == 0 && mdp->md_top != NULL) {
+ /* User's buffer large enough? */
+ len = m_fixhdr(mdp->md_top);
+ if (len > ioc->ioc_rparamcnt) {
+ err = EMSGSIZE;
+ goto out;
+ }
+ ioc->ioc_rparamcnt = (ushort_t)len;
+ err = md_get_mem(mdp, ioc->ioc_rparam, len, mbseg);
+ if (err)
+ goto out;
+ } else
+ ioc->ioc_rparamcnt = 0;
+
+ /* Copyout returned data. */
+ mdp = &t2p->t2_rdata;
+ if (err == 0 && mdp->md_top != NULL) {
+ /* User's buffer large enough? */
+ len = m_fixhdr(mdp->md_top);
+ if (len > ioc->ioc_rdatacnt) {
+ err = EMSGSIZE;
+ goto out;
+ }
+ ioc->ioc_rdatacnt = (ushort_t)len;
+ err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg);
+ if (err)
+ goto out;
+ } else
+ ioc->ioc_rdatacnt = 0;
+
+ ioc->ioc_errclass = t2p->t2_sr_errclass;
+ ioc->ioc_serror = t2p->t2_sr_serror;
+ ioc->ioc_error = t2p->t2_sr_error;
+ ioc->ioc_rpflags2 = t2p->t2_sr_rpflags2;
+
+ ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
+
+
+out:
+ if (t2p != NULL) {
+ /* Note: t2p->t_name no longer allocated */
+ smb_t2_done(t2p);
+ kmem_free(t2p, sizeof (*t2p));
+ }
+ if (ioc != NULL)
+ kmem_free(ioc, sizeof (*ioc));
+ smb_credrele(&scred);
+
+ return (err);
}
+/* helper for _t2request */
static int
-smb_usr_ioc2sharespec(struct smbioc_oshare *dp, struct smb_sharespec *spec)
+smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg)
{
- bzero(spec, sizeof (*spec));
- spec->name = dp->ioc_share;
- spec->pass = dp->ioc_password;
- spec->mode = dp->ioc_mode;
- spec->rights = dp->ioc_rights;
- spec->owner = dp->ioc_owner;
- spec->group = dp->ioc_group;
- spec->stype = dp->ioc_stype;
- spec->optflags = dp->ioc_opt;
- return (0);
+ int error;
+
+ if (len == 0)
+ return (0);
+ error = mb_init(mbp);
+ if (error)
+ return (error);
+ return (mb_put_mem(mbp, data, len, mbseg));
}
+/*
+ * Helper for nsmb_ioctl cases
+ * SMBIOC_READ, SMBIOC_WRITE
+ */
int
-smb_usr_findvc(struct smbioc_lookup *dp, struct smb_cred *scred,
- struct smb_vc **vcpp)
+smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
{
- struct smb_vc *vcp = NULL;
- struct smb_vcspec *vspec = NULL;
- int error = 0;
+ struct smb_cred scred;
+ struct smb_share *ssp;
+ smbioc_rw_t *ioc = NULL;
+ struct iovec aiov[1];
+ struct uio auio;
+ u_int16_t fh;
+ int err;
+ uio_rw_t rw;
- if (dp->ioc_flags & SMBLK_CREATE)
- return (EINVAL);
- if (dp->ioc_level != SMBL_VC)
- return (EINVAL);
- vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP);
- error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec);
- if (error)
+ /* This ioctl requires a share. */
+ if ((ssp = sdp->sd_share) == NULL)
+ return (ENOTCONN);
+
+ /* After reconnect, force close+reopen */
+ if (sdp->sd_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
+ smb_credinit(&scred, cr);
+ ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
+ if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
+ err = EFAULT;
goto out;
- error = smb_sm_findvc(vspec, scred, &vcp);
- if (error == 0)
- *vcpp = vcp;
+ }
+
+ switch (cmd) {
+ case SMBIOC_READ:
+ rw = UIO_READ;
+ break;
+ case SMBIOC_WRITE:
+ rw = UIO_WRITE;
+ break;
+ default:
+ err = ENODEV;
+ goto out;
+ }
+
+ fh = ioc->ioc_fh;
+
+ aiov[0].iov_base = ioc->ioc_base;
+ aiov[0].iov_len = (size_t)ioc->ioc_cnt;
+
+ auio.uio_iov = aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_loffset = ioc->ioc_offset;
+ auio.uio_segflg = (flags & FKIOCTL) ?
+ UIO_SYSSPACE : UIO_USERSPACE;
+ auio.uio_fmode = 0;
+ auio.uio_resid = (size_t)ioc->ioc_cnt;
+
+ err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0);
+
+ /*
+ * On return ioc_cnt holds the
+ * number of bytes transferred.
+ */
+ ioc->ioc_cnt -= auio.uio_resid;
+
+ ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
+
out:
- smb_usr_vcspec_free(vspec);
- return (error);
+ if (ioc != NULL)
+ kmem_free(ioc, sizeof (*ioc));
+ smb_credrele(&scred);
+
+ return (err);
}
+/*
+ * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE
+ * Find or create a session (a.k.a. "VC" in here)
+ */
int
-smb_usr_negotiate(struct smbioc_lookup *dp, struct smb_cred *scred,
- struct smb_vc **vcpp)
+smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
{
+ struct smb_cred scred;
+ smbioc_ossn_t *ossn = NULL;
struct smb_vc *vcp = NULL;
- struct smb_vcspec *vspec = NULL;
- struct smb_sharespec *sspecp = NULL;
int error = 0;
+ uid_t realuid;
- if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
- return (EINVAL);
- vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP);
- error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec);
- if (error)
- return (error);
- if (dp->ioc_flags & SMBLK_CREATE)
- vspec->optflags |= SMBVOPT_CREATE;
- if (dp->ioc_level >= SMBL_SHARE) {
- sspecp = kmem_alloc(sizeof (*sspecp), KM_SLEEP);
- error = smb_usr_ioc2sharespec(&dp->ioc_sh, sspecp);
- if (error)
- goto out;
+ /* Should be no VC */
+ if (sdp->sd_vc != NULL)
+ return (EISCONN);
+
+ smb_credinit(&scred, cr);
+ ossn = kmem_alloc(sizeof (*ossn), KM_SLEEP);
+ if (ddi_copyin((void *)arg, ossn, sizeof (*ossn), flags)) {
+ error = EFAULT;
+ goto out;
}
- error = smb_sm_negotiate(vspec, scred, &vcp);
- if (error == 0) {
- *vcpp = vcp;
+
+ /*
+ * Only superuser can specify a UID or GID.
+ */
+ realuid = crgetruid(cr);
+ if (ossn->ssn_owner == SMBM_ANY_OWNER)
+ ossn->ssn_owner = realuid;
+ else {
/*
- * Used to copyout ioc_outtok, outtoklen here,
- * but that's now in smb_dev. (our caller)
- *
- * If this call asked for extended security and
- * the server does not support it, clear the
- * flag so the caller knows this.
- *
- * XXX: Should just add sv_caps to ioc_ssn,
- * set the new sv_caps field here, and let
- * let the copyout of ioc_ssn handle it.
+ * Do we have the privilege to create with the
+ * specified uid? (does uid == cr->cr_uid, etc.)
*/
- if (!(vcp->vc_sopt.sv_caps & SMB_CAP_EXT_SECURITY) &&
- (dp->ioc_ssn.ioc_opt & SMBVOPT_EXT_SEC)) {
- dp->ioc_ssn.ioc_opt &= ~SMBVOPT_EXT_SEC;
- SMBSDEBUG("turned off extended security");
+ if (secpolicy_vnode_owner(cr, ossn->ssn_owner)) {
+ error = EPERM;
+ goto out;
}
+ /* ossn->ssn_owner is OK */
}
-out:
- smb_usr_vcspec_free(vspec);
- smb_usr_shspec_free(sspecp);
- return (error);
-}
-int
-smb_usr_ssnsetup(struct smbioc_lookup *dp, struct smb_cred *scred,
- struct smb_vc *vcp)
-{
- struct smb_vcspec *vspec = NULL;
- int error;
+ /*
+ * Make sure the strings are null terminated.
+ */
+ ossn->ssn_srvname[SMBIOC_MAX_NAME-1] = '\0';
+ ossn->ssn_id.id_domain[ SMBIOC_MAX_NAME-1] = '\0';
+ ossn->ssn_id.id_user[ SMBIOC_MAX_NAME-1] = '\0';
- if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
- return (EINVAL);
+ if (cmd == SMBIOC_SSN_CREATE)
+ ossn->ssn_vopt |= SMBVOPT_CREATE;
+ else /* FIND */
+ ossn->ssn_vopt &= ~SMBVOPT_CREATE;
- vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP);
- error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec);
+ error = smb_vc_findcreate(ossn, &scred, &vcp);
if (error)
goto out;
+ ASSERT(vcp != NULL);
- error = smb_sm_ssnsetup(vspec, scred, vcp);
/*
- * Moved the copyout of ioc_outtok to
- * smb_dev.c (our caller)
+ * We have a VC, held, but not locked.
+ * If we're creating, mark this instance as
+ * an open from IOD so close can do cleanup.
+ *
+ * XXX: Would be nice to have a back pointer
+ * from the VC to this (IOD) sdp instance.
*/
+ if (cmd == SMBIOC_SSN_CREATE) {
+ if (vcp->iod_thr != NULL) {
+ error = EEXIST;
+ goto out;
+ }
+ sdp->sd_flags |= NSMBFL_IOD;
+ } else {
+ /*
+ * Wait for it to finish connecting
+ * (or reconnect) if necessary.
+ */
+ if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ error = smb_iod_reconnect(vcp);
+ if (error != 0)
+ goto out;
+ }
+ }
+
+ /*
+ * The VC has a hold from _findvc
+ * which we keep until _SSN_RELE
+ * or nsmb_close().
+ */
+ sdp->sd_level = SMBL_VC;
+ sdp->sd_vc = vcp;
+ vcp = NULL;
+ (void) ddi_copyout(ossn, (void *)arg, sizeof (*ossn), flags);
out:
- smb_usr_vcspec_free(vspec);
+ if (vcp) {
+ /* Error path: rele hold from _findcreate */
+ smb_vc_rele(vcp);
+ }
+ if (ossn != NULL)
+ kmem_free(ossn, sizeof (*ossn));
+ smb_credrele(&scred);
+
return (error);
}
-
+/*
+ * Ioctl functions: SMBIOC_SSN_RELE, SMBIOC_SSN_KILL
+ * Release or kill the current session.
+ */
int
-smb_usr_tcon(struct smbioc_lookup *dp, struct smb_cred *scred,
- struct smb_vc *vcp, struct smb_share **sspp)
+smb_usr_drop_ssn(smb_dev_t *sdp, int cmd)
{
- struct smb_sharespec *sspecp = NULL;
- int error;
+ struct smb_vc *vcp = NULL;
- if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
- return (EINVAL);
+ /* Must have a VC. */
+ if ((vcp = sdp->sd_vc) == NULL)
+ return (ENOTCONN);
- if (dp->ioc_level >= SMBL_SHARE) {
- sspecp = kmem_alloc(sizeof (*sspecp), KM_SLEEP);
- error = smb_usr_ioc2sharespec(&dp->ioc_sh, sspecp);
- if (error)
- goto out;
+ /* If we have a share ref, drop it too. */
+ if (sdp->sd_share) {
+ smb_share_rele(sdp->sd_share);
+ sdp->sd_share = NULL;
+ sdp->sd_level = SMBL_VC;
}
- error = smb_sm_tcon(sspecp, scred, vcp, sspp);
-out:
- if (sspecp)
- smb_usr_shspec_free(sspecp);
+ if (cmd == SMBIOC_SSN_KILL)
+ smb_vc_kill(vcp);
- return (error);
+ /* Drop the VC ref. */
+ smb_vc_rele(vcp);
+ sdp->sd_vc = NULL;
+ sdp->sd_level = 0;
+
+ return (0);
}
/*
- * Connect to the resource specified by smbioc_ossn structure.
- * It may either find an existing connection or try to establish a new one.
- * If no errors occured smb_vc returned locked and referenced.
+ * Find or create a tree (connected share)
*/
-
int
-smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp,
- struct smb_cred *scred)
+smb_usr_get_tree(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
{
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- struct mdchain *mdp;
- char *p;
- size_t wc2;
- u_int8_t wc;
- u_int16_t bc;
- int error;
+ struct smb_cred scred;
+ smbioc_tcon_t *tcon = NULL;
+ struct smb_vc *vcp = NULL;
+ struct smb_share *ssp = NULL;
+ int error = 0;
- switch (dp->ioc_cmd) {
- case SMB_COM_TRANSACTION2:
- case SMB_COM_TRANSACTION2_SECONDARY:
- case SMB_COM_CLOSE_AND_TREE_DISC:
- case SMB_COM_TREE_CONNECT:
- case SMB_COM_TREE_DISCONNECT:
- case SMB_COM_NEGOTIATE:
- case SMB_COM_SESSION_SETUP_ANDX:
- case SMB_COM_LOGOFF_ANDX:
- case SMB_COM_TREE_CONNECT_ANDX:
- return (EPERM);
+ /* Must have a VC. */
+ if ((vcp = sdp->sd_vc) == NULL)
+ return (ENOTCONN);
+ /* Should not have a share. */
+ if (sdp->sd_share != NULL)
+ return (EISCONN);
+
+ smb_credinit(&scred, cr);
+ tcon = kmem_alloc(sizeof (*tcon), KM_SLEEP);
+ if (ddi_copyin((void *)arg, tcon, sizeof (*tcon), flags)) {
+ error = EFAULT;
+ goto out;
}
- error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred);
- if (error)
- return (error);
- mbp = &rqp->sr_rq;
- smb_rq_wstart(rqp);
- error = mb_put_mem(mbp, dp->ioc_twords,
- dp->ioc_twc * 2, MB_MUSER);
- if (error)
- goto bad;
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- error = mb_put_mem(mbp, dp->ioc_tbytes,
- dp->ioc_tbc, MB_MUSER);
- if (error)
- goto bad;
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
+
+ /*
+ * Make sure the strings are null terminated.
+ */
+ tcon->tc_sh.sh_name[SMBIOC_MAX_NAME-1] = '\0';
+ tcon->tc_sh.sh_pass[SMBIOC_MAX_NAME-1] = '\0';
+ tcon->tc_sh.sh_type_req[SMBIOC_STYPE_LEN-1] = '\0';
+ bzero(tcon->tc_sh.sh_type_ret, SMBIOC_STYPE_LEN);
+
+ if (cmd == SMBIOC_TREE_CONNECT)
+ tcon->tc_opt |= SMBSOPT_CREATE;
+ else /* FIND */
+ tcon->tc_opt &= ~SMBSOPT_CREATE;
+
+ error = smb_share_findcreate(tcon, vcp, &ssp, &scred);
if (error)
- goto bad;
- mdp = &rqp->sr_rp;
- md_get_uint8(mdp, &wc);
- dp->ioc_rwc = wc;
- wc2 = wc * 2;
- if (wc2 > dp->ioc_rpbufsz) {
- error = EBADRPC;
- goto bad;
+ goto out;
+ ASSERT(ssp != NULL);
+
+ /*
+ * We have a share, held, but not locked.
+ * If we're creating, do tree connect now,
+ * otherwise let that wait for a request.
+ */
+ if (cmd == SMBIOC_TREE_CONNECT) {
+ error = smb_share_tcon(ssp, &scred);
+ if (error)
+ goto out;
}
- error = md_get_mem(mdp, dp->ioc_rpbuf, wc2, MB_MUSER);
- if (error)
- goto bad;
- md_get_uint16le(mdp, &bc);
- if ((wc2 + bc) > dp->ioc_rpbufsz) {
- error = EBADRPC;
- goto bad;
+
+ /*
+ * Give caller the real share type from
+ * the tree connect response, so they can
+ * see if they got the requested type.
+ */
+ memcpy(tcon->tc_sh.sh_type_ret,
+ ssp->ss_type_ret, SMBIOC_STYPE_LEN);
+
+ /*
+ * The share has a hold from _tcon
+ * which we keep until nsmb_close()
+ * or the SMBIOC_TDIS below.
+ */
+ sdp->sd_level = SMBL_SHARE;
+ sdp->sd_share = ssp;
+ ssp = NULL;
+ (void) ddi_copyout(tcon, (void *)arg, sizeof (*tcon), flags);
+
+out:
+ if (ssp) {
+ /* Error path: rele hold from _findcreate */
+ smb_share_rele(ssp);
}
- dp->ioc_rbc = bc;
- p = dp->ioc_rpbuf;
- error = md_get_mem(mdp, p + wc2, bc, MB_MUSER);
-bad:
- dp->ioc_errclass = rqp->sr_errclass;
- dp->ioc_serror = rqp->sr_serror;
- dp->ioc_error = rqp->sr_error;
- smb_rq_done(rqp);
- return (error);
+ if (tcon) {
+ /*
+ * This structure may contain a
+ * cleartext password, so zap it.
+ */
+ bzero(tcon, sizeof (*tcon));
+ kmem_free(tcon, sizeof (*tcon));
+ }
+ smb_credrele(&scred);
+ return (error);
}
-static int
-smb_cpdatain(struct mbchain *mbp, int len, char *data)
+/*
+ * Ioctl functions: SMBIOC_TREE_RELE, SMBIOC_TREE_KILL
+ * Release or kill the current tree
+ */
+int
+smb_usr_drop_tree(smb_dev_t *sdp, int cmd)
{
- int error;
+ struct smb_share *ssp = NULL;
- if (len == 0)
- return (0);
- error = mb_init(mbp);
- if (error)
- return (error);
- return (mb_put_mem(mbp, data, len, MB_MUSER));
+ /* Must have a VC and a share. */
+ if (sdp->sd_vc == NULL)
+ return (ENOTCONN);
+ if ((ssp = sdp->sd_share) == NULL)
+ return (ENOTCONN);
+
+ if (cmd == SMBIOC_TREE_KILL)
+ smb_share_kill(ssp);
+
+ /* Drop the share ref. */
+ smb_share_rele(sdp->sd_share);
+ sdp->sd_share = NULL;
+ sdp->sd_level = SMBL_VC;
+
+ return (0);
}
+
+/*
+ * Ioctl function: SMBIOC_IOD_WORK
+ *
+ * Become the reader (IOD) thread, until either the connection is
+ * reset by the server, or until the connection is idle longer than
+ * some max time. (max idle time not yet implemented)
+ */
int
-smb_usr_t2request(struct smb_share *ssp, smbioc_t2rq_t *dp,
- struct smb_cred *scred)
+smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
{
- struct smb_t2rq t2, *t2p = &t2;
- struct mdchain *mdp;
- int error, len;
+ struct smb_vc *vcp = NULL;
+ int err = 0;
- if (dp->ioc_setupcnt > SMB_MAXSETUPWORDS)
+ /* Must have a valid session. */
+ if ((vcp = sdp->sd_vc) == NULL)
return (EINVAL);
- error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup, dp->ioc_setupcnt,
- scred);
- if (error)
- return (error);
- len = t2p->t2_setupcount = dp->ioc_setupcnt;
- if (len > 1)
- t2p->t2_setupdata = dp->ioc_setup;
- /* This ioc member is a fixed-size array. */
- if (dp->ioc_name[0]) {
- t2p->t_name_maxlen = SMBIOC_T2RQ_MAXNAME;
- t2p->t_name = kmem_alloc(t2p->t_name_maxlen, KM_SLEEP);
- bcopy(dp->ioc_name, t2p->t_name, t2p->t_name_maxlen);
- /* Get the string length - carefully! */
- t2p->t_name[t2p->t_name_maxlen - 1] = '\0';
- t2p->t_name_len = strlen(t2p->t_name);
+ if (vcp->vc_flags & SMBV_GONE)
+ return (EINVAL);
+
+ /*
+ * Is there already an IOD for this VC?
+ * (Should never happen.)
+ */
+ SMB_VC_LOCK(vcp);
+ if (vcp->iod_thr == NULL)
+ vcp->iod_thr = curthread;
+ else
+ err = EEXIST;
+ SMB_VC_UNLOCK(vcp);
+ if (err)
+ return (err);
+
+ /*
+ * Copy the "work" state, etc. into the VC
+ * The MAC key is copied separately.
+ */
+ if (ddi_copyin((void *)arg, &vcp->vc_work,
+ sizeof (smbioc_ssn_work_t), flags)) {
+ err = EFAULT;
+ goto out;
}
- t2p->t2_maxscount = 0;
- t2p->t2_maxpcount = dp->ioc_rparamcnt;
- t2p->t2_maxdcount = dp->ioc_rdatacnt;
- error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt,
- dp->ioc_tparam);
- if (error)
- goto bad;
- error = smb_cpdatain(&t2p->t2_tdata,
- dp->ioc_tdatacnt, dp->ioc_tdata);
- if (error)
- goto bad;
- error = smb_t2_request(t2p);
- dp->ioc_errclass = t2p->t2_sr_errclass;
- dp->ioc_serror = t2p->t2_sr_serror;
- dp->ioc_error = t2p->t2_sr_error;
- dp->ioc_rpflags2 = t2p->t2_sr_rpflags2;
- if (error)
- goto bad;
- mdp = &t2p->t2_rparam;
- if (mdp->md_top) {
- mblk_t *m = mdp->md_top;
-#ifdef lint
- m = m;
-#endif
- len = m_fixhdr(mdp->md_top);
- if (len > dp->ioc_rparamcnt) {
- error = EMSGSIZE;
- goto bad;
- }
- dp->ioc_rparamcnt = (ushort_t)len;
- error = md_get_mem(mdp, dp->ioc_rparam,
- len, MB_MUSER);
- if (error) {
- goto bad;
- }
- } else
- dp->ioc_rparamcnt = 0;
- mdp = &t2p->t2_rdata;
- if (mdp->md_top) {
- mblk_t *m = mdp->md_top;
-#ifdef lint
- m = m;
-#endif
- len = m_fixhdr(mdp->md_top);
- if (len > dp->ioc_rdatacnt) {
- error = EMSGSIZE;
- goto bad;
- }
- dp->ioc_rdatacnt = (ushort_t)len;
- error = md_get_mem(mdp, dp->ioc_rdata,
- len, MB_MUSER);
- if (error) {
- goto bad;
+ if (vcp->vc_u_maclen) {
+ vcp->vc_mackeylen = vcp->vc_u_maclen;
+ vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP);
+ if (ddi_copyin(vcp->vc_u_mackey.lp_ptr, vcp->vc_mackey,
+ vcp->vc_mackeylen, flags)) {
+ err = EFAULT;
+ goto out;
}
- } else
- dp->ioc_rdatacnt = 0;
-bad:
- if (t2p->t_name) {
- kmem_free(t2p->t_name, t2p->t_name_maxlen);
- t2p->t_name = NULL;
}
- smb_t2_done(t2p);
- return (error);
+
+ err = smb_iod_vc_work(vcp, cr);
+
+ /* Caller wants state here. */
+ vcp->vc_work.wk_out_state = vcp->vc_state;
+
+ (void) ddi_copyout(&vcp->vc_work, (void *)arg,
+ sizeof (smbioc_ssn_work_t), flags);
+
+out:
+ if (vcp->vc_mackey) {
+ kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
+ vcp->vc_mackey = NULL;
+ vcp->vc_mackeylen = 0;
+ }
+
+ /*
+ * The IOD thread is leaving the driver. Clear iod_thr,
+ * and wake up anybody waiting for us to quit.
+ */
+ SMB_VC_LOCK(vcp);
+ vcp->iod_thr = NULL;
+ cv_broadcast(&vcp->vc_statechg);
+ SMB_VC_UNLOCK(vcp);
+
+ return (err);
}
/*
- * Helper for nsmb_ioctl cases
- * SMBIOC_READ, SMBIOC_WRITE
+ * Ioctl functions: SMBIOC_IOD_IDLE, SMBIOC_IOD_RCFAIL
+ *
+ * Wait for user-level requests to be enqueued on this session,
+ * and then return to the user-space helper, which will then
+ * initiate a reconnect, etc.
*/
int
-smb_usr_rw(struct smb_share *ssp, smbioc_rw_t *rwrq,
- int cmd, struct smb_cred *scred)
+smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags)
{
- struct iovec aiov[1];
- struct uio auio;
- u_int16_t fh;
- int error;
- uio_rw_t rw;
+ struct smb_vc *vcp = NULL;
+ int err = 0;
+
+ /* Must have a valid session. */
+ if ((vcp = sdp->sd_vc) == NULL)
+ return (EINVAL);
+ if (vcp->vc_flags & SMBV_GONE)
+ return (EINVAL);
+
+ /*
+ * Is there already an IOD for this VC?
+ * (Should never happen.)
+ */
+ SMB_VC_LOCK(vcp);
+ if (vcp->iod_thr == NULL)
+ vcp->iod_thr = curthread;
+ else
+ err = EEXIST;
+ SMB_VC_UNLOCK(vcp);
+ if (err)
+ return (err);
+
+ /* nothing to copyin */
switch (cmd) {
- case SMBIOC_READ:
- rw = UIO_READ;
+ case SMBIOC_IOD_IDLE:
+ err = smb_iod_vc_idle(vcp);
break;
- case SMBIOC_WRITE:
- rw = UIO_WRITE;
+
+ case SMBIOC_IOD_RCFAIL:
+ err = smb_iod_vc_rcfail(vcp);
break;
+
default:
- return (ENODEV);
+ err = ENOTTY;
+ goto out;
}
- fh = htoles(rwrq->ioc_fh);
-
- aiov[0].iov_base = rwrq->ioc_base;
- aiov[0].iov_len = (size_t)rwrq->ioc_cnt;
-
- auio.uio_iov = aiov;
- auio.uio_iovcnt = 1;
- auio.uio_loffset = rwrq->ioc_offset;
- auio.uio_segflg = UIO_USERSPACE;
- auio.uio_fmode = 0;
- auio.uio_resid = (size_t)rwrq->ioc_cnt;
-
- error = smb_rwuio(ssp, fh, rw, &auio, scred, 0);
+ /* Both of these ioctls copy out the new state. */
+ (void) ddi_copyout(&vcp->vc_state, (void *)arg,
+ sizeof (int), flags);
+out:
/*
- * On return ioc_cnt holds the
- * number of bytes transferred.
+ * The IOD thread is leaving the driver. Clear iod_thr,
+ * and wake up anybody waiting for us to quit.
*/
- rwrq->ioc_cnt -= auio.uio_resid;
+ SMB_VC_LOCK(vcp);
+ vcp->iod_thr = NULL;
+ cv_broadcast(&vcp->vc_statechg);
+ SMB_VC_UNLOCK(vcp);
- return (error);
+ return (err);
}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c
index 5ea38af704..525beb671d 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c
@@ -31,13 +31,12 @@
*
* $FreeBSD: src/sys/kern/subr_mchain.c,v 1.1 2001/02/24 15:44:29 bp Exp $
*/
+
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
@@ -46,6 +45,7 @@
#include <sys/stream.h>
#include <sys/strsun.h>
#include <sys/strsubr.h>
+#include <sys/sunddi.h>
#include <sys/cmn_err.h>
#ifdef APPLE
@@ -127,17 +127,10 @@
*/
/*
- * uio_isuserspace - return non zero value if the address space
+ * uio_isuserspace - non zero value if the address space
* flag is for a user address space (could be 32 or 64 bit).
*/
-int
-uio_isuserspace(uio_t *a_uio)
-{
- if (a_uio->uio_segflg == UIO_USERSPACE) {
- return (1);
- }
- return (0);
-}
+#define uio_isuserspace(uio) (uio->uio_segflg == UIO_USERSPACE)
/*
* uio_curriovbase - return the base address of the current iovec associated
@@ -198,10 +191,10 @@ uio_update(uio_t *a_uio, size_t a_count)
a_uio->uio_resid = 0;
}
if (a_count > (size_t)a_uio->uio_resid) {
- a_uio->uio_offset += a_uio->uio_resid;
+ a_uio->uio_loffset += a_uio->uio_resid;
a_uio->uio_resid = 0;
} else {
- a_uio->uio_offset += a_count;
+ a_uio->uio_loffset += a_count;
a_uio->uio_resid -= a_count;
}
}
@@ -216,7 +209,10 @@ uio_update(uio_t *a_uio, size_t a_count)
}
}
-
+/*
+ * This is now used only to extend an existing mblk chain,
+ * so don't need to use allocb_cred_wait here.
+ */
/*ARGSUSED*/
mblk_t *
m_getblk(int size, int type)
@@ -265,12 +261,17 @@ mb_initm(struct mbchain *mbp, mblk_t *m)
int
mb_init(struct mbchain *mbp)
{
+ cred_t *cr;
mblk_t *mblk;
+ int error;
- mblk = m_getblk(MLEN, 1);
- if (mblk == NULL) {
- return (ENOSR);
- }
+ /*
+ * This message will be the head of a new mblk chain,
+ * so we'd like its db_credp set. If we extend this
+ * chain later, we'll just use allocb_wait()
+ */
+ cr = ddi_get_cred();
+ mblk = allocb_cred_wait(MLEN, STR_NOSIG, &error, cr, NOPID);
/*
* Leave room in this first mblk so we can
@@ -302,7 +303,7 @@ mb_detach(struct mbchain *mbp)
/*
* Returns the length of the mblk_t data.
- *
+ * Should be m_totlen() perhaps?
*/
int
m_fixhdr(mblk_t *m0)
@@ -364,70 +365,115 @@ mb_reserve(struct mbchain *mbp, int size)
* All mb_put_*() functions perform an actual copy of the data into mbuf
* chain. Functions which have le or be suffixes will perform conversion to
* the little- or big-endian data formats.
- * XXX: Assumes total data length in previous mblks is EVEN.
- * XXX: Might need to compute the offset from mb_top instead.
+ *
+ * Inline version of mb_put_mem(). Handles the easy case in-line,
+ * and calls mb_put_mem() if crossing mblk boundaries, etc.
+ *
+ * We build with -xspace, which causes these inline functions
+ * to not be inlined. Using macros instead for now.
+ */
+#ifdef INLINE_WORKS
+
+static inline int
+mb_put_inline(struct mbchain *mbp, void *src, int size)
+{
+ mblk_t *m = mbp->mb_cur;
+
+ if (m != NULL && size <= MBLKTAIL(m)) {
+ uchar_t *p = src;
+ int n = size;
+ while (n--)
+ *(m->b_wptr)++ = *p++;
+ mbp->mb_count += size;
+ return (0);
+ }
+ return (mb_put_mem(mbp, src, size, MB_MINLINE));
+}
+#define MB_PUT_INLINE(MBP, SRC, SZ) \
+ return (mb_put_inline(MBP, SRC, SZ))
+
+#else /* INLINE_WORKS */
+
+#define MB_PUT_INLINE(MBP, SRC, SZ) \
+ mblk_t *m = MBP->mb_cur; \
+ if (m != NULL && SZ <= MBLKTAIL(m)) { \
+ uchar_t *p = (void *) SRC; \
+ int n = SZ; \
+ while (n--) \
+ *(m->b_wptr)++ = *p++; \
+ MBP->mb_count += SZ; \
+ return (0); \
+ } \
+ return (mb_put_mem(MBP, SRC, SZ, MB_MINLINE))
+
+#endif /* INLINE_WORKS */
+
+/*
+ * Assumes total data length in previous mblks is EVEN.
+ * Might need to compute the offset from mb_top instead.
*/
int
mb_put_padbyte(struct mbchain *mbp)
{
- caddr_t dst;
- char x = 0;
-
- dst = (caddr_t)mbp->mb_cur->b_wptr;
+ uintptr_t dst;
+ char v = 0;
+ dst = (uintptr_t)mbp->mb_cur->b_wptr;
/* only add padding if address is odd */
- if ((long)dst & 1)
- return (mb_put_mem(mbp, (caddr_t)&x, 1, MB_MSYSTEM));
- else
- return (0);
+ if (dst & 1) {
+ MB_PUT_INLINE(mbp, &v, sizeof (v));
+ }
+
+ return (0);
}
int
mb_put_uint8(struct mbchain *mbp, u_int8_t x)
{
- return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+ u_int8_t v = x;
+ MB_PUT_INLINE(mbp, &v, sizeof (v));
}
int
mb_put_uint16be(struct mbchain *mbp, u_int16_t x)
{
- x = htobes(x);
- return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+ u_int16_t v = htobes(x);
+ MB_PUT_INLINE(mbp, &v, sizeof (v));
}
int
mb_put_uint16le(struct mbchain *mbp, u_int16_t x)
{
- x = htoles(x);
- return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+ u_int16_t v = htoles(x);
+ MB_PUT_INLINE(mbp, &v, sizeof (v));
}
int
mb_put_uint32be(struct mbchain *mbp, u_int32_t x)
{
- x = htobel(x);
- return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+ u_int32_t v = htobel(x);
+ MB_PUT_INLINE(mbp, &v, sizeof (v));
}
int
mb_put_uint32le(struct mbchain *mbp, u_int32_t x)
{
- x = htolel(x);
- return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+ u_int32_t v = htolel(x);
+ MB_PUT_INLINE(mbp, &v, sizeof (v));
}
int
mb_put_uint64be(struct mbchain *mbp, u_int64_t x)
{
- x = htobeq(x);
- return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+ u_int64_t v = htobeq(x);
+ MB_PUT_INLINE(mbp, &v, sizeof (v));
}
int
mb_put_uint64le(struct mbchain *mbp, u_int64_t x)
{
- x = htoleq(x);
- return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+ u_int64_t v = htoleq(x);
+ MB_PUT_INLINE(mbp, &v, sizeof (v));
}
/*
@@ -436,15 +482,14 @@ mb_put_uint64le(struct mbchain *mbp, u_int64_t x)
* to perform a copy
*/
int
-mb_put_mem(struct mbchain *mbp, c_caddr_t source, int size, int type)
+mb_put_mem(struct mbchain *mbp, const void *vsrc, int size, int type)
{
- mblk_t *m, *n;
- caddr_t dst;
+ mblk_t *n, *m = mbp->mb_cur;
+ c_caddr_t source = vsrc;
c_caddr_t src;
- int cplen, error, mleft, count;
+ caddr_t dst;
uint64_t diff;
-
- m = mbp->mb_cur;
+ int cplen, mleft, count;
diff = MBLKTAIL(m);
ASSERT(diff == (uint64_t)((int)diff));
@@ -477,15 +522,11 @@ mb_put_mem(struct mbchain *mbp, c_caddr_t source, int size, int type)
*dst++ = *src++;
break;
case MB_MSYSTEM:
- /*
- * Try copying the raw bytes instead of using bcopy()
- */
bcopy(source, dst, cplen);
break;
case MB_MUSER:
- error = copyin((void *)source, dst, cplen);
- if (error)
- return (error);
+ if (copyin((void *)source, dst, cplen))
+ return (EFAULT);
break;
case MB_MZERO:
bzero(dst, cplen);
@@ -523,16 +564,15 @@ mb_put_mbuf(struct mbchain *mbp, mblk_t *m)
* copies a uio scatter/gather list to an mbuf chain.
*/
int
-mb_put_uio(struct mbchain *mbp, uio_t *uiop, int size)
+mb_put_uio(struct mbchain *mbp, uio_t *uiop, size_t size)
{
- int left;
+ size_t left;
int mtype, error;
mtype = (uio_isuserspace(uiop) ? MB_MUSER : MB_MSYSTEM);
-
while (size > 0 && uiop->uio_resid) {
- if (uiop->uio_iovcnt <= 0 || uio_curriovbase(uiop) ==
- USER_ADDR_NULL)
+ if (uiop->uio_iovcnt <= 0 ||
+ uio_curriovbase(uiop) == USER_ADDR_NULL)
return (EFBIG);
left = uio_curriovlen(uiop);
if (left > size)
@@ -550,17 +590,6 @@ mb_put_uio(struct mbchain *mbp, uio_t *uiop, int size)
/*
* Routines for fetching data from an mbuf chain
*/
-int
-md_init(struct mdchain *mdp)
-{
- mblk_t *m;
-
- m = m_getblk(MLEN, 1);
- if (m == NULL)
- return (ENOBUFS);
- md_initm(mdp, m);
- return (0);
-}
void
md_initm(struct mdchain *mdp, mblk_t *m)
@@ -634,43 +663,81 @@ md_next_record(struct mdchain *mdp)
return (0);
}
-int
-md_get_uint8(struct mdchain *mdp, u_int8_t *x)
-{
- return (md_get_mem(mdp, (char *)x, 1, MB_MINLINE));
-}
+/*
+ * Inline version of md_get_mem(). Handles the easy case in-line,
+ * and calls md_get_mem() if crossing mblk boundaries, etc.
+ */
+#ifdef INLINE_WORKS /* see above */
-int
-md_get_uint16(struct mdchain *mdp, u_int16_t *x)
+static inline int
+md_get_inline(struct mdchain *mdp, void *dst, int size)
{
- return (md_get_mem(mdp, (char *)x, 2, MB_MINLINE));
+ mblk_t *m = mdp->md_cur;
+
+ if (m != NULL && mdp->md_pos + size <= m->b_wptr) {
+ uchar_t *p = dst;
+ int n = size;
+ while (n--)
+ *p++ = *(mdp->md_pos)++;
+ /* no md_count += size */
+ return (0);
+ }
+ return (md_get_mem(mdp, dst, size, MB_MINLINE));
}
+#define MD_GET_INLINE(MDP, DST, SZ) \
+ error = md_get_inline(MDP, DST, SZ)
+
+#else /* INLINE_WORKS */
+
+/* Note, sets variable: error */
+#define MD_GET_INLINE(MDP, DST, SZ) \
+ mblk_t *m = MDP->md_cur; \
+ if (m != NULL && MDP->md_pos + SZ <= m->b_wptr) { \
+ uchar_t *p = (void *) DST; \
+ int n = SZ; \
+ while (n--) \
+ *p++ = *(mdp->md_pos)++; \
+ /* no md_count += SZ */ \
+ error = 0; \
+ } else \
+ error = md_get_mem(MDP, DST, SZ, MB_MINLINE)
+
+#endif /* INLINE_WORKS */
+
int
-md_get_uint16le(struct mdchain *mdp, u_int16_t *x)
+md_get_uint8(struct mdchain *mdp, u_int8_t *x)
{
- u_int16_t v;
- int error = md_get_uint16(mdp, &v);
+ uint8_t v;
+ int error;
+ MD_GET_INLINE(mdp, &v, sizeof (v));
if (x)
- *x = letohs(v);
+ *x = v;
return (error);
}
int
md_get_uint16be(struct mdchain *mdp, u_int16_t *x) {
u_int16_t v;
- int error = md_get_uint16(mdp, &v);
+ int error;
+ MD_GET_INLINE(mdp, &v, sizeof (v));
if (x)
*x = betohs(v);
return (error);
}
int
-md_get_uint32(struct mdchain *mdp, u_int32_t *x)
+md_get_uint16le(struct mdchain *mdp, u_int16_t *x)
{
- return (md_get_mem(mdp, (caddr_t)x, 4, MB_MINLINE));
+ u_int16_t v;
+ int error;
+
+ MD_GET_INLINE(mdp, &v, sizeof (v));
+ if (x)
+ *x = letohs(v);
+ return (error);
}
int
@@ -679,7 +746,7 @@ md_get_uint32be(struct mdchain *mdp, u_int32_t *x)
u_int32_t v;
int error;
- error = md_get_uint32(mdp, &v);
+ MD_GET_INLINE(mdp, &v, sizeof (v));
if (x)
*x = betohl(v);
return (error);
@@ -691,25 +758,19 @@ md_get_uint32le(struct mdchain *mdp, u_int32_t *x)
u_int32_t v;
int error;
- error = md_get_uint32(mdp, &v);
+ MD_GET_INLINE(mdp, &v, sizeof (v));
if (x)
*x = letohl(v);
return (error);
}
int
-md_get_uint64(struct mdchain *mdp, u_int64_t *x)
-{
- return (md_get_mem(mdp, (caddr_t)x, 8, MB_MINLINE));
-}
-
-int
md_get_uint64be(struct mdchain *mdp, u_int64_t *x)
{
u_int64_t v;
int error;
- error = md_get_uint64(mdp, &v);
+ MD_GET_INLINE(mdp, &v, sizeof (v));
if (x)
*x = betohq(v);
return (error);
@@ -721,20 +782,20 @@ md_get_uint64le(struct mdchain *mdp, u_int64_t *x)
u_int64_t v;
int error;
- error = md_get_uint64(mdp, &v);
+ MD_GET_INLINE(mdp, &v, sizeof (v));
if (x)
*x = letohq(v);
return (error);
}
int
-md_get_mem(struct mdchain *mdp, caddr_t target, int size, int type)
+md_get_mem(struct mdchain *mdp, void *vdst, int size, int type)
{
mblk_t *m = mdp->md_cur;
- int error;
- int count;
+ caddr_t target = vdst;
unsigned char *s;
uint64_t diff;
+ int count;
while (size > 0) {
if (m == NULL) {
@@ -773,9 +834,8 @@ md_get_mem(struct mdchain *mdp, caddr_t target, int size, int type)
continue;
switch (type) {
case MB_MUSER:
- error = copyout(s, (void *)target, count);
- if (error)
- return (error);
+ if (copyout(s, target, count))
+ return (EFAULT);
break;
case MB_MSYSTEM:
bcopy(s, target, count);
@@ -821,7 +881,7 @@ md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret)
}
int
-md_get_uio(struct mdchain *mdp, uio_t *uiop, int size)
+md_get_uio(struct mdchain *mdp, uio_t *uiop, size_t size)
{
size_t left;
int mtype, error;
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs.h
index 4770ee6e84..9eb6cdbed3 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs.h
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs.h
@@ -48,11 +48,21 @@
* but that's now in sys/fs/smbfs_mount.h
*/
+#include <sys/param.h>
+#include <sys/fstyp.h>
#include <sys/list.h>
#include <sys/vfs.h>
-#include <sys/vfs_opreg.h>
#include <sys/fs/smbfs_mount.h>
+/*
+ * Path component length
+ *
+ * The generic fs code uses MAXNAMELEN to represent
+ * what the largest component length is, but note:
+ * that length DOES include the terminating NULL.
+ * SMB_MAXFNAMELEN does NOT include the NULL.
+ */
+#define SMB_MAXFNAMELEN (MAXNAMELEN-1) /* 255 */
/*
* SM_MAX_STATFSTIME is the maximum time to cache statvfs data. Since this
@@ -82,6 +92,16 @@ struct smb_share;
#define SMI_LLOCK 0x80 /* local locking only */
/*
+ * Stuff returned by smbfs_smb_qfsattr
+ * See [CIFS] SMB_QUERY_FS_ATTRIBUTE_INFO
+ */
+typedef struct smb_fs_attr_info {
+ uint32_t fsa_aflags; /* Attr. flags [CIFS 4.1.6.6] */
+ uint32_t fsa_maxname; /* max. component length */
+ char fsa_tname[FSTYPSZ]; /* type name, i.e. "NTFS" */
+} smb_fs_attr_info_t;
+
+/*
* Corresponds to Darwin: struct smbmount
*/
typedef struct smbmntinfo {
@@ -90,11 +110,12 @@ typedef struct smbmntinfo {
struct smb_share *smi_share; /* netsmb SMB share conn data */
kmutex_t smi_lock; /* mutex for flags, etc. */
uint32_t smi_flags; /* NFS-derived flag bits */
- uint32_t smi_fsattr; /* acls & streams opts */
uint32_t smi_status; /* status bits for this mount */
hrtime_t smi_statfstime; /* sm_statvfsbuf cache time */
statvfs64_t smi_statvfsbuf; /* cached statvfs data */
kcondvar_t smi_statvfs_cv;
+ smb_fs_attr_info_t smi_fsa; /* SMB FS attributes. */
+#define smi_fsattr smi_fsa.fsa_aflags
/*
* Kstat statistics
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c
index 88665cfd1b..e50e3b2389 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* ACL support for smbfs
*/
@@ -89,7 +87,7 @@ smbfs_getsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
/* Shared lock for (possible) n_fid use. */
if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
return (EINTR);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
if (error)
@@ -162,7 +160,7 @@ smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
/* Shared lock for (possible) n_fid use. */
if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
return (EINTR);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
if (error)
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
index 368d5e2487..fc089d4c33 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
@@ -18,16 +18,15 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
* All rights reserved.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/thread.h>
@@ -212,42 +211,35 @@ smbfs_zonelist_remove(smbmntinfo_t *smi)
mutex_exit(&smg->smg_lock);
}
+#ifdef lint
+#define NEED_SMBFS_CALLBACKS 1
+#endif
#ifdef NEED_SMBFS_CALLBACKS
/*
* Call-back hooks for netsmb, in case we want them.
* Apple's VFS wants them. We may not need them.
- *
- * I thought I could use the "dead" callback from netsmb
- * to set the SMI_DEAD flag, but that looks like it will
- * interfere with the zone shutdown mechanisms.
*/
+/*ARGSUSED*/
static void smbfs_dead(smb_share_t *ssp)
{
-#if 0 /* see above */
- smbmntinfo_t *smi = ssp->ss_mount;
- if (smi) {
- mutex_enter(&smi->smi_lock);
- smi->smi_flags |= SMI_DEAD;
- mutex_exit(&smi->smi_lock);
- }
-#endif
-}
-
-static void smbfs_down(smb_share_t *ss)
-{
- /* no-op */
+ /*
+ * Walk the mount list, finding all mounts
+ * using this share...
+ */
}
-static void smbfs_up(smb_share_t *ss)
+/*ARGSUSED*/
+static void smbfs_cb_nop(smb_share_t *ss)
{
/* no-op */
}
smb_fscb_t smbfs_cb = {
- .fscb_dead = smbfs_dead,
- .fscb_down = smbfs_down,
- .fscb_up = smbfs_up };
+ .fscb_disconn = smbfs_dead,
+ .fscb_connect = smbfs_cb_nop,
+ .fscb_down = smbfs_cb_nop,
+ .fscb_up = smbfs_cb_nop };
#endif /* NEED_SMBFS_CALLBACKS */
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h
index 98adac6c21..6dc1396094 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h
@@ -33,15 +33,13 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _FS_SMBFS_NODE_H_
#define _FS_SMBFS_NODE_H_
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Much code copied into here from Sun NFS.
*/
@@ -225,6 +223,7 @@ typedef struct smbnode {
struct smbfs_fctx *n_dirseq; /* ff context */
long n_dirofs; /* last ff offset */
long n_direof; /* End of dir. offset. */
+ int n_vcgenid; /* gereration no. (reconnect) */
int n_fidrefs;
uint16_t n_fid; /* file handle */
uint32_t n_rights; /* granted rights */
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c
index 95019bf34f..8e06faa612 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -41,6 +41,7 @@
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/vnode.h>
+#include <sys/sunddi.h>
#include <sys/cmn_err.h>
#ifdef APPLE
@@ -113,6 +114,10 @@ smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid,
/* Shared lock for n_fid use below. */
ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+ /* After reconnect, n_fid is invalid */
+ if (np->n_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
if (op == SMB_LOCK_SHARED)
ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
if (largelock)
@@ -125,7 +130,7 @@ smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid,
mb_put_uint8(mbp, 0xff); /* secondary command */
mb_put_uint8(mbp, 0); /* MBZ */
mb_put_uint16le(mbp, 0);
- mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
+ mb_put_uint16le(mbp, np->n_fid);
mb_put_uint8(mbp, ltype); /* locktype */
mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */
@@ -301,14 +306,14 @@ top:
}
md_get_uint32le(mdp, &size);
fap->fa_size = size;
- md_get_uint32(mdp, NULL); /* allocation size */
+ md_get_uint32le(mdp, NULL); /* allocation size */
md_get_uint16le(mdp, &wattr);
fap->fa_attr = wattr;
break;
case SMB_QFILEINFO_ALL_INFO:
timesok = 0;
/* creation time (discard) */
- md_get_uint64(mdp, NULL);
+ md_get_uint64le(mdp, NULL);
/* last access time */
md_get_uint64le(mdp, &llongint);
if (llongint) {
@@ -384,6 +389,10 @@ smbfs_smb_qfileinfo(struct smbnode *np, struct smbfattr *fap,
*/
ASSERT(np->r_lkserlock.count != 0);
+ /* After reconnect, n_fid is invalid */
+ if (np->n_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
if (np->n_fid == SMB_FID_UNUSED)
return (EBADF);
@@ -400,7 +409,7 @@ top:
else
infolevel = SMB_QFILEINFO_ALL_INFO;
}
- mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
+ mb_put_uint16le(mbp, np->n_fid);
mb_put_uint16le(mbp, infolevel);
t2p->t2_maxpcount = 2;
t2p->t2_maxdcount = vcp->vc_txmax;
@@ -436,14 +445,14 @@ top:
}
md_get_uint32le(mdp, &size);
fap->fa_size = size;
- md_get_uint32(mdp, NULL); /* allocation size */
+ md_get_uint32le(mdp, NULL); /* allocation size */
md_get_uint16le(mdp, &wattr);
fap->fa_attr = wattr;
break;
case SMB_QFILEINFO_ALL_INFO:
timesok = 0;
/* creation time (discard) */
- md_get_uint64(mdp, NULL);
+ md_get_uint64le(mdp, NULL);
/* last access time */
md_get_uint64le(mdp, &llongint);
if (llongint) {
@@ -497,20 +506,18 @@ top:
/*
* Support functions for _qstreaminfo
- * See smbfs_xattr.c
+ * Moved to smbfs_xattr.c
*/
int
-smbfs_smb_qfsattr(struct smb_share *ssp, uint32_t *attrp,
- struct smb_cred *scrp)
+smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
+ struct smb_cred *scrp)
{
struct smb_t2rq *t2p;
struct mbchain *mbp;
struct mdchain *mdp;
- uint32_t nlen;
int error;
- char *fs_name; /* will malloc whatever the size is */
- struct smbfs_fctx ctx;
+ uint32_t nlen;
error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
scrp, &t2p);
@@ -527,35 +534,44 @@ smbfs_smb_qfsattr(struct smb_share *ssp, uint32_t *attrp,
return (error);
}
mdp = &t2p->t2_rdata;
- md_get_uint32le(mdp, attrp);
- md_get_uint32le(mdp, &ssp->ss_maxfilenamelen);
+ md_get_uint32le(mdp, &fsa->fsa_aflags);
+ md_get_uint32le(mdp, &fsa->fsa_maxname);
md_get_uint32le(mdp, &nlen); /* fs name length */
- if (ssp->ss_fsname == NULL && nlen) {
- ctx.f_ssp = ssp;
- ctx.f_name = kmem_alloc(nlen, KM_SLEEP);
- ctx.f_namesz = nlen;
- md_get_mem(mdp, ctx.f_name, nlen, MB_MSYSTEM);
- ctx.f_nmlen = nlen;
- smbfs_fname_tolocal(&ctx);
- fs_name = kmem_alloc(ctx.f_nmlen+1, KM_SLEEP);
- bcopy(ctx.f_name, fs_name, ctx.f_nmlen);
- fs_name[ctx.f_nmlen] = '\0';
- ssp->ss_fsname = fs_name;
- kmem_free(ctx.f_name, ctx.f_namesz);
- /*
- * If fs_name isn't NTFS they probably require resume keys.
- * This is another example of the client trying to fix a server
- * bug. This code uses the logic created by PR-3983209. See
- * long block comment in smbfs_smb_findnextLM2.
- */
- if (strcmp(fs_name, "NTFS")) {
- SMB_SS_LOCK(ssp);
- ssp->ss_flags |= SMBS_RESUMEKEYS;
- SMB_SS_UNLOCK(ssp);
- }
- SMBVDEBUG("(fyi) share '%s', attr 0x%x, maxfilename %d\n",
- ssp->ss_fsname, *attrp, ssp->ss_maxfilenamelen);
+
+ /*
+ * Get the FS type name.
+ */
+ bzero(fsa->fsa_tname, FSTYPSZ);
+ if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
+ uint16_t tmpbuf[FSTYPSZ];
+ size_t tmplen, outlen;
+
+ if (nlen > sizeof (tmpbuf))
+ nlen = sizeof (tmpbuf);
+ md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
+ tmplen = nlen / 2; /* UCS-2 chars */
+ outlen = FSTYPSZ - 1;
+ uconv_u16tou8(tmpbuf, &tmplen,
+ (uchar_t *)fsa->fsa_tname, &outlen,
+ UCONV_IN_LITTLE_ENDIAN);
+ } else {
+ if (nlen > (FSTYPSZ - 1))
+ nlen = FSTYPSZ - 1;
+ md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
}
+
+ /*
+ * If fs_name isn't NTFS they probably require resume keys.
+ * This is another example of the client trying to fix a server
+ * bug. This code uses the logic created by PR-3983209. See
+ * long block comment in smbfs_smb_findnextLM2.
+ */
+ if (strcmp(fsa->fsa_tname, "NTFS")) {
+ SMB_SS_LOCK(ssp);
+ ssp->ss_flags |= SMBS_RESUMEKEYS;
+ SMB_SS_UNLOCK(ssp);
+ }
+
smb_t2_done(t2p);
return (0);
}
@@ -601,7 +617,7 @@ smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp,
return (error);
}
mdp = &t2p->t2_rdata;
- md_get_uint32(mdp, NULL); /* fs id */
+ md_get_uint32le(mdp, NULL); /* fs id */
md_get_uint32le(mdp, &bpu);
md_get_uint32le(mdp, &units);
md_get_uint32le(mdp, &funits);
@@ -713,7 +729,7 @@ smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
return (error);
mbp = &t2p->t2_tparam;
mb_init(mbp);
- mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+ mb_put_uint16le(mbp, fid);
if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION);
else
@@ -747,6 +763,10 @@ smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp,
/* Shared lock for n_fid use below. */
ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+ /* After reconnect, n_fid is invalid */
+ if (np->n_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU))
return (ENOTSUP);
error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
@@ -761,13 +781,13 @@ smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp,
}
mbp = &t2p->t2_tparam;
mb_init(mbp);
- mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
+ mb_put_uint16le(mbp, np->n_fid);
mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
mb_put_uint16le(mbp, 0); /* reserved, nowadays */
mbp = &t2p->t2_tdata;
mb_init(mbp);
mb_put_uint32le(mbp, overwrite);
- mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); /* base for tname */
+ mb_put_uint16le(mbp, fid); /* base for tname */
mb_put_uint16le(mbp, 0); /* part of a 32bit fid? */
ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t));
mbp->mb_count = 0;
@@ -805,12 +825,16 @@ smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp)
if (np->n_fidrefs == 0)
return (0); /* not open */
+ /* After reconnect, n_fid is invalid */
+ if (np->n_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
if (error)
return (error);
smb_rq_getrequest(rqp, &mbp);
smb_rq_wstart(rqp);
- mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
+ mb_put_uint16le(mbp, np->n_fid);
smb_rq_wend(rqp);
smb_rq_bstart(rqp);
smb_rq_bend(rqp);
@@ -865,7 +889,7 @@ smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
return (error);
smb_rq_getrequest(rqp, &mbp);
smb_rq_wstart(rqp);
- mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+ mb_put_uint16le(mbp, fid);
mb_put_uint16le(mbp, 0);
mb_put_uint32le(mbp, newsize);
mb_put_uint16le(mbp, 0);
@@ -1273,7 +1297,7 @@ smbfs_smb_setftime1(
tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
smb_rq_getrequest(rqp, &mbp);
smb_rq_wstart(rqp);
- mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+ mb_put_uint16le(mbp, fid);
mb_put_uint32le(mbp, 0); /* creation time */
if (atime)
@@ -1320,7 +1344,7 @@ smbfs_smb_setfattrNT(struct smbnode *np, uint16_t fid,
svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
mbp = &t2p->t2_tparam;
mb_init(mbp);
- mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+ mb_put_uint16le(mbp, fid);
if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION);
else
@@ -1461,7 +1485,7 @@ smbfs_smb_ntcreatex(struct smbnode *np, uint32_t rights,
md_get_uint8(mdp, NULL); /* mbz */
md_get_uint16le(mdp, NULL); /* andxoffset */
md_get_uint8(mdp, NULL); /* oplock lvl granted */
- md_get_uint16(mdp, &fid); /* yes, leaving it LE */
+ md_get_uint16le(mdp, &fid); /* file ID */
md_get_uint32le(mdp, &createact); /* create_action */
md_get_uint64le(mdp, &llongint); /* creation time */
md_get_uint64le(mdp, &llongint); /* access time */
@@ -1634,7 +1658,7 @@ smbfs_smb_oldopen(struct smbnode *np, int accmode, struct smb_cred *scrp,
error = EBADRPC;
break;
}
- md_get_uint16(mdp, &fid); /* yes, we leave it LE */
+ md_get_uint16le(mdp, &fid);
md_get_uint16le(mdp, &wattr);
fap.fa_attr = wattr;
/*
@@ -1703,15 +1727,19 @@ int
smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
uint16_t *fidp)
{
- struct smb_vc *vcp = SSTOVC(np->n_mount->smi_share);
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
enum vtype vt = VREG;
int error;
/* Shared lock for n_fid use below. */
ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+ /* Can we re-use n_fid? or must we open anew? */
mutex_enter(&np->r_statelock);
- if (np->n_fidrefs && (rights & np->n_rights) == rights) {
+ if (np->n_fidrefs > 0 &&
+ np->n_vcgenid == ssp->ss_vcgenid &&
+ (rights & np->n_rights) == rights) {
np->n_fidrefs++;
*fidp = np->n_fid;
mutex_exit(&np->r_statelock);
@@ -1731,14 +1759,6 @@ smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
NULL, NULL);
}
- if (*fidp == np->n_fid) {
- /*
- * Oh no, the server gave us the same FID again?
- * This will cause us to close np->n_fid early!
- */
- SMBVDEBUG("duplicate fid: 0x%x\n", *fidp);
- }
-
return (error);
}
@@ -1797,10 +1817,7 @@ smbfs_smb_open(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
error = smbfs_smb_oldopen(np, smb_rights2mode(rights), scrp,
attrcacheupdated, fidp, name, nmlen, xattr, sizep, rightsp);
}
-#if 0 /* let caller do this */
- if (!error && !name)
- np->n_fidrefs++;
-#endif
+
return (error);
}
@@ -1818,7 +1835,7 @@ smbfs_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
return (error);
smb_rq_getrequest(rqp, &mbp);
smb_rq_wstart(rqp);
- mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
+ mb_put_uint16le(mbp, fid);
if (mtime) {
smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
} else
@@ -1900,7 +1917,7 @@ smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen,
smb_rq_getreply(rqp, &mdp);
md_get_uint8(mdp, &wc);
if (wc == 1)
- md_get_uint16(mdp, fidp);
+ md_get_uint16le(mdp, fidp);
else
error = EBADRPC;
}
@@ -2327,7 +2344,7 @@ smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
ctx->f_t2 = t2p;
mbp = &t2p->t2_tparam;
mb_init(mbp);
- mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
+ mb_put_uint16le(mbp, ctx->f_Sid);
mb_put_uint16le(mbp, ctx->f_limit);
mb_put_uint16le(mbp, ctx->f_infolevel);
if (ctx->f_ssp->ss_flags & SMBS_RESUMEKEYS) {
@@ -2366,7 +2383,7 @@ smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
return (error);
mdp = &t2p->t2_rparam;
if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
- if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
+ if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0)
return (error);
ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
}
@@ -2420,7 +2437,7 @@ smbfs_smb_findclose2(struct smbfs_fctx *ctx)
return (error);
smb_rq_getrequest(rqp, &mbp);
smb_rq_wstart(rqp);
- mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
+ mb_put_uint16le(mbp, ctx->f_Sid);
smb_rq_wend(rqp);
smb_rq_bstart(rqp);
smb_rq_bend(rqp);
@@ -2438,10 +2455,10 @@ smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
{
ctx->f_type = ft_LM2;
- ctx->f_namesz = SMB_MAXFNAMELEN;
+ ctx->f_namesz = SMB_MAXFNAMELEN + 1;
if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
ctx->f_namesz *= 2;
- ctx->f_name = kmem_zalloc(ctx->f_namesz, KM_SLEEP);
+ ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp))
< SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD :
SMB_FIND_BOTH_DIRECTORY_INFO;
@@ -2495,7 +2512,7 @@ again:
smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
md_get_uint32le(mdp, &size);
ctx->f_attr.fa_size = size;
- md_get_uint32(mdp, NULL); /* allocation size */
+ md_get_uint32le(mdp, NULL); /* allocation size */
md_get_uint16le(mdp, &wattr);
ctx->f_attr.fa_attr = wattr;
md_get_uint8(mdp, &tb);
@@ -2507,7 +2524,7 @@ again:
case SMB_FIND_BOTH_DIRECTORY_INFO:
md_get_uint32le(mdp, &next);
md_get_uint32le(mdp, &resumekey); /* file index (resume key) */
- md_get_uint64(mdp, NULL); /* creation time */
+ md_get_uint64le(mdp, NULL); /* creation time */
md_get_uint64le(mdp, &llongint);
smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_atime);
md_get_uint64le(mdp, &llongint);
@@ -2516,7 +2533,7 @@ again:
smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_ctime);
md_get_uint64le(mdp, &llongint); /* file size */
ctx->f_attr.fa_size = llongint;
- md_get_uint64(mdp, NULL); /* real size (should use) */
+ md_get_uint64le(mdp, NULL); /* real size (should use) */
/* freebsd bug: fa_attr endian bug */
md_get_uint32le(mdp, &dattr); /* extended file attributes */
ctx->f_attr.fa_attr = dattr;
@@ -2541,10 +2558,11 @@ again:
nmlen = min(size, SMB_MAXFNAMELEN * 2);
else
nmlen = min(size, SMB_MAXFNAMELEN);
- if (ctx->f_name)
- kmem_free(ctx->f_name, ctx->f_namesz);
- cp = ctx->f_name = kmem_alloc(nmlen, KM_SLEEP);
- ctx->f_namesz = nmlen;
+
+ /* Allocated f_name in findopen */
+ ASSERT(nmlen < ctx->f_namesz);
+ cp = ctx->f_name;
+
error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM);
if (error)
return (error);
@@ -2663,10 +2681,7 @@ smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
struct smbfs_fctx *ctx;
int error;
- ctx = kmem_alloc(sizeof (*ctx), KM_SLEEP);
- if (ctx == NULL)
- return (ENOMEM);
- bzero(ctx, sizeof (*ctx));
+ ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
ctx->f_flags = SMBFS_RDD_FINDFIRST;
ctx->f_dnp = dnp;
@@ -2876,7 +2891,7 @@ smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
/* Parameters part */
mbp = &ntp->nt_tparam;
mb_init(mbp);
- mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+ mb_put_uint16le(mbp, fid);
mb_put_uint16le(mbp, 0); /* reserved */
mb_put_uint32le(mbp, selector);
/* Data part (none) */
@@ -2904,7 +2919,7 @@ smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
*/
mdp = &ntp->nt_rdata;
if (mdp->md_top == NULL) {
- SMBVDEBUG("null md_top? fid 0x%x\n", letohs(fid));
+ SMBVDEBUG("null md_top? fid 0x%x\n", fid);
error = EBADRPC;
goto done;
}
@@ -2917,7 +2932,7 @@ smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
len = m_fixhdr(mdp->md_top);
if (len != *reslen) {
SMBVDEBUG("len %d *reslen %d fid 0x%x\n",
- len, *reslen, letohs(fid));
+ len, *reslen, fid);
}
/*
@@ -3023,7 +3038,7 @@ int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
/* Parameters part */
mbp = &ntp->nt_tparam;
mb_init(mbp);
- mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+ mb_put_uint16le(mbp, fid);
mb_put_uint16le(mbp, 0); /* reserved */
mb_put_uint32le(mbp, selector);
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
index eaf3fb2238..c94b4dddff 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
@@ -33,12 +33,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/time.h>
@@ -343,48 +341,55 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
return (error);
}
+/*
+ * Convert a Unicode directory entry to UTF-8
+ */
void
smbfs_fname_tolocal(struct smbfs_fctx *ctx)
{
- int length;
+ uchar_t tmpbuf[SMB_MAXFNAMELEN+1];
struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
uchar_t *dst;
const ushort_t *src;
size_t inlen, outlen;
- int flags = 0;
+ int flags;
if (ctx->f_nmlen == 0)
return;
- /* XXX: This is temporary, right? Need iconv... */
if (!SMB_UNICODE_STRINGS(vcp))
return;
+ if (ctx->f_namesz < sizeof (tmpbuf)) {
+ ASSERT(0);
+ goto errout;
+ }
+
/*
- * In Unix, the UTF-8 name can be larger and
- * in-place conversions are not supported.
- * Note: 3,9 are the maximum UTF-8 expansion
- * factors when converting strings from UTF-16
- * XXX: This was removed. REVISIT
+ * In-place conversions are not supported,
+ * so convert into tmpbuf and copy.
*/
- if (SMB_UNICODE_STRINGS(vcp))
- length = ctx->f_nmlen * 9; /* why 9 */
- else
- length = ctx->f_nmlen * 3; /* why 3 */
- length = min(length, SMB_MAXFNAMELEN);
-
- dst = kmem_zalloc(length, KM_SLEEP);
- outlen = length;
+ dst = tmpbuf;
+ outlen = SMB_MAXFNAMELEN;
/*LINTED*/
src = (const ushort_t *)ctx->f_name;
- inlen = ctx->f_nmlen / 2; /* need number of UCS-2 characters */
- flags |= UCONV_IN_LITTLE_ENDIAN;
-
- if (uconv_u16tou8(src, &inlen, dst, &outlen, flags) == 0) {
- kmem_free(ctx->f_name, ctx->f_namesz);
- ctx->f_name = (char *)dst;
- ctx->f_namesz = length;
- ctx->f_nmlen = (int)outlen;
- } else
- kmem_free(dst, length);
+ inlen = ctx->f_nmlen / 2; /* number of UCS-2 characters */
+ flags = UCONV_IN_LITTLE_ENDIAN;
+
+ if (uconv_u16tou8(src, &inlen, dst, &outlen, flags) != 0)
+ goto errout;
+
+ ASSERT(outlen < sizeof (tmpbuf));
+ tmpbuf[outlen] = '\0';
+ bcopy(tmpbuf, ctx->f_name, outlen + 1);
+ ctx->f_nmlen = (int)outlen;
+ return;
+
+errout:
+ /*
+ * Conversion failed, but our caller does not
+ * deal with errors here, so... (hack).
+ * Don't expect to ever see this.
+ */
+ strlcpy(ctx->f_name + 1, "?", ctx->f_namesz);
}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h
index b2382d5438..877f6e53c3 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h
@@ -33,15 +33,13 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _FS_SMBFS_SMBFS_SUBR_H_
#define _FS_SMBFS_SMBFS_SUBR_H_
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/cmn_err.h>
#include <netsmb/mchain.h>
@@ -150,14 +148,13 @@ typedef struct smbfs_fctx smbfs_fctx_t;
#define f_rq f_urq.uf_rq
#define f_t2 f_urq.uf_t2
-
/*
* smb level
*/
int smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
offset_t start, uint64_t len, int largelock,
struct smb_cred *scrp, uint32_t timeout);
-int smbfs_smb_qfsattr(struct smb_share *ssp, uint32_t *attrp,
+int smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *,
struct smb_cred *scrp);
int smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
struct smb_cred *scrp);
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c
index f86518902c..b616543a92 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c
@@ -33,12 +33,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/systm.h>
#include <sys/cred.h>
#include <sys/vfs.h>
@@ -119,9 +117,11 @@ static mntopts_t smbfs_mntopts = {
mntopts
};
+static const char fs_type_name[FSTYPSZ] = "smbfs";
+
static vfsdef_t vfw = {
VFSDEF_VERSION,
- "smbfs", /* type name string */
+ (char *)fs_type_name,
smbfsinit, /* init routine */
VSW_HASPROTO|VSW_NOTZONESAFE, /* flags */
&smbfs_mntopts /* mount options table prototype */
@@ -129,7 +129,7 @@ static vfsdef_t vfw = {
static struct modlfs modlfs = {
&mod_fsops,
- "SMBFS filesystem v" SMBFS_VER_STR,
+ "SMBFS filesystem",
&vfw
};
@@ -386,16 +386,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
return (error);
}
- /*
- * We don't have data structures to support multiple mounts of
- * the same share object by the same owner, so don't allow it.
- */
- if (ssp->ss_mount != NULL) {
- smb_share_rele(ssp);
- return (EBUSY);
- }
-
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
/*
* Use "goto errout" from here on.
@@ -458,7 +449,6 @@ proceed:
smi = kmem_zalloc(sizeof (smbmntinfo_t), KM_SLEEP);
smi->smi_share = ssp;
- ssp->ss_mount = smi;
smi->smi_zone = mntzone;
smi->smi_flags = SMI_LLOCK;
@@ -481,7 +471,7 @@ proceed:
* Get attributes of the remote file system,
* i.e. ACL support, named streams, etc.
*/
- error = smbfs_smb_qfsattr(ssp, &smi->smi_fsattr, &scred);
+ error = smbfs_smb_qfsattr(ssp, &smi->smi_fsa, &scred);
if (error) {
SMBVDEBUG("smbfs_smb_qfsattr error %d\n", error);
}
@@ -729,6 +719,7 @@ smbfs_statvfs(vfs_t *vfsp, statvfs64_t *sbp)
recheck:
now = gethrtime();
if (now < smi->smi_statfstime) {
+ error = 0;
goto cache_hit;
}
@@ -753,46 +744,45 @@ recheck:
/*
* Do the OTW call. Note: lock NOT held.
*/
- smb_credinit(&scred, curproc, NULL);
+ smb_credinit(&scred, NULL);
bzero(&stvfs, sizeof (stvfs));
error = smbfs_smb_statfs(ssp, &stvfs, &scred);
smb_credrele(&scred);
+ if (error) {
+ SMBVDEBUG("statfs error=%d\n", error);
+ } else {
+
+ /*
+ * Set a few things the OTW call didn't get.
+ */
+ stvfs.f_frsize = stvfs.f_bsize;
+ stvfs.f_favail = stvfs.f_ffree;
+ stvfs.f_fsid = (unsigned long)vfsp->vfs_fsid.val[0];
+ bcopy(fs_type_name, stvfs.f_basetype, FSTYPSZ);
+ stvfs.f_flag = vf_to_stf(vfsp->vfs_flag);
+ stvfs.f_namemax = smi->smi_fsa.fsa_maxname;
+
+ /*
+ * Save the result, update lifetime
+ */
+ now = gethrtime();
+ smi->smi_statfstime = now +
+ (SM_MAX_STATFSTIME * (hrtime_t)NANOSEC);
+ smi->smi_statvfsbuf = stvfs; /* struct assign! */
+ }
mutex_enter(&smi->smi_lock);
if (smi->smi_status & SM_STATUS_STATFS_WANT)
cv_broadcast(&smi->smi_statvfs_cv);
smi->smi_status &= ~(SM_STATUS_STATFS_BUSY | SM_STATUS_STATFS_WANT);
- if (error) {
- SMBVDEBUG("statfs error=%d\n", error);
- mutex_exit(&smi->smi_lock);
- return (error);
- }
-
- /*
- * Set a few things the OTW call didn't get.
- */
- stvfs.f_frsize = stvfs.f_bsize;
- stvfs.f_favail = stvfs.f_ffree;
- stvfs.f_fsid = (unsigned long)vfsp->vfs_fsid.val[0];
- (void) strncpy(stvfs.f_basetype, vfw.name, FSTYPSZ);
- stvfs.f_flag = vf_to_stf(vfsp->vfs_flag);
- stvfs.f_namemax = (uint32_t)MAXNAMELEN - 1;
-
- /*
- * Save the result, update lifetime
- */
- now = gethrtime();
- smi->smi_statfstime = now +
- (SM_MAX_STATFSTIME * (hrtime_t)NANOSEC);
- smi->smi_statvfsbuf = stvfs; /* struct assign! */
-
/*
* Copy the statvfs data to caller's buf.
* Note: struct assignment
*/
cache_hit:
- *sbp = smi->smi_statvfsbuf;
+ if (error == 0)
+ *sbp = smi->smi_statvfsbuf;
mutex_exit(&smi->smi_lock);
return (error);
}
@@ -861,8 +851,6 @@ smbfs_freevfs(vfs_t *vfsp)
*/
ssp = smi->smi_share;
smi->smi_share = NULL;
- ssp->ss_mount = NULL;
-
smb_share_rele(ssp);
zone_rele(smi->smi_zone);
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
index 9bf9d5d7c3..df78ba61ff 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
@@ -45,6 +45,7 @@
#include <sys/uio.h>
#include <sys/dirent.h>
#include <sys/errno.h>
+#include <sys/sunddi.h>
#include <sys/sysmacros.h>
#include <sys/kmem.h>
#include <sys/cmn_err.h>
@@ -233,8 +234,10 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
vnode_t *vp;
u_int32_t rights, rightsrcvd;
u_int16_t fid, oldfid;
+ int oldgenid;
struct smb_cred scred;
smbmntinfo_t *smi;
+ smb_share_t *ssp;
cred_t *oldcr;
int attrcacheupdated = 0;
int tmperror;
@@ -243,6 +246,7 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
vp = *vpp;
np = VTOSMB(vp);
smi = VTOSMI(vp);
+ ssp = smi->smi_share;
if (curproc->p_zone != smi->smi_zone)
return (EIO);
@@ -261,7 +265,7 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
*/
if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
return (EINTR);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
/*
* Keep track of the vnode type at first open.
@@ -296,10 +300,11 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
flag |= FWRITE;
/*
- * If we already have it open, check to see if current rights
- * are sufficient for this open.
+ * If we already have it open, and the FID is still valid,
+ * check whether the rights are sufficient for FID reuse.
*/
- if (np->n_fidrefs) {
+ if (np->n_fidrefs > 0 &&
+ np->n_vcgenid == ssp->ss_vcgenid) {
int upgrade = 0;
/* BEGIN CSTYLED */
@@ -346,16 +351,19 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
* We have a new FID and access rights.
*/
oldfid = np->n_fid;
+ oldgenid = np->n_vcgenid;
np->n_fid = fid;
+ np->n_vcgenid = ssp->ss_vcgenid;
np->n_rights = rightsrcvd;
np->n_fidrefs++;
- if (np->n_fidrefs > 1) {
+ if (np->n_fidrefs > 1 &&
+ oldgenid == ssp->ss_vcgenid) {
/*
* We already had it open (presumably because
* it was open with insufficient rights.)
* Close old wire-open.
*/
- tmperror = smbfs_smb_close(smi->smi_share,
+ tmperror = smbfs_smb_close(ssp,
oldfid, &np->n_mtime, &scred);
if (tmperror)
SMBVDEBUG("error %d closing %s\n",
@@ -413,10 +421,14 @@ smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
caller_context_t *ct)
{
smbnode_t *np;
+ smbmntinfo_t *smi;
+ smb_share_t *ssp;
int error = 0;
struct smb_cred scred;
np = VTOSMB(vp);
+ smi = VTOSMI(vp);
+ ssp = smi->smi_share;
/*
* Don't "bail out" for VFS_UNMOUNTED here,
@@ -457,8 +469,9 @@ smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
* incoming reference count is.
*/
if (VTOSMI(vp)->smi_flags & SMI_LLOCK) {
- cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
- cleanshares(vp, ttoproc(curthread)->p_pid);
+ pid_t pid = ddi_get_pid();
+ cleanlocks(vp, pid, 0);
+ cleanshares(vp, pid);
}
if (count > 1)
@@ -478,7 +491,7 @@ smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
* Don't want this one ever interruptible.
*/
(void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
error = 0;
@@ -505,8 +518,11 @@ smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
goto out;
if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
np->n_fid = SMB_FID_UNUSED;
- error = smbfs_smb_close(np->n_mount->smi_share,
- ofid, NULL, &scred);
+ /* After reconnect, n_fid is invalid */
+ if (np->n_vcgenid == ssp->ss_vcgenid) {
+ error = smbfs_smb_close(
+ ssp, ofid, NULL, &scred);
+ }
}
}
if (error) {
@@ -533,18 +549,18 @@ static int
smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
caller_context_t *ct)
{
- smbmntinfo_t *smi;
- smbnode_t *np;
struct smb_cred scred;
struct vattr va;
- /* u_offset_t off; */
- /* offset_t diff; */
+ smbnode_t *np;
+ smbmntinfo_t *smi;
+ smb_share_t *ssp;
offset_t endoff;
ssize_t past_eof;
int error;
np = VTOSMB(vp);
smi = VTOSMI(vp);
+ ssp = smi->smi_share;
if (curproc->p_zone != smi->smi_zone)
return (EIO);
@@ -565,8 +581,8 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
* Our SMB layer takes care to return EFBIG
* when it has to fallback to a 32-bit call.
*/
- if (uiop->uio_loffset < 0 ||
- uiop->uio_loffset + uiop->uio_resid < 0)
+ endoff = uiop->uio_loffset + uiop->uio_resid;
+ if (uiop->uio_loffset < 0 || endoff < 0)
return (EINVAL);
/* get vnode attributes from server */
@@ -585,7 +601,6 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
* Do this by temporarily reducing uio_resid
* by the amount the lies beyoned the EOF.
*/
- endoff = uiop->uio_loffset + uiop->uio_resid;
if (endoff > va.va_size) {
past_eof = (ssize_t)(endoff - va.va_size);
uiop->uio_resid -= past_eof;
@@ -595,10 +610,14 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
/* Shared lock for n_fid use in smb_rwuio */
if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
return (EINTR);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
- error = smb_rwuio(smi->smi_share, np->n_fid, UIO_READ, uiop,
- &scred, smb_timo_read);
+ /* After reconnect, n_fid is invalid */
+ if (np->n_vcgenid != ssp->ss_vcgenid)
+ error = ESTALE;
+ else
+ error = smb_rwuio(ssp, np->n_fid, UIO_READ,
+ uiop, &scred, smb_timo_read);
smb_credrele(&scred);
smbfs_rw_exit(&np->r_lkserlock);
@@ -615,16 +634,18 @@ static int
smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
caller_context_t *ct)
{
- smbmntinfo_t *smi;
- smbnode_t *np;
struct smb_cred scred;
struct vattr va;
+ smbnode_t *np;
+ smbmntinfo_t *smi;
+ smb_share_t *ssp;
offset_t endoff, limit;
ssize_t past_limit;
int error, timo;
np = VTOSMB(vp);
smi = VTOSMI(vp);
+ ssp = smi->smi_share;
if (curproc->p_zone != smi->smi_zone)
return (EIO);
@@ -696,10 +717,14 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
/* Shared lock for n_fid use in smb_rwuio */
if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
return (EINTR);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
- error = smb_rwuio(smi->smi_share, np->n_fid, UIO_WRITE, uiop,
- &scred, timo);
+ /* After reconnect, n_fid is invalid */
+ if (np->n_vcgenid != ssp->ss_vcgenid)
+ error = ESTALE;
+ else
+ error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
+ uiop, &scred, timo);
if (error == 0) {
mutex_enter(&np->r_statelock);
@@ -864,7 +889,7 @@ smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr)
/* Shared lock for (possible) n_fid use. */
if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
return (EINTR);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
bzero(&fattr, sizeof (fattr));
error = smbfs_smb_getfattr(np, &fattr, &scred);
@@ -964,7 +989,7 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
/* Shared lock for (possible) n_fid use. */
if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
return (EINTR);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
/*
* Will we need an open handle for this setattr?
@@ -984,6 +1009,7 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
* Only SIZE requires a handle.
* XXX May be more reliable to just
* always get the file handle here.
+ * The tmpopen checks n_vcgenid.
*/
error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
if (error) {
@@ -1024,6 +1050,9 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
* Tests indicate the server will zero-fill,
* so looks like we don't need to do this.
* Good thing, as this could take forever.
+ *
+ * XXX: Reportedly, writing one byte of zero
+ * at the end offset avoids problems here.
*/
mutex_enter(&np->r_statelock);
np->r_size = vap->va_size;
@@ -1265,7 +1294,7 @@ smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
/* Shared lock for n_fid use in _flush */
if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
return (EINTR);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
error = smbfs_smb_flush(np, &scred);
@@ -1563,7 +1592,7 @@ smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int dnlc,
* First, go over-the-wire to get the
* node type (and attributes).
*/
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
/* Note: this can allocate a new "name" */
error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
smb_credrele(&scred);
@@ -1748,7 +1777,7 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
return (EINTR);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
/*
* XXX: Do we need r_lkserlock too?
@@ -2016,7 +2045,7 @@ smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
} else {
mutex_exit(&np->r_statelock);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
error = smbfs_smb_delete(np, &scred, NULL, 0, 0);
smb_credrele(&scred);
@@ -2254,7 +2283,7 @@ smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
/*
* Target file is not active. Try to remove it.
*/
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
error = smbfs_smb_delete(nnp, &scred, NULL, 0, 0);
smb_credrele(&scred);
if (error)
@@ -2273,7 +2302,7 @@ smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
dnlc_remove(ndvp, nnm);
onp = VTOSMB(ovp);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred);
smb_credrele(&scred);
@@ -2331,7 +2360,7 @@ smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
return (EINTR);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
/*
* XXX: Do we need r_lkserlock too?
@@ -2409,7 +2438,7 @@ smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
return (EINTR);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
/*
* Require w/x access in the containing directory.
@@ -2572,8 +2601,8 @@ smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
dnlc_purge_vp(vp);
#endif
SMBVDEBUG("dirname='%s'\n", np->n_rpath);
- smb_credinit(&scred, curproc, cr);
- dbufsiz = DIRENT64_RECLEN(MAXNAMELEN);
+ smb_credinit(&scred, cr);
+ dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN);
dp = kmem_alloc(dbufsiz, KM_SLEEP);
offset = uio->uio_offset; /* NB: "cookie" */
@@ -2670,8 +2699,8 @@ smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
np->n_dirofs++;
/* Sanity check the name length. */
nmlen = ctx->f_nmlen;
- if (nmlen > (MAXNAMELEN - 1)) {
- nmlen = MAXNAMELEN - 1;
+ if (nmlen > SMB_MAXFNAMELEN) {
+ nmlen = SMB_MAXFNAMELEN;
SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
}
reclen = DIRENT64_RECLEN(nmlen);
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c
index 4760576731..ad68648d12 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -198,7 +198,7 @@ smbfs_xa_exists(vnode_t *vp, cred_t *cr)
/* NB: have VN_HOLD on xpv */
xnp = VTOSMB(xvp);
- smb_credinit(&scred, curproc, cr);
+ smb_credinit(&scred, cr);
bzero(&ctx, sizeof (ctx));
ctx.f_flags = SMBFS_RDD_FINDFIRST;
@@ -303,6 +303,10 @@ smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
ASSERT(dnp->n_flag & N_XATTR);
ctx->f_type = ft_XA;
+ ctx->f_namesz = SMB_MAXFNAMELEN + 1;
+ if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
+ ctx->f_namesz *= 2;
+ ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
error = smbfs_xa_parent(SMBTOV(dnp), &pvp);
if (error)
@@ -404,12 +408,8 @@ again:
nmlen = min(size, SMB_MAXFNAMELEN);
}
- if (ctx->f_name)
- kmem_free(ctx->f_name, ctx->f_namesz);
+ ASSERT(nmlen < ctx->f_namesz);
ctx->f_nmlen = nmlen;
- /* Add one to prevent allocating size zero. */
- ctx->f_namesz = nmlen + 1;
- ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
error = md_get_mem(mdp, ctx->f_name, nmlen, MB_MSYSTEM);
if (error)
return (error);
diff --git a/usr/src/uts/common/netsmb/mchain.h b/usr/src/uts/common/netsmb/mchain.h
index 7009ba75bf..bccb9aab7f 100644
--- a/usr/src/uts/common/netsmb/mchain.h
+++ b/usr/src/uts/common/netsmb/mchain.h
@@ -31,16 +31,15 @@
*
* $FreeBSD: src/sys/sys/mchain.h,v 1.1 2001/02/24 15:44:30 bp Exp $
*/
+
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _MCHAIN_H_
#define _MCHAIN_H_
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/isa_defs.h>
#include <sys/byteorder.h>
@@ -158,10 +157,10 @@ int mb_put_uint32be(struct mbchain *mbp, uint32_t x);
int mb_put_uint32le(struct mbchain *mbp, uint32_t x);
int mb_put_uint64be(struct mbchain *mbp, uint64_t x);
int mb_put_uint64le(struct mbchain *mbp, uint64_t x);
-int mb_put_mem(struct mbchain *mbp, const char *src, int size, int type);
+int mb_put_mem(struct mbchain *mbp, const void *src, int size, int type);
int mb_put_mbuf(struct mbchain *mbp, mblk_t *m);
-int mb_put_uio(struct mbchain *mbp, uio_t *uiop, int size);
+int mb_put_uio(struct mbchain *mbp, uio_t *uiop, size_t size);
int md_init(struct mdchain *mdp);
void md_initm(struct mdchain *mbp, mblk_t *m);
@@ -169,18 +168,15 @@ void md_done(struct mdchain *mdp);
void md_append_record(struct mdchain *mdp, mblk_t *top);
int md_next_record(struct mdchain *mdp);
int md_get_uint8(struct mdchain *mdp, uint8_t *x);
-int md_get_uint16(struct mdchain *mdp, uint16_t *x);
int md_get_uint16le(struct mdchain *mdp, uint16_t *x);
int md_get_uint16be(struct mdchain *mdp, uint16_t *x);
-int md_get_uint32(struct mdchain *mdp, uint32_t *x);
int md_get_uint32be(struct mdchain *mdp, uint32_t *x);
int md_get_uint32le(struct mdchain *mdp, uint32_t *x);
-int md_get_uint64(struct mdchain *mdp, uint64_t *x);
int md_get_uint64be(struct mdchain *mdp, uint64_t *x);
int md_get_uint64le(struct mdchain *mdp, uint64_t *x);
-int md_get_mem(struct mdchain *mdp, caddr_t target, int size, int type);
+int md_get_mem(struct mdchain *mdp, void *vdst, int size, int type);
int md_get_mbuf(struct mdchain *mdp, int size, mblk_t **m);
-int md_get_uio(struct mdchain *mdp, uio_t *uiop, int size);
+int md_get_uio(struct mdchain *mdp, uio_t *uiop, size_t size);
/*
* Additions for Solaris to replace things that came from
diff --git a/usr/src/uts/common/netsmb/netbios.h b/usr/src/uts/common/netsmb/netbios.h
index b61f19c2dd..b9ebce1018 100644
--- a/usr/src/uts/common/netsmb/netbios.h
+++ b/usr/src/uts/common/netsmb/netbios.h
@@ -32,11 +32,14 @@
* $Id: netbios.h,v 1.5 2004/03/19 01:49:45 lindak Exp $
*/
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
#ifndef _NETSMB_NETBIOS_H_
#define _NETSMB_NETBIOS_H_
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifndef _NETINET_IN_H_
#include <netinet/in.h>
#endif
@@ -66,6 +69,8 @@
#define NB_ENCNAMELEN NB_NAMELEN * 2
#define NB_MAXLABLEN 63
+#define NB_MAXPKTLEN 0x1FFFF
+
#define NB_MINSALEN (sizeof (struct sockaddr_nb))
/*
diff --git a/usr/src/uts/common/netsmb/smb.h b/usr/src/uts/common/netsmb/smb.h
index 40c3522cfc..f0957634cb 100644
--- a/usr/src/uts/common/netsmb/smb.h
+++ b/usr/src/uts/common/netsmb/smb.h
@@ -45,8 +45,6 @@
#ifndef _NETSMB_SMB_H_
#define _NETSMB_SMB_H_
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* This file should be purely SMB protocol definition stuff.
* (Please don't make it a catch-all:)
@@ -81,7 +79,7 @@ enum smb_dialects {
#define SMB_SIGNATURE "\xFFSMB"
#define SMB_SIGLEN 4
#define SMB_HDRCMD(p) (*((uchar_t *)(p) + SMB_SIGLEN))
-#define SMB_HDRMID(p) (letohs(*(ushort_t *)((uchar_t *)(p) + 30)))
+#define SMB_HDRMID(p) (*(ushort_t *)((uchar_t *)(p) + 30))
#define SMB_HDRLEN 32
/*
* bits in the smb_flags field
@@ -751,26 +749,6 @@ typedef struct ntsid ntsid_t;
#define SMB_LOCKING_ANDX_LARGE_FILES 0x10
/*
- * Some names length limitations. Some of them aren't declared by specs,
- * but we need reasonable limits.
- */
-#define SMB_MAXSRVNAMELEN 15 /* NetBIOS limit */
-#define SMB_MAXUSERNAMELEN 128
-#define SMB_MAXPASSWORDLEN 128
-#define SMB_MAXSHARENAMELEN 128
-#define SMB_MAXPKTLEN 0x1FFFF
-#define SMB_MAXCHALLENGELEN 8
-#define SMB_MAXFNAMELEN 255 /* Keep in sync with MAXNAMLEN */
-
-#define SMB_RCNDELAY 2 /* seconds between reconnect attempts */
-/*
- * leave this zero - we can't ssecond guess server side effects of
- * duplicate ops, this isn't nfs!
- */
-#define SMBMAXRESTARTS 0
-#define SMB_MAXSETUPWORDS 3 /* max # of setup words in trans/t2 */
-
-/*
* Error classes
*/
#define SMBSUCCESS 0x00
diff --git a/usr/src/uts/common/netsmb/smb_dev.h b/usr/src/uts/common/netsmb/smb_dev.h
index ac09858c7d..8fee2bccf2 100644
--- a/usr/src/uts/common/netsmb/smb_dev.h
+++ b/usr/src/uts/common/netsmb/smb_dev.h
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -59,13 +59,9 @@
* any part of this user/kernel I/F changes.
*/
-#ifndef _KERNEL
#include <sys/types.h>
-#endif
-
#include <sys/socket_impl.h>
-#include <netsmb/smb.h>
-#include <netsmb/netbios.h>
+#include <netinet/in.h>
#define NSMB_NAME "nsmb"
@@ -75,35 +71,25 @@
* make them incompatible with an old driver.
*/
#define NSMB_VERMAJ 1
-#define NSMB_VERMIN 3600
+#define NSMB_VERMIN 3900
#define NSMB_VERSION (NSMB_VERMAJ * 100000 + NSMB_VERMIN)
-#define NSMB_VER_STR "1.36"
-
-#define NSMBFL_OPEN 0x0001
-#define NSMBFL_NEWVC 0x0002
/*
- * Hack-ish errno values we need to expose to the library.
+ * Some errno values we need to expose to the library.
+ * NB: these are also defined in the library smbfs_api.h
+ * to avoid exposing all of this stuff in that API.
+ *
* EBADRPC is used for message decoding errors.
* EAUTH is used for CIFS authentication errors.
*/
#ifndef EBADRPC
-#define EBADRPC 113 /* XXX */
+#define EBADRPC 113
#endif
#ifndef EAUTH
-#define EAUTH 114 /* XXX */
+#define EAUTH 114
#endif
/*
- * "Level" in the connection object hierarchy
- */
-#define SMBL_SM 0
-#define SMBL_VC 1
-#define SMBL_SHARE 2
-#define SMBL_NUM 3
-#define SMBL_NONE (-1)
-
-/*
* Upper/lower case options
*/
#define SMB_CS_NONE 0x0000
@@ -115,14 +101,6 @@
*/
#define SMBM_ANY_OWNER ((uid_t)-1)
#define SMBM_ANY_GROUP ((gid_t)-1)
-#define SMBM_MASK 0777
-#define SMBM_EXACT 010000 /* check for specified mode exactly */
-#ifdef _KERNEL
-/* In-kernel, we prefer the vnode.h names. */
-#define SMBM_READ VREAD /* (S_IRUSR) read conn attrs. */
-#define SMBM_WRITE VWRITE /* (S_IWUSR) modify conn attrs */
-#define SMBM_EXEC VEXEC /* (S_IXUSR) can send SMB requests */
-#endif
/*
* Option flags in smbioc_ossn.ioc_opt
@@ -140,14 +118,6 @@
#define SMBVOPT_SIGNING_REQUIRED 0x0200 /* signing required */
#define SMBVOPT_SIGNING_MASK 0x0300 /* all signing bits */
-/* XXX: How about a separate field for these? */
-#define SMBVOPT_MINAUTH 0x7000 /* min. auth. level (mask) */
-#define SMBVOPT_MINAUTH_NONE 0x0000 /* any authentication OK */
-#define SMBVOPT_MINAUTH_LM 0x1000 /* no plaintext passwords */
-#define SMBVOPT_MINAUTH_NTLM 0x2000 /* don't send LM reply */
-#define SMBVOPT_MINAUTH_NTLMV2 0x3000 /* don't fall back to NTLMv1 */
-#define SMBVOPT_MINAUTH_KERBEROS 0x4000 /* don't do NTLMv1 or v2 */
-
/*
* Option flags in smbioc_oshare.ioc_opt
* and sharespec.optflags
@@ -155,7 +125,27 @@
#define SMBSOPT_CREATE SMBVOPT_CREATE
#define SMBSOPT_PERMANENT SMBVOPT_PERMANENT
-#define MAX_STR_LEN 8 /* Maxilum length of the minor device name */
+/* All user and machine names. */
+#define SMBIOC_MAX_NAME 256
+
+/*
+ * Size of storage for p/w hashes.
+ * Also for SMBIOC_GETSSNKEY.
+ */
+#define SMBIOC_HASH_SZ 16
+
+/*
+ * network IO daemon states
+ * really connection states.
+ */
+enum smbiod_state {
+ SMBIOD_ST_IDLE = 0, /* no user requests enqueued yet */
+ SMBIOD_ST_RECONNECT, /* a [re]connect attempt is in progress */
+ SMBIOD_ST_RCFAILED, /* a reconnect attempt has failed */
+ SMBIOD_ST_VCACTIVE, /* session established */
+ SMBIOD_ST_DEAD /* connection gone, no IOD */
+};
+
/*
* We're now using structures that are invariant
@@ -187,98 +177,141 @@ typedef union lptr {
* Handy union of sockaddr types we use.
* Type discriminator is sa_family
*/
-union sockaddr_any {
- struct sockaddr sa;
- struct sockaddr_in in;
- struct sockaddr_nb nb;
+union smbioc_sockaddr {
+ struct sockaddr sa; /* generic */
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
};
+typedef union smbioc_sockaddr smbioc_sockaddr_t;
+/*
+ * This is what identifies a session.
+ */
+struct smbioc_ssn_ident {
+ smbioc_sockaddr_t id_srvaddr;
+ char id_domain[SMBIOC_MAX_NAME];
+ char id_user[SMBIOC_MAX_NAME];
+};
+typedef struct smbioc_ssn_ident smbioc_ssn_ident_t;
/*
- * SMBIOC_LOOKUP flags
+ * Flags for smbioc_ossn.ssn_opt
*/
#define SMBLK_CREATE SMBVOPT_CREATE
-#define DEF_SEC_TOKEN_LEN 2048
-
+/*
+ * Structure used with SMBIOC_SSN_FIND, _CREATE
+ */
struct smbioc_ossn {
- union sockaddr_any ioc_server;
- union sockaddr_any ioc_local;
- char ioc_localcs[16]; /* local charset */
- char ioc_servercs[16]; /* server charset */
- char ioc_srvname[SMB_MAXSRVNAMELEN + 1];
- char ioc_user[SMB_MAXUSERNAMELEN + 1];
- char ioc_workgroup[SMB_MAXUSERNAMELEN + 1];
- char ioc_password[SMB_MAXPASSWORDLEN + 1];
- int32_t ioc_opt;
- int32_t ioc_timeout; /* ignored?! XXX */
- int32_t ioc_retrycount; /* number of retries before giveup */
- uid_t ioc_owner; /* proposed owner */
- gid_t ioc_group; /* proposed group */
- mode_t ioc_mode; /* desired access mode */
- mode_t ioc_rights; /* SMBM_* */
- int32_t ioc_intoklen;
- int32_t ioc_outtoklen;
- /* copyout ends at this offset */
- lptr_t _ioc_intok;
- lptr_t _ioc_outtok;
+ uint32_t ssn_vopt; /* i.e. SMBVOPT_CREATE */
+ uint32_t ssn_owner; /* Unix owner (UID) */
+ smbioc_ssn_ident_t ssn_id;
+ char ssn_srvname[SMBIOC_MAX_NAME];
};
typedef struct smbioc_ossn smbioc_ossn_t;
-#define ioc_intok _ioc_intok.lp_ptr
-#define ioc_outtok _ioc_outtok.lp_ptr
-
+/* Convenience names for members under ssn_id */
+#define ssn_srvaddr ssn_id.id_srvaddr
+#define ssn_domain ssn_id.id_domain
+#define ssn_user ssn_id.id_user
+/*
+ * Structure used with SMBIOC_TREE_FIND, _CONNECT
+ */
+#define SMBIOC_STYPE_LEN 8
struct smbioc_oshare {
- char ioc_share[SMB_MAXSHARENAMELEN + 1];
- char ioc_password[SMB_MAXPASSWORDLEN + 1];
- int32_t ioc_opt;
- int32_t ioc_stype; /* share type */
- uid_t ioc_owner; /* proposed owner of share */
- gid_t ioc_group; /* proposed group of share */
- mode_t ioc_mode; /* desired access mode to share */
- mode_t ioc_rights; /* SMBM_* */
- /*
- * Hack: need the size of this to be 8-byte aligned
- * so that the ioc_ossn following it in smbioc_lookup
- * is correctly aligned...
- */
- int32_t ioc__pad;
+ uint32_t sh_pwlen;
+ char sh_name[SMBIOC_MAX_NAME];
+ char sh_pass[SMBIOC_MAX_NAME];
+ /* share types, in ASCII form, i.e. "A:", "IPC", ... */
+ char sh_type_req[SMBIOC_STYPE_LEN]; /* requested */
+ char sh_type_ret[SMBIOC_STYPE_LEN]; /* returned */
};
typedef struct smbioc_oshare smbioc_oshare_t;
+typedef struct smbioc_tcon {
+ int32_t tc_flags;
+ int32_t tc_opt;
+ smbioc_oshare_t tc_sh;
+} smbioc_tcon_t;
+
+
+/*
+ * Negotiated protocol parameters
+ */
+struct smb_sopt {
+ int16_t sv_proto; /* protocol dialect */
+ uchar_t sv_sm; /* security mode */
+ int16_t sv_tz; /* offset in min relative to UTC */
+ uint16_t sv_maxmux; /* max number of outstanding rq's */
+ uint16_t sv_maxvcs; /* max number of VCs */
+ uint16_t sv_rawmode;
+ uint32_t sv_maxtx; /* maximum transmit buf size */
+ uint32_t sv_maxraw; /* maximum raw-buffer size */
+ uint32_t sv_skey; /* session key */
+ uint32_t sv_caps; /* capabilites SMB_CAP_ */
+};
+typedef struct smb_sopt smb_sopt_t;
+
+/*
+ * State carried in/out of the driver by the IOD thread.
+ * Inside the driver, these are members of the "VC" object.
+ */
+struct smb_iods {
+ int32_t is_tran_fd; /* transport FD */
+ uint32_t is_vcflags; /* SMBV_... */
+ uint8_t is_hflags; /* SMB header flags */
+ uint16_t is_hflags2; /* SMB header flags2 */
+ uint16_t is_smbuid; /* SMB header UID */
+ uint16_t is_next_mid; /* SMB header MID */
+ uint32_t is_txmax; /* max tx/rx packet size */
+ uint32_t is_rwmax; /* max read/write data size */
+ uint32_t is_rxmax; /* max readx data size */
+ uint32_t is_wxmax; /* max writex data size */
+ uint8_t is_ssn_key[SMBIOC_HASH_SZ]; /* session key */
+ /* Signing state */
+ uint32_t is_next_seq; /* my next sequence number */
+ uint32_t is_u_maclen; /* MAC key length */
+ lptr_t is_u_mackey; /* user-space ptr! */
+};
+typedef struct smb_iods smb_iods_t;
+
+/*
+ * This is the operational state information passed
+ * in and out of the driver for SMBIOC_SSN_WORK
+ */
+struct smbioc_ssn_work {
+ smb_iods_t wk_iods;
+ smb_sopt_t wk_sopt;
+ int wk_out_state;
+};
+typedef struct smbioc_ssn_work smbioc_ssn_work_t;
+
+/*
+ * User-level SMB requests
+ */
+
+/*
+ * SMBIOC_REQUEST (simple SMB request)
+ */
typedef struct smbioc_rq {
uchar_t ioc_cmd;
- uchar_t ioc_twc; /* _twords */
- ushort_t ioc_tbc; /* _tbytes */
- int32_t ioc_rpbufsz; /* _rpbuf */
- uchar_t ioc__pad1;
- uchar_t ioc_rwc;
- ushort_t ioc_rbc;
- uchar_t ioc__pad2;
uint8_t ioc_errclass;
uint16_t ioc_serror;
uint32_t ioc_error;
- uint32_t ioc__pad3;
- /*
- * Copyout all but the pointers, which
- * we may have set to kernel memory.
- * See ..._COPYOUT_SIZE
- */
- lptr_t _ioc_twords;
- lptr_t _ioc_tbytes;
- lptr_t _ioc_rpbuf;
+ uint32_t ioc_tbufsz; /* transmit */
+ uint32_t ioc_rbufsz; /* receive */
+ lptr_t _ioc_tbuf;
+ lptr_t _ioc_rbuf;
} smbioc_rq_t;
-#define ioc_twords _ioc_twords.lp_ptr
-#define ioc_tbytes _ioc_tbytes.lp_ptr
-#define ioc_rpbuf _ioc_rpbuf.lp_ptr
-#define SMBIOC_RQ_COPYOUT_SIZE \
- (offsetof(smbioc_rq_t, _ioc_twords))
+#define ioc_tbuf _ioc_tbuf.lp_ptr
+#define ioc_rbuf _ioc_rbuf.lp_ptr
-#define SMBIOC_T2RQ_MAXNAME 128
+#define SMBIOC_T2RQ_MAXSETUP 4
+#define SMBIOC_T2RQ_MAXNAME 128
typedef struct smbioc_t2rq {
- uint16_t ioc_setup[SMB_MAXSETUPWORDS];
+ uint16_t ioc_setup[SMBIOC_T2RQ_MAXSETUP];
int32_t ioc_setupcnt;
char ioc_name[SMBIOC_T2RQ_MAXNAME];
ushort_t ioc_tparamcnt;
@@ -291,11 +324,6 @@ typedef struct smbioc_t2rq {
uint32_t ioc_error;
uint16_t ioc_rpflags2;
uint16_t ioc__pad2;
- /*
- * Copyout all but the pointers, which
- * we may have set to kernel memory.
- * See ..._COPYOUT_SIZE
- */
lptr_t _ioc_tparam;
lptr_t _ioc_tdata;
lptr_t _ioc_rparam;
@@ -305,43 +333,30 @@ typedef struct smbioc_t2rq {
#define ioc_tdata _ioc_tdata.lp_ptr
#define ioc_rparam _ioc_rparam.lp_ptr
#define ioc_rdata _ioc_rdata.lp_ptr
-#define SMBIOC_T2RQ_COPYOUT_SIZE \
- (offsetof(smbioc_t2rq_t, _ioc_tparam))
typedef struct smbioc_flags {
int32_t ioc_level; /* 0 - session, 1 - share */
- int32_t ioc_mask;
int32_t ioc_flags;
+ int32_t ioc_mask;
} smbioc_flags_t;
-typedef struct smbioc_lookup {
- int32_t ioc_level;
- int32_t ioc_flags;
- struct smbioc_oshare ioc_sh;
- struct smbioc_ossn ioc_ssn;
-} smbioc_lookup_t;
-#define SMBIOC_LOOK_COPYOUT_SIZE \
- (offsetof(smbioc_lookup_t, ioc_ssn._ioc_intok))
-
typedef struct smbioc_rw {
- uint16_t ioc_fh;
+ uint32_t ioc_fh;
uint32_t ioc_cnt;
lloff_t _ioc_offset;
lptr_t _ioc_base;
} smbioc_rw_t;
#define ioc_offset _ioc_offset._f
#define ioc_base _ioc_base.lp_ptr
-#define SMBIOC_RW_COPYOUT_SIZE \
- (offsetof(smbioc_rw_t, _ioc_base))
/* Password Keychain (PK) support. */
-#define SMBIOC_PK_MAXLEN 255
typedef struct smbioc_pk {
uid_t pk_uid; /* UID for PAM use */
- char pk_dom[SMBIOC_PK_MAXLEN+1]; /* CIFS domain name */
- char pk_usr[SMBIOC_PK_MAXLEN+1]; /* CIFS user name */
- char pk_pass[SMBIOC_PK_MAXLEN+1]; /* CIFS password */
+ char pk_dom[SMBIOC_MAX_NAME]; /* CIFS domain name */
+ char pk_usr[SMBIOC_MAX_NAME]; /* CIFS user name */
+ uchar_t pk_lmhash[SMBIOC_HASH_SZ]; /* LanMan p/w hash */
+ uchar_t pk_nthash[SMBIOC_HASH_SZ]; /* NTLM p/w hash */
} smbioc_pk_t;
@@ -357,18 +372,29 @@ typedef struct smbioc_pk {
*/
#define SMBIOC_BASE ((('n' << 8) | 's') << 8)
typedef enum nsmb_ioc {
- SMBIOC_GETVERS = SMBIOC_BASE,
- SMBIOC_REQUEST,
- SMBIOC_T2RQ,
- SMBIOC_LOOKUP,
- SMBIOC_READ,
- SMBIOC_WRITE,
- SMBIOC_FINDVC,
- SMBIOC_NEGOTIATE,
- SMBIOC_SSNSETUP,
- SMBIOC_TCON,
- SMBIOC_TDIS,
- SMBIOC_FLAGS2,
+ SMBIOC_GETVERS = SMBIOC_BASE, /* keep first */
+ SMBIOC_FLAGS2, /* get hflags2 */
+ SMBIOC_GETSSNKEY, /* get SMB session key */
+
+ SMBIOC_REQUEST, /* simple request */
+ SMBIOC_T2RQ, /* trans2 request */
+ SMBIOC_READ, /* read (pipe) */
+ SMBIOC_WRITE, /* write (pipe) */
+
+ SMBIOC_SSN_CREATE,
+ SMBIOC_SSN_FIND,
+ SMBIOC_SSN_KILL, /* force disconnect */
+ SMBIOC_SSN_RELE, /* drop our reference */
+
+ SMBIOC_TREE_CONNECT, /* create and connect */
+ SMBIOC_TREE_FIND,
+ SMBIOC_TREE_KILL,
+ SMBIOC_TREE_RELE,
+
+ SMBIOC_IOD_WORK, /* work on session requests */
+ SMBIOC_IOD_IDLE, /* wait for requests on this session */
+ SMBIOC_IOD_RCFAIL, /* notify that reconnect failed */
+
/* Password Keychain (PK) support. */
SMBIOC_PK_ADD, /* Add/Modify a password entry */
SMBIOC_PK_CHK, /* Check for a password entry */
@@ -377,52 +403,4 @@ typedef enum nsmb_ioc {
SMBIOC_PK_DEL_EVERYONE /* all owned by everyone */
} nsmb_ioc_t;
-#ifdef _KERNEL
-#include <sys/dditypes.h> /* for dev_info_t */
-
-#define SMBST_CONNECTED 1
-
-/* Size of storage for p/w hashes. */
-#define SMB_PWH_MAX 24
-
-extern const uint32_t nsmb_version;
-
-struct smb_cred;
-struct smb_share;
-struct smb_vc;
-
-typedef struct smb_dev {
- int sd_opened; /* Opened or not */
- int sd_level; /* Future use */
- struct smb_vc *sd_vc; /* Reference to VC */
- struct smb_share *sd_share; /* Reference to share if any */
- int sd_poll; /* Future use */
- int sd_seq; /* Kind of minor number/instance no */
- int sd_flags; /* State of connection */
- zoneid_t zoneid; /* Zone id */
- dev_info_t *smb_dip; /* ptr to dev_info node */
- void *sd_devfs; /* Dont know how to use this. but */
- struct cred *smb_cred; /* per dev credentails. Future use */
-} smb_dev_t;
-
-/*
- * Compound user interface
- */
-int smb_usr_findvc(struct smbioc_lookup *dp, struct smb_cred *scred,
- struct smb_vc **vcpp);
-int smb_usr_negotiate(struct smbioc_lookup *dp, struct smb_cred *scred,
- struct smb_vc **vcpp);
-int smb_usr_ssnsetup(struct smbioc_lookup *dp, struct smb_cred *scred,
- struct smb_vc *vcp);
-int smb_usr_tcon(struct smbioc_lookup *dp, struct smb_cred *scred,
- struct smb_vc *vcp, struct smb_share **sspp);
-int smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *data,
- struct smb_cred *scred);
-int smb_usr_t2request(struct smb_share *ssp, struct smbioc_t2rq *data,
- struct smb_cred *scred);
-int smb_usr_rw(struct smb_share *ssp, smbioc_rw_t *dp,
- int cmd, struct smb_cred *scred);
-int smb_dev2share(int fd, struct smb_share **sspp);
-
-#endif /* _KERNEL */
#endif /* _NETSMB_DEV_H_ */
diff --git a/usr/src/uts/intel/nsmb/Makefile b/usr/src/uts/intel/nsmb/Makefile
index 3b8d751ac2..a55850a141 100644
--- a/usr/src/uts/intel/nsmb/Makefile
+++ b/usr/src/uts/intel/nsmb/Makefile
@@ -21,10 +21,10 @@
#
# uts/intel/nsmb/Makefile
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
+
#
# intel architecture dependent
#
@@ -70,6 +70,8 @@ LDFLAGS += -dy -Ncrypto/md4 -Ncrypto/md5 -Nmisc/tlimod
LINTTAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2
LINTTAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2
+# Until CR 4994570 is fixed...
+LINTTAGS += -erroff=E_BAD_FORMAT_ARG_TYPE2
#
# Default build targets.
diff --git a/usr/src/uts/intel/nsmb/ioc_check.ref b/usr/src/uts/intel/nsmb/ioc_check.ref
index ead69ec44f..76660e2ef5 100644
--- a/usr/src/uts/intel/nsmb/ioc_check.ref
+++ b/usr/src/uts/intel/nsmb/ioc_check.ref
@@ -1,56 +1,62 @@
-#define SIZEOF_SOCKADDR_ANY 0x18
-#define SIZEOF_SOCKADDR_IN 0x10
-#define SIZEOF_SOCKADDR_NB 0x18
-#define SIZEOF_SMBIOC_OSSN 0x218
-#define IOC_SERVER 0x0
-#define IOC_LOCAL 0x18
-#define IOC_LOCALCS 0x30
-#define IOC_LOCALCS_INCR 0x1
-#define IOC_SERVERCS 0x40
-#define IOC_SERVERCS_INCR 0x1
-#define IOC_SRVNAME 0x50
-#define IOC_SRVNAME_INCR 0x1
-#define IOC_USER 0x60
-#define IOC_USER_INCR 0x1
-#define IOC_WORKGROUP 0xe1
-#define IOC_WORKGROUP_INCR 0x1
-#define IOC_SSN_PASSWD 0x162
-#define IOC_SSN_PASSWD_INCR 0x1
-#define IOC_SSN_OPT 0x1e4
-#define IOC_TIMEOUT 0x1e8
-#define IOC_RETRYCOUNT 0x1ec
-#define IOC_SSN_OWNER 0x1f0
-#define IOC_SSN_GROUP 0x1f4
-#define IOC_SSN_MODE 0x1f8
-#define IOC_SSN_RIGHTS 0x1fc
-#define IOC_INTOKLEN 0x200
-#define IOC_OUTTOKLEN 0x204
-#define _IOC_INTOK 0x208
-#define _IOC_OUTTOK 0x210
-#define SIZEOF_SMBIOC_OSHARE 0x120
-#define IOC_SHARE 0x0
-#define IOC_SHARE_INCR 0x1
-#define IOC_SH_PASSWD 0x81
-#define IOC_SH_PASSWD_INCR 0x1
-#define IOC_SH_OPT 0x104
-#define IOC_STYPE 0x108
-#define IOC_SH_OWNER 0x10c
-#define IOC_SH_GROUP 0x110
-#define IOC_SH_MODE 0x114
-#define IOC_SH_RIGHTS 0x118
-#define SIZEOF_SMBIOC_RQ 0x30
+#define ID_SRVADDR 0x0
+#define ID_DOMAIN 0x20
+#define ID_DOMAIN_INCR 0x1
+#define ID_USER 0x120
+#define ID_USER_INCR 0x1
+#define SSN_VOPT 0x0
+#define SSN_OWNER 0x4
+#define SSN_ID 0x8
+#define SSN_SRVNAME 0x228
+#define SSN_SRVNAME_INCR 0x1
+#define SH_PWLEN 0x0
+#define SH_NAME 0x4
+#define SH_NAME_INCR 0x1
+#define SH_PASS 0x104
+#define SH_PASS_INCR 0x1
+#define SH_TYPE_REQ 0x204
+#define SH_TYPE_REQ_INCR 0x1
+#define SH_TYPE_RET 0x20c
+#define SH_TYPE_RET_INCR 0x1
+#define TC_FLAGS 0x0
+#define TC_OPT 0x4
+#define TC_SH 0x8
+#define SV_PROTO 0x0
+#define SV_SM 0x2
+#define SV_TZ 0x4
+#define SV_MAXMUX 0x6
+#define SV_MAXVCS 0x8
+#define SV_RAWMODE 0xa
+#define SV_MAXTX 0xc
+#define SV_MAXRAW 0x10
+#define SV_SKEY 0x14
+#define SV_CAPS 0x18
+#define IS_TRAN_FD 0x0
+#define IS_VCFLAGS 0x4
+#define IS_HFLAGS 0x8
+#define IS_HFLAGS2 0xa
+#define IS_SMBUID 0xc
+#define IS_NEXT_MID 0xe
+#define IS_TXMAX 0x10
+#define IS_RWMAX 0x14
+#define IS_RXMAX 0x18
+#define IS_WXMAX 0x1c
+#define IS_SSN_KEY 0x20
+#define IS_SSN_KEY_INCR 0x1
+#define IS_NEXT_SEQ 0x30
+#define IS_U_MACLEN 0x34
+#define IS_U_MACKEY 0x38
+#define WK_IODS 0x0
+#define WK_SOPT 0x40
+#define WK_OUT_STATE 0x5c
+#define SIZEOF_SMBIOC_RQ 0x20
#define IOC_CMD 0x0
-#define IOC_TWC 0x1
-#define IOC_TBC 0x2
-#define IOC_RPBUFSZ 0x4
-#define IOC_RWC 0x9
-#define IOC_RBC 0xa
-#define IOC_RQ_ERRCLASS 0xd
-#define IOC_RQ_SERROR 0xe
-#define IOC_RQ_ERROR 0x10
-#define _IOC_TWORDS 0x18
-#define _IOC_TBYTES 0x20
-#define _IOC_RPBUF 0x28
+#define IOC_RQ_ERRCLASS 0x1
+#define IOC_RQ_SERROR 0x2
+#define IOC_RQ_ERROR 0x4
+#define IOC_TBUFSZ 0x8
+#define IOC_RBUFSZ 0xc
+#define _IOC_TBUF 0x10
+#define _IOC_RBUF 0x18
#define SIZEOF_SMBIOC_T2RQ 0xc0
#define IOC_SETUP 0x0
#define IOC_SETUP_INCR 0x2
@@ -71,22 +77,20 @@
#define _IOC_RDATA 0xb8
#define SIZEOF_SMBIOC_FLAGS 0xc
#define IOC_LEVEL 0x0
-#define IOC_MASK 0x4
-#define IOC_FLAGS 0x8
-#define SIZEOF_SMBIOC_LOOKUP 0x340
-#define IOC_LOOK_LEVEL 0x0
-#define IOC_LOOK_FLAGS 0x4
-#define IOC_SH 0x8
-#define IOC_SSN 0x128
+#define IOC_MASK 0x8
+#define IOC_FLAGS 0x4
#define SIZEOF_SMBIOC_RW 0x18
#define IOC_FH 0x0
#define IOC_CNT 0x4
#define _IOC_OFFSET 0x8
#define _IOC_BASE 0x10
-#define SIZEOF_SMBIOC_PK 0x304
+#define SIZEOF_SMBIOC_PK 0x224
+#define PK_UID 0x0
#define PK_DOM 0x4
#define PK_DOM_INCR 0x1
#define PK_USR 0x104
#define PK_USR_INCR 0x1
-#define PK_PASS 0x204
-#define PK_PASS_INCR 0x1
+#define PK_LMHASH 0x204
+#define PK_LMHASH_INCR 0x1
+#define PK_NTHASH 0x214
+#define PK_NTHASH_INCR 0x1
diff --git a/usr/src/uts/sparc/nsmb/Makefile b/usr/src/uts/sparc/nsmb/Makefile
index 85c05e9fcb..09b2bc72b9 100644
--- a/usr/src/uts/sparc/nsmb/Makefile
+++ b/usr/src/uts/sparc/nsmb/Makefile
@@ -21,10 +21,10 @@
#
# uts/sparc/nsmb/Makefile
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
+
#
# sparc architecture dependent
#
@@ -94,6 +94,8 @@ LDFLAGS += -dy -Ncrypto/md4 -Ncrypto/md5 -Nmisc/tlimod
LINTTAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2
LINTTAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2
+# Until CR 4994570 is fixed...
+LINTTAGS += -erroff=E_BAD_FORMAT_ARG_TYPE2
#
# Default build targets.
diff --git a/usr/src/uts/sparc/nsmb/ioc_check.ref b/usr/src/uts/sparc/nsmb/ioc_check.ref
index ead69ec44f..76660e2ef5 100644
--- a/usr/src/uts/sparc/nsmb/ioc_check.ref
+++ b/usr/src/uts/sparc/nsmb/ioc_check.ref
@@ -1,56 +1,62 @@
-#define SIZEOF_SOCKADDR_ANY 0x18
-#define SIZEOF_SOCKADDR_IN 0x10
-#define SIZEOF_SOCKADDR_NB 0x18
-#define SIZEOF_SMBIOC_OSSN 0x218
-#define IOC_SERVER 0x0
-#define IOC_LOCAL 0x18
-#define IOC_LOCALCS 0x30
-#define IOC_LOCALCS_INCR 0x1
-#define IOC_SERVERCS 0x40
-#define IOC_SERVERCS_INCR 0x1
-#define IOC_SRVNAME 0x50
-#define IOC_SRVNAME_INCR 0x1
-#define IOC_USER 0x60
-#define IOC_USER_INCR 0x1
-#define IOC_WORKGROUP 0xe1
-#define IOC_WORKGROUP_INCR 0x1
-#define IOC_SSN_PASSWD 0x162
-#define IOC_SSN_PASSWD_INCR 0x1
-#define IOC_SSN_OPT 0x1e4
-#define IOC_TIMEOUT 0x1e8
-#define IOC_RETRYCOUNT 0x1ec
-#define IOC_SSN_OWNER 0x1f0
-#define IOC_SSN_GROUP 0x1f4
-#define IOC_SSN_MODE 0x1f8
-#define IOC_SSN_RIGHTS 0x1fc
-#define IOC_INTOKLEN 0x200
-#define IOC_OUTTOKLEN 0x204
-#define _IOC_INTOK 0x208
-#define _IOC_OUTTOK 0x210
-#define SIZEOF_SMBIOC_OSHARE 0x120
-#define IOC_SHARE 0x0
-#define IOC_SHARE_INCR 0x1
-#define IOC_SH_PASSWD 0x81
-#define IOC_SH_PASSWD_INCR 0x1
-#define IOC_SH_OPT 0x104
-#define IOC_STYPE 0x108
-#define IOC_SH_OWNER 0x10c
-#define IOC_SH_GROUP 0x110
-#define IOC_SH_MODE 0x114
-#define IOC_SH_RIGHTS 0x118
-#define SIZEOF_SMBIOC_RQ 0x30
+#define ID_SRVADDR 0x0
+#define ID_DOMAIN 0x20
+#define ID_DOMAIN_INCR 0x1
+#define ID_USER 0x120
+#define ID_USER_INCR 0x1
+#define SSN_VOPT 0x0
+#define SSN_OWNER 0x4
+#define SSN_ID 0x8
+#define SSN_SRVNAME 0x228
+#define SSN_SRVNAME_INCR 0x1
+#define SH_PWLEN 0x0
+#define SH_NAME 0x4
+#define SH_NAME_INCR 0x1
+#define SH_PASS 0x104
+#define SH_PASS_INCR 0x1
+#define SH_TYPE_REQ 0x204
+#define SH_TYPE_REQ_INCR 0x1
+#define SH_TYPE_RET 0x20c
+#define SH_TYPE_RET_INCR 0x1
+#define TC_FLAGS 0x0
+#define TC_OPT 0x4
+#define TC_SH 0x8
+#define SV_PROTO 0x0
+#define SV_SM 0x2
+#define SV_TZ 0x4
+#define SV_MAXMUX 0x6
+#define SV_MAXVCS 0x8
+#define SV_RAWMODE 0xa
+#define SV_MAXTX 0xc
+#define SV_MAXRAW 0x10
+#define SV_SKEY 0x14
+#define SV_CAPS 0x18
+#define IS_TRAN_FD 0x0
+#define IS_VCFLAGS 0x4
+#define IS_HFLAGS 0x8
+#define IS_HFLAGS2 0xa
+#define IS_SMBUID 0xc
+#define IS_NEXT_MID 0xe
+#define IS_TXMAX 0x10
+#define IS_RWMAX 0x14
+#define IS_RXMAX 0x18
+#define IS_WXMAX 0x1c
+#define IS_SSN_KEY 0x20
+#define IS_SSN_KEY_INCR 0x1
+#define IS_NEXT_SEQ 0x30
+#define IS_U_MACLEN 0x34
+#define IS_U_MACKEY 0x38
+#define WK_IODS 0x0
+#define WK_SOPT 0x40
+#define WK_OUT_STATE 0x5c
+#define SIZEOF_SMBIOC_RQ 0x20
#define IOC_CMD 0x0
-#define IOC_TWC 0x1
-#define IOC_TBC 0x2
-#define IOC_RPBUFSZ 0x4
-#define IOC_RWC 0x9
-#define IOC_RBC 0xa
-#define IOC_RQ_ERRCLASS 0xd
-#define IOC_RQ_SERROR 0xe
-#define IOC_RQ_ERROR 0x10
-#define _IOC_TWORDS 0x18
-#define _IOC_TBYTES 0x20
-#define _IOC_RPBUF 0x28
+#define IOC_RQ_ERRCLASS 0x1
+#define IOC_RQ_SERROR 0x2
+#define IOC_RQ_ERROR 0x4
+#define IOC_TBUFSZ 0x8
+#define IOC_RBUFSZ 0xc
+#define _IOC_TBUF 0x10
+#define _IOC_RBUF 0x18
#define SIZEOF_SMBIOC_T2RQ 0xc0
#define IOC_SETUP 0x0
#define IOC_SETUP_INCR 0x2
@@ -71,22 +77,20 @@
#define _IOC_RDATA 0xb8
#define SIZEOF_SMBIOC_FLAGS 0xc
#define IOC_LEVEL 0x0
-#define IOC_MASK 0x4
-#define IOC_FLAGS 0x8
-#define SIZEOF_SMBIOC_LOOKUP 0x340
-#define IOC_LOOK_LEVEL 0x0
-#define IOC_LOOK_FLAGS 0x4
-#define IOC_SH 0x8
-#define IOC_SSN 0x128
+#define IOC_MASK 0x8
+#define IOC_FLAGS 0x4
#define SIZEOF_SMBIOC_RW 0x18
#define IOC_FH 0x0
#define IOC_CNT 0x4
#define _IOC_OFFSET 0x8
#define _IOC_BASE 0x10
-#define SIZEOF_SMBIOC_PK 0x304
+#define SIZEOF_SMBIOC_PK 0x224
+#define PK_UID 0x0
#define PK_DOM 0x4
#define PK_DOM_INCR 0x1
#define PK_USR 0x104
#define PK_USR_INCR 0x1
-#define PK_PASS 0x204
-#define PK_PASS_INCR 0x1
+#define PK_LMHASH 0x204
+#define PK_LMHASH_INCR 0x1
+#define PK_NTHASH 0x214
+#define PK_NTHASH_INCR 0x1