summaryrefslogtreecommitdiff
path: root/usr/src/lib/libsmbfs
diff options
context:
space:
mode:
authorthurlow <none@none>2008-02-13 19:51:22 -0800
committerthurlow <none@none>2008-02-13 19:51:22 -0800
commit4bff34e37def8a90f9194d81bc345c52ba20086a (patch)
tree7bf2710d9da099e3b07fea38e12788bfd565f3c5 /usr/src/lib/libsmbfs
parenta916d99c7b27a531bf37c57f83b0b74120fd05bb (diff)
downloadillumos-joyent-4bff34e37def8a90f9194d81bc345c52ba20086a.tar.gz
PSARC 2005/695 CIFS Client on Solaris
PSARC 2007/303 pam_smb_login PSARC 2008/073 CIFS Client on Solaris - Updates 6651904 CIFS Client - PSARC 2005/695
Diffstat (limited to 'usr/src/lib/libsmbfs')
-rw-r--r--usr/src/lib/libsmbfs/Makefile72
-rw-r--r--usr/src/lib/libsmbfs/Makefile.com98
-rw-r--r--usr/src/lib/libsmbfs/amd64/Makefile31
-rw-r--r--usr/src/lib/libsmbfs/cflib.h95
-rw-r--r--usr/src/lib/libsmbfs/i386/Makefile30
-rw-r--r--usr/src/lib/libsmbfs/netsmb/nb_lib.h177
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smb_keychain.h82
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smb_lib.h345
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smb_netshareenum.h18
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smb_rap.h81
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple23
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip1
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov29
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip1
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd432
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip1
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft10
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip1
-rw-r--r--usr/src/lib/libsmbfs/smb/cfopt.c125
-rw-r--r--usr/src/lib/libsmbfs/smb/charsets.c385
-rw-r--r--usr/src/lib/libsmbfs/smb/charsets.h48
-rw-r--r--usr/src/lib/libsmbfs/smb/ctx.c2140
-rw-r--r--usr/src/lib/libsmbfs/smb/derparse.c750
-rw-r--r--usr/src/lib/libsmbfs/smb/derparse.h196
-rw-r--r--usr/src/lib/libsmbfs/smb/file.c95
-rw-r--r--usr/src/lib/libsmbfs/smb/keychain.c199
-rw-r--r--usr/src/lib/libsmbfs/smb/llib-lsmbfs32
-rw-r--r--usr/src/lib/libsmbfs/smb/mapfile-vers72
-rw-r--r--usr/src/lib/libsmbfs/smb/mbuf.c476
-rw-r--r--usr/src/lib/libsmbfs/smb/nb.c265
-rw-r--r--usr/src/lib/libsmbfs/smb/nb_name.c273
-rw-r--r--usr/src/lib/libsmbfs/smb/nb_net.c234
-rw-r--r--usr/src/lib/libsmbfs/smb/nbns_rq.c581
-rw-r--r--usr/src/lib/libsmbfs/smb/netshareenum.c349
-rw-r--r--usr/src/lib/libsmbfs/smb/nls.c179
-rw-r--r--usr/src/lib/libsmbfs/smb/print.c96
-rw-r--r--usr/src/lib/libsmbfs/smb/queue.h109
-rw-r--r--usr/src/lib/libsmbfs/smb/rap.c468
-rw-r--r--usr/src/lib/libsmbfs/smb/rcfile.c644
-rw-r--r--usr/src/lib/libsmbfs/smb/rcfile_priv.h21
-rw-r--r--usr/src/lib/libsmbfs/smb/rq.c213
-rw-r--r--usr/src/lib/libsmbfs/smb/spnego.c797
-rw-r--r--usr/src/lib/libsmbfs/smb/spnego.h244
-rw-r--r--usr/src/lib/libsmbfs/smb/spnegoparse.c1883
-rw-r--r--usr/src/lib/libsmbfs/smb/spnegoparse.h170
-rw-r--r--usr/src/lib/libsmbfs/smb/subr.c394
-rw-r--r--usr/src/lib/libsmbfs/smb/ui-sun.c155
-rw-r--r--usr/src/lib/libsmbfs/sparc/Makefile30
-rw-r--r--usr/src/lib/libsmbfs/sparcv9/Makefile31
49 files changed, 12781 insertions, 0 deletions
diff --git a/usr/src/lib/libsmbfs/Makefile b/usr/src/lib/libsmbfs/Makefile
new file mode 100644
index 0000000000..0ab1f6c137
--- /dev/null
+++ b/usr/src/lib/libsmbfs/Makefile
@@ -0,0 +1,72 @@
+#
+# 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 2008 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
+
+# ISA targets
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+# conditional assignments
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+
+POFILE = libsmbfs.po
+
+.KEEP_STATE:
+
+all install clean clobber lint: $(SUBDIRS)
+
+include $(SRC)/Makefile.msg.targ
+
+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
+
+_msg: $(MSGDOMAINPOFILE)
+
+$(MSGDOMAINPOFILE): $(POFILE)
+
+$(POFILE): $(MSGFILES)
+ $(BUILDPO.msgfiles)
+
+install: $(ROOTLIBS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libsmbfs/Makefile.com b/usr/src/lib/libsmbfs/Makefile.com
new file mode 100644
index 0000000000..76e2eac287
--- /dev/null
+++ b/usr/src/lib/libsmbfs/Makefile.com
@@ -0,0 +1,98 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsmbfs/Makefile.com
+
+LIBRARY= libsmbfs.a
+VERS= .1
+
+# leaving out: kiconv.o
+
+OBJECTS=\
+ charsets.o \
+ cfopt.o \
+ ctx.o \
+ derparse.o \
+ file.o \
+ keychain.o \
+ mbuf.o \
+ nb.o \
+ nb_name.o \
+ nb_net.o \
+ nbns_rq.o \
+ netshareenum.o \
+ nls.o \
+ print.o \
+ rap.o \
+ rcfile.o \
+ rq.o \
+ spnego.o \
+ spnegoparse.o \
+ subr.o \
+ ui-sun.o
+
+include $(SRC)/lib/Makefile.lib
+
+LIBS = $(DYNLIB) $(LINTLIB)
+
+SRCDIR= ../smb
+
+SRCS= $(OBJECTS:%.o=../smb/%.c)
+
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
+
+C99MODE= $(C99_ENABLE)
+
+LDLIBS += -lsocket -lnsl -lc -lkrb5
+
+# normal warnings...
+CFLAGS += $(CCVERBOSE)
+
+CPPFLAGS += -D__EXTENSIONS__ -D_REENTRANT -DMIA \
+ -I$(SRCDIR) -I.. -I$(SRC)/uts/common
+
+# uncomment these if you want to use dbx
+#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:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/libsmbfs/amd64/Makefile b/usr/src/lib/libsmbfs/amd64/Makefile
new file mode 100644
index 0000000000..7443ee1806
--- /dev/null
+++ b/usr/src/lib/libsmbfs/amd64/Makefile
@@ -0,0 +1,31 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/libsmbfs/cflib.h b/usr/src/lib/libsmbfs/cflib.h
new file mode 100644
index 0000000000..0b6941931e
--- /dev/null
+++ b/usr/src/lib/libsmbfs/cflib.h
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ *
+ * $Id: cflib.h,v 1.1.1.1 2001/06/09 00:28:11 zarzycki Exp $
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifndef _CFLIB_H_
+#define _CFLIB_H_
+
+struct rcfile;
+
+/*
+ * A unified options parser
+ */
+enum opt_argtype {OPTARG_STR, OPTARG_INT, OPTARG_BOOL};
+
+struct opt_args;
+
+typedef int opt_callback_t (struct opt_args *);
+
+#define OPTFL_NONE 0x0000
+#define OPTFL_HAVEMIN 0x0001
+#define OPTFL_HAVEMAX 0x0002
+#define OPTFL_MINMAX NAFL_HAVEMIN | NAFL_HAVEMAX
+
+struct opt_args {
+ enum opt_argtype type;
+ int opt; /* command line option */
+ char *name; /* rc file equiv */
+ int flag; /* OPTFL_* */
+ int ival; /* int/bool values, or max len for str value */
+ char *str; /* string value */
+ int min; /* min for ival */
+ int max; /* max for ival */
+ opt_callback_t *fn; /* call back to validate */
+};
+typedef struct opt_args opt_args_t;
+
+extern int cf_opterr, cf_optind, cf_optopt, cf_optreset;
+extern const char *cf_optarg;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int opt_args_parse(struct rcfile *, struct opt_args *, const char *,
+ opt_callback_t *);
+int opt_args_parseopt(struct opt_args *, int, char *, opt_callback_t *);
+
+int cf_getopt(int, char * const *, const char *);
+
+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 *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CFLIB_H_ */
diff --git a/usr/src/lib/libsmbfs/i386/Makefile b/usr/src/lib/libsmbfs/i386/Makefile
new file mode 100644
index 0000000000..23b74c3928
--- /dev/null
+++ b/usr/src/lib/libsmbfs/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libsmbfs/netsmb/nb_lib.h b/usr/src/lib/libsmbfs/netsmb/nb_lib.h
new file mode 100644
index 0000000000..1c4100e17a
--- /dev/null
+++ b/usr/src/lib/libsmbfs/netsmb/nb_lib.h
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ *
+ * $Id: nb_lib.h,v 1.4 2004/12/11 05:23:58 lindak Exp $
+ */
+
+#ifndef _NETSMB_NB_LIB_H_
+#define _NETSMB_NB_LIB_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Error codes
+ */
+#define NBERR_INVALIDFORMAT 0x0001
+#define NBERR_SRVFAILURE 0x0002
+#define NBERR_NAMENOTFOUND 0x0003
+#define NBERR_IMP 0x0004
+#define NBERR_REFUSED 0x0005
+#define NBERR_ACTIVE 0x0006
+#define NBERR_HOSTNOTFOUND 0x0101
+#define NBERR_TOOMANYREDIRECTS 0x0102
+#define NBERR_INVALIDRESPONSE 0x0103
+#define NBERR_NAMETOOLONG 0x0104
+#define NBERR_NOBCASTIFS 0x0105
+#define NBERR_MAX 0x0106
+#define NBERROR(e) ((e) | SMB_NB_ERROR)
+
+#define NBCF_RESOLVED 0x0001
+#define NBCF_NS_ENABLE 0x0002 /* any NetBIOS lookup */
+#define NBCF_BC_ENABLE 0x0004 /* lookup via broadcast */
+
+/*
+ * nb environment
+ */
+struct nb_ctx {
+ int nb_flags;
+ int nb_timo;
+ char *nb_scope; /* NetBIOS scope */
+ in_addr_t nb_wins1; /* primary WINS */
+ in_addr_t nb_wins2; /* secondary WINS (unused now) */
+ struct sockaddr_in nb_lastns; /* see cmd:lookup.c */
+};
+typedef struct nb_ctx nb_ctx_t;
+
+/*
+ * resource record
+ */
+struct nbns_rr {
+ uchar_t *rr_name; /* compressed NETBIOS name */
+ uint16_t rr_type;
+ uint16_t rr_class;
+ uint32_t rr_ttl;
+ uint16_t rr_rdlength;
+ uchar_t *rr_data;
+};
+typedef struct nbns_rr nfns_rr_t;
+
+/*
+ * NetBIOS name return
+ */
+struct nbns_nr {
+ char ns_name[NB_NAMELEN];
+ uint16_t ns_flags;
+};
+typedef struct nbns_nr nbns_nr_t;
+
+#define NBRQF_POINT 0x0000
+#define NBRQF_BROADCAST 0x0001
+
+#define NBNS_GROUPFLG 0x8000
+
+/*
+ * nbns request
+ */
+struct nbns_rq {
+ int nr_opcode;
+ int nr_nmflags;
+ int nr_rcode;
+ int nr_qdcount;
+ int nr_ancount;
+ int nr_nscount;
+ int nr_arcount;
+ struct nb_name *nr_qdname;
+ uint16_t nr_qdtype;
+ uint16_t nr_qdclass;
+ struct in_addr nr_dest; /* receiver of query */
+ struct sockaddr_in nr_sender; /* sender of response */
+ int nr_rpnmflags;
+ int nr_rprcode;
+ uint16_t nr_rpancount;
+ uint16_t nr_rpnscount;
+ uint16_t nr_rparcount;
+ uint16_t nr_trnid;
+ struct nb_ctx *nr_nbd;
+ struct mbdata nr_rq;
+ struct mbdata nr_rp;
+ struct nb_ifdesc *nr_if;
+ int nr_flags;
+ int nr_fd;
+ int nr_maxretry;
+};
+typedef struct nbns_rq nbns_rq_t;
+
+struct nb_ifdesc {
+ int id_flags;
+ struct in_addr id_addr;
+ struct in_addr id_mask;
+ char id_name[16]; /* actually IFNAMSIZ */
+ struct nb_ifdesc *id_next;
+};
+typedef struct nb_ifdesc nb_ifdesc_t;
+
+struct sockaddr;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+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_encname_len(const uchar_t *);
+
+int nb_snballoc(int namelen, struct sockaddr_nb **);
+void nb_snbfree(struct sockaddr *);
+int nb_sockaddr(struct sockaddr *, struct nb_name *, struct sockaddr_nb **);
+
+int nb_resolvehost_in(const char *, struct sockaddr **);
+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 nb_enum_if(struct nb_ifdesc **);
+
+const char *nb_strerror(int error);
+
+int nb_ctx_create(struct nb_ctx **);
+void nb_ctx_done(struct nb_ctx *);
+int nb_ctx_setns(struct nb_ctx *, const char *);
+int nb_ctx_setscope(struct nb_ctx *, const char *);
+int nb_ctx_resolve(struct nb_ctx *);
+int nb_ctx_readrcsection(struct rcfile *, struct nb_ctx *, const char *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_NETSMB_NB_LIB_H_ */
diff --git a/usr/src/lib/libsmbfs/netsmb/smb_keychain.h b/usr/src/lib/libsmbfs/netsmb/smb_keychain.h
new file mode 100644
index 0000000000..9e4113a225
--- /dev/null
+++ b/usr/src/lib/libsmbfs/netsmb/smb_keychain.h
@@ -0,0 +1,82 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMB_KEYCHAIN_H
+#define _SMB_KEYCHAIN_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * External interface to the libsmbfs/netsmb keychain
+ * storage mechanism. This interface is consumed by
+ * the "smbutil" commands: login, logout, ...
+ * and by the SMBFS PAM module.
+ */
+
+#define SMB_KEYCHAIN_SUCCESS 0
+#define SMB_KEYCHAIN_BADPASSWD 300
+#define SMB_KEYCHAIN_BADDOMAIN 301
+#define SMB_KEYCHAIN_BADUSER 302
+#define SMB_KEYCHAIN_NODRIVER 303
+#define SMB_KEYCHAIN_UNKNOWN 304
+
+/* Add a password to the keychain. */
+int smbfs_keychain_add(uid_t uid, const char *domain, const char *user,
+ const char *password);
+
+/* Delete a password from the keychain. */
+int smbfs_keychain_del(uid_t uid, const char *domain, const char *user);
+
+/*
+ * Check for existence of a keychain entry.
+ * Returns 0 if it exists, else ENOENT.
+ */
+int smbfs_keychain_chk(const char *domain, const char *user);
+
+/*
+ * Delete all keychain entries owned by the caller.
+ */
+int smbfs_keychain_del_owner(void);
+
+/*
+ * Delete all keychain entries (regardless of owner).
+ * Requires super-user privliege.
+ */
+int smbfs_keychain_del_everyone(void);
+
+/*
+ * This is not really part of the keychain library,
+ * but is typically needed in code that wants to
+ * provide (editable) defaults for domain/user
+ *
+ * Get default domain and user names
+ * Server name is optional.
+ */
+int
+smbfs_default_dom_usr(const char *home, const char *server,
+ char *dom, int maxdom, char *usr, int maxusr);
+
+#endif /* _SMB_KEYCHAIN_H */
diff --git a/usr/src/lib/libsmbfs/netsmb/smb_lib.h b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
new file mode 100644
index 0000000000..90bfda6313
--- /dev/null
+++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
@@ -0,0 +1,345 @@
+/*
+ * 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_lib.h,v 1.21.82.2 2005/06/02 00:55:39 lindak Exp $
+ */
+
+#ifndef _NETSMB_SMB_LIB_H_
+#define _NETSMB_SMB_LIB_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#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/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:"
+
+/*
+ * bits to indicate the source of error
+ */
+#define SMB_ERRTYPE_MASK 0xf0000
+#define SMB_SYS_ERROR 0x00000
+#define SMB_RAP_ERROR 0x10000
+#define SMB_NB_ERROR 0x20000
+
+/*
+ * These get/set macros do not handle mis-aligned data.
+ * The data are all supposed to be aligned, but that's
+ * up to the server. If we ever encounter a server that
+ * doesn't obey this rule, a "strict alignment" client
+ * (i.e. SPARC) may get an alignment trap in one of these.
+ * If that ever happens, make these macros into functions
+ * that can handle mis-aligned data. (Or catch traps.)
+ */
+#define getb(buf, ofs) (((const uint8_t *)(buf))[ofs])
+#define setb(buf, ofs, val) (((uint8_t *)(buf))[ofs]) = val
+#define getbw(buf, ofs) ((uint16_t)(getb(buf, ofs)))
+#define getw(buf, ofs) (*((uint16_t *)(&((uint8_t *)(buf))[ofs])))
+#define getdw(buf, ofs) (*((uint32_t *)(&((uint8_t *)(buf))[ofs])))
+
+#ifdef _LITTLE_ENDIAN
+
+#define getwle(buf, ofs) (*((uint16_t *)(&((uint8_t *)(buf))[ofs])))
+#define getdle(buf, ofs) (*((uint32_t *)(&((uint8_t *)(buf))[ofs])))
+#define getwbe(buf, ofs) (ntohs(getwle(buf, ofs)))
+#define getdbe(buf, ofs) (ntohl(getdle(buf, ofs)))
+
+#define setwle(buf, ofs, val) getwle(buf, ofs) = val
+#define setwbe(buf, ofs, val) getwle(buf, ofs) = htons(val)
+#define setdle(buf, ofs, val) getdle(buf, ofs) = val
+#define setdbe(buf, ofs, val) getdle(buf, ofs) = htonl(val)
+
+#else /* _LITTLE_ENDIAN */
+
+#define getwbe(buf, ofs) (*((uint16_t *)(&((uint8_t *)(buf))[ofs])))
+#define getdbe(buf, ofs) (*((uint32_t *)(&((uint8_t *)(buf))[ofs])))
+#define getwle(buf, ofs) (BSWAP_16(getwbe(buf, ofs)))
+#define getdle(buf, ofs) (BSWAP_32(getdbe(buf, ofs)))
+
+#define setwbe(buf, ofs, val) getwbe(buf, ofs) = val
+#define setwle(buf, ofs, val) getwbe(buf, ofs) = BSWAP_16(val)
+#define setdbe(buf, ofs, val) getdbe(buf, ofs) = val
+#define setdle(buf, ofs, val) getdbe(buf, ofs) = BSWAP_32(val)
+
+#endif /* _LITTLE_ENDIAN */
+
+/*
+ * 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_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_origshare;
+ char *ct_home;
+#ifdef APPLE
+ /* temporary automount hack */
+ char **ct_xxx;
+ int ct_maxxxx; /* max # to mount (-x arg) */
+#endif
+ 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 */
+};
+typedef struct smb_ctx smb_ctx_t;
+
+#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 */
+#define SMBCF_CMD_DOM 0x0010 /* CMD specified domain */
+#define SMBCF_CMD_USR 0x0020 /* CMD specified user */
+#define SMBCF_CMD_PW 0x0040 /* CMD specified password */
+#define SMBCF_RESOLVED 0x8000 /* structure has been verified */
+#define SMBCF_KCBAD 0x00080000 /* keychain password failed */
+#define SMBCF_KCFOUND 0x00100000 /* password is from keychain */
+#define SMBCF_BROWSEOK 0x00200000 /* browser dialogue may be used */
+#define SMBCF_AUTHREQ 0x00400000 /* auth. dialog requested */
+#define SMBCF_KCSAVE 0x00800000 /* add to keychain requested */
+#define SMBCF_XXX 0x01000000 /* mount-all, a very bad thing */
+#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
+ */
+#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 */
+
+
+/*
+ * request handling structures
+ */
+struct mbuf {
+ int m_len;
+ int m_maxlen;
+ char *m_data;
+ struct mbuf *m_next;
+};
+typedef struct mbuf mbuf_t;
+
+struct mbdata {
+ struct mbuf *mb_top;
+ struct mbuf *mb_cur;
+ char *mb_pos;
+ int mb_count;
+};
+typedef struct mbdata mbdata_t;
+
+#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_TOP(m) ((char *)(m) + M_BASESIZE)
+#define M_TRAILINGSPACE(m) ((m)->m_maxlen - (m)->m_len)
+#define mtod(m, t) ((t)(m)->m_data)
+
+struct smb_rq {
+ uchar_t rq_cmd;
+ struct mbdata rq_rq;
+ struct mbdata rq_rp;
+ struct smb_ctx *rq_ctx;
+ int rq_wcount;
+ int rq_bcount;
+};
+typedef struct smb_rq smb_rq_t;
+
+struct smb_bitname {
+ uint_t bn_bit;
+ char *bn_name;
+};
+typedef struct smb_bitname smb_bitname_t;
+
+extern int smb_debug, smb_verbose;
+extern struct rcfile *smb_rc;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct sockaddr;
+
+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 *);
+
+/*
+ * Context management
+ */
+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_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);
+
+int smb_read(struct smb_ctx *, smbfh, off_t, size_t, char *);
+int smb_write(struct smb_ctx *, smbfh, off_t, size_t, const char *);
+
+#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 **);
+void smb_rq_done(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_t2_request(struct smb_ctx *, int, uint16_t *, const char *,
+ int, void *, int, void *, int *, void *, int *, void *, int *);
+
+void smb_simplecrypt(char *dst, const char *src);
+int smb_simpledecrypt(char *dst, const char *src);
+
+int m_getm(struct mbuf *, size_t, struct mbuf **);
+int m_lineup(struct mbuf *, struct mbuf **);
+int mb_init(struct mbdata *, size_t);
+int mb_initm(struct mbdata *, struct mbuf *);
+int mb_done(struct mbdata *);
+int mb_fit(struct mbdata *mbp, size_t size, char **pp);
+int mb_put_uint8(struct mbdata *, uint8_t);
+int mb_put_uint16be(struct mbdata *, uint16_t);
+int mb_put_uint16le(struct mbdata *, uint16_t);
+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_mbuf(struct mbdata *, struct mbuf *);
+
+int mb_get_uint8(struct mbdata *, uint8_t *);
+int mb_get_uint16(struct mbdata *, uint16_t *);
+int mb_get_uint16le(struct mbdata *, uint16_t *);
+int mb_get_uint16be(struct mbdata *, uint16_t *);
+int mb_get_uint32(struct mbdata *, uint32_t *);
+int mb_get_uint32be(struct mbdata *, uint32_t *);
+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);
+
+extern uchar_t nls_lower[256], nls_upper[256];
+
+int nls_setrecode(const char *, const char *);
+int nls_setlocale(const char *);
+char *nls_str_toext(char *, const char *);
+char *nls_str_toloc(char *, const char *);
+void *nls_mem_toext(void *, const void *, int);
+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/smb_netshareenum.h b/usr/src/lib/libsmbfs/netsmb/smb_netshareenum.h
new file mode 100644
index 0000000000..14f2594df7
--- /dev/null
+++ b/usr/src/lib/libsmbfs/netsmb/smb_netshareenum.h
@@ -0,0 +1,18 @@
+
+#ifndef _NETSMB_SMB_NETSHAREENUM_H_
+#define _NETSMB_SMB_NETSHAREENUM_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* This is from Apple. See ../smb/netshareenum.c */
+
+struct share_info {
+ uint16_t type;
+ char *netname;
+ char *remark;
+};
+typedef struct share_info share_info_t;
+
+int smb_netshareenum(struct smb_ctx *, int *, int *, struct share_info **);
+
+#endif /* _NETSMB_SMB_NETSHAREENUM_H_ */
diff --git a/usr/src/lib/libsmbfs/netsmb/smb_rap.h b/usr/src/lib/libsmbfs/netsmb/smb_rap.h
new file mode 100644
index 0000000000..118861f633
--- /dev/null
+++ b/usr/src/lib/libsmbfs/netsmb/smb_rap.h
@@ -0,0 +1,81 @@
+/*
+ * 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_rap.h,v 1.1.1.1 2001/07/06 22:38:38 conrad Exp $
+ */
+
+#ifndef _NETSMB_SMB_RAP_H_
+#define _NETSMB_SMB_RAP_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+struct smb_rap {
+ char *r_sparam;
+ char *r_nparam;
+ char *r_sdata;
+ char *r_ndata;
+ char *r_pbuf; /* rq parameters */
+ int r_plen; /* rq param len */
+ char *r_npbuf;
+ char *r_dbuf; /* rq data */
+ int r_dlen; /* rq data len */
+ char *r_ndbuf;
+ uint32_t r_result;
+ char *r_rcvbuf;
+ int r_rcvbuflen;
+ int r_entries;
+};
+
+struct smb_share_info_1 {
+ char shi1_netname[13];
+ char shi1_pad;
+ uint16_t shi1_type;
+ uint32_t shi1_remark; /* char * */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int smb_rap_create(int, const char *, const char *, struct smb_rap **);
+void smb_rap_done(struct smb_rap *);
+int smb_rap_request(struct smb_rap *, struct smb_ctx *);
+int smb_rap_setNparam(struct smb_rap *, int);
+int smb_rap_setPparam(struct smb_rap *, void *);
+int smb_rap_error(struct smb_rap *, int);
+
+int smb_rap_NetShareEnum(struct smb_ctx *, int, void *, int *, int *, int *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NETSMB_SMB_RAP_H_ */
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple
new file mode 100644
index 0000000000..a979c99b4f
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip
new file mode 100644
index 0000000000..aa3d6ad7e1
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip
@@ -0,0 +1 @@
+PORTIONS OF LIBSMBFS IN CIFS CLIENT
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov
new file mode 100644
index 0000000000..583923c355
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov
@@ -0,0 +1,29 @@
+ 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.
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip
new file mode 100644
index 0000000000..d7cc9ebbd7
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip
@@ -0,0 +1 @@
+CIFS CLIENT SOFTWARE
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4 b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4
new file mode 100644
index 0000000000..56ec482ec5
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip
new file mode 100644
index 0000000000..aa3d6ad7e1
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip
@@ -0,0 +1 @@
+PORTIONS OF LIBSMBFS IN CIFS CLIENT
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft
new file mode 100644
index 0000000000..afbd224c30
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft
@@ -0,0 +1,10 @@
+/*
+// Copyright (C) 2002 Microsoft Corporation
+// All rights reserved.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+// OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+*/
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip
new file mode 100644
index 0000000000..aa3d6ad7e1
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip
@@ -0,0 +1 @@
+PORTIONS OF LIBSMBFS IN CIFS CLIENT
diff --git a/usr/src/lib/libsmbfs/smb/cfopt.c b/usr/src/lib/libsmbfs/smb/cfopt.c
new file mode 100644
index 0000000000..094682f6d8
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/cfopt.c
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ *
+ * $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 <stdio.h>
+#include <string.h>
+#include <libintl.h>
+
+#include <cflib.h>
+#include <netsmb/smb_lib.h>
+
+int cf_opterr = 1, /* if error message should be printed */
+ cf_optind = 1, /* index into parent argv vector */
+ cf_optopt, /* character checked for validity */
+ cf_optreset; /* reset getopt */
+const char *cf_optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+int
+cf_getopt(nargc, nargv, ostr)
+ int nargc;
+ char * const *nargv;
+ const char *ostr;
+{
+ static const char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+ int tmpind;
+
+ if (cf_optreset || !*place) { /* update scanning pointer */
+ cf_optreset = 0;
+ tmpind = cf_optind;
+ while (1) {
+ if (tmpind >= nargc) {
+ place = EMSG;
+ return (-1);
+ }
+ if (*(place = nargv[tmpind]) != '-') {
+ tmpind++;
+ continue; /* lookup next option */
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ cf_optind = ++tmpind;
+ place = EMSG;
+ return (-1);
+ }
+ cf_optind = tmpind;
+ break;
+ }
+ } /* option letter okay? */
+ if ((cf_optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, cf_optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if (cf_optopt == (int)'-')
+ return (-1);
+ if (!*place)
+ ++cf_optind;
+ if (cf_opterr && *ostr != ':')
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "%s: illegal option -- %c\n"),
+ __progname, cf_optopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ cf_optarg = NULL;
+ if (!*place)
+ ++cf_optind;
+ } else { /* need an argument */
+ if (*place) /* no white space */
+ cf_optarg = place;
+ else if (nargc <= ++cf_optind) { /* no arg */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (cf_opterr)
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "%s: option requires an argument -- %c\n"),
+ __progname, cf_optopt);
+ return (BADCH);
+ } else /* white space */
+ cf_optarg = nargv[cf_optind];
+ place = EMSG;
+ ++cf_optind;
+ }
+ return (cf_optopt); /* dump back option letter */
+}
diff --git a/usr/src/lib/libsmbfs/smb/charsets.c b/usr/src/lib/libsmbfs/smb/charsets.c
new file mode 100644
index 0000000000..7000be5416
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/charsets.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/* @(#)charsets.c *
+ * (c) 2004 Apple Computer, Inc. All Rights Reserved
+ *
+ *
+ * charsets.c -- Routines converting between UTF-8, 16-bit
+ * little-endian Unicode, and various Windows
+ * code pages.
+ *
+ * MODIFICATION HISTORY:
+ * 28-Nov-2004 Guy Harris New today
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <iconv.h>
+#include <langinfo.h>
+#include <strings.h>
+
+#ifdef NOTPORTED
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFStringDefaultEncoding.h>
+#include <CoreFoundation/CFStringEncodingConverter.h>
+#include <sys/mchain.h>
+#endif /* NOTPORTED */
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/mchain.h>
+
+#include "charsets.h"
+
+#ifdef NOTPORTED
+extern uid_t real_uid,eff_uid;
+#endif /* NOTPORTED */
+
+/*
+ * On Solaris, we will need to do some rewriting to use our iconv
+ * routines for the conversions. For now, we're effectively
+ * stubbing out code, leaving the details of what happens on
+ * Darwin in case it's useful as a guide later.
+ */
+
+static unsigned
+xtoi(char u)
+{
+ if (isdigit(u))
+ return (u - '0');
+ else if (islower(u))
+ return (10 + u - 'a');
+ else if (isupper(u))
+ return (10 + u - 'A');
+ return (16);
+}
+
+
+/* Removes the "%" escape sequences from a URL component.
+ * See IETF RFC 2396.
+ */
+char *
+unpercent(char * component)
+{
+ char c, *s;
+ unsigned hi, lo;
+
+ if (component)
+ for (s = component; (c = *s) != 0; s++) {
+ if (c != '%')
+ continue;
+ if ((hi = xtoi(s[1])) > 15 || (lo = xtoi(s[2])) > 15)
+ continue; /* ignore invalid escapes */
+ s[0] = hi*16 + lo;
+ /*
+ * This was strcpy(s + 1, s + 3);
+ * But nowadays leftward overlapping copies are
+ * officially undefined in C. Ours seems to
+ * work or not depending upon alignment.
+ */
+ memmove(s+1, s+3, strlen(s+3) + 1);
+ }
+ return (component);
+}
+
+#ifdef NOTPORTED
+static CFStringEncoding
+get_windows_encoding_equivalent( void )
+{
+
+ CFStringEncoding encoding;
+ uint32_t index,region;
+
+ /* important! use root ID so you can read the config file! */
+ seteuid(eff_uid);
+ __CFStringGetInstallationEncodingAndRegion(&index,&region);
+ seteuid(real_uid);
+
+ switch ( index )
+ {
+ case kCFStringEncodingMacRoman:
+ if (region) /* anything nonzero is not US */
+ encoding = kCFStringEncodingDOSLatin1;
+ else /* US region */
+ encoding = kCFStringEncodingDOSLatinUS;
+ break;
+
+ case kCFStringEncodingMacJapanese:
+ encoding = kCFStringEncodingDOSJapanese;
+ break;
+
+ case kCFStringEncodingMacChineseTrad:
+ encoding = kCFStringEncodingDOSChineseTrad;
+ break;
+
+ case kCFStringEncodingMacKorean:
+ encoding = kCFStringEncodingDOSKorean;
+ break;
+
+ case kCFStringEncodingMacArabic:
+ encoding = kCFStringEncodingDOSArabic;
+ break;
+
+ case kCFStringEncodingMacHebrew:
+ encoding = kCFStringEncodingDOSHebrew;
+ break;
+
+ case kCFStringEncodingMacGreek:
+ encoding = kCFStringEncodingDOSGreek;
+ break;
+
+ case kCFStringEncodingMacCyrillic:
+ encoding = kCFStringEncodingDOSCyrillic;
+ break;
+
+ case kCFStringEncodingMacThai:
+ encoding = kCFStringEncodingDOSThai;
+ break;
+
+ case kCFStringEncodingMacChineseSimp:
+ encoding = kCFStringEncodingDOSChineseSimplif;
+ break;
+
+ case kCFStringEncodingMacCentralEurRoman:
+ encoding = kCFStringEncodingDOSLatin2;
+ break;
+
+ case kCFStringEncodingMacTurkish:
+ encoding = kCFStringEncodingDOSTurkish;
+ break;
+
+ case kCFStringEncodingMacCroatian:
+ encoding = kCFStringEncodingDOSLatin2;
+ break;
+
+ case kCFStringEncodingMacIcelandic:
+ encoding = kCFStringEncodingDOSIcelandic;
+ break;
+
+ case kCFStringEncodingMacRomanian:
+ encoding = kCFStringEncodingDOSLatin2;
+ break;
+
+ case kCFStringEncodingMacFarsi:
+ encoding = kCFStringEncodingDOSArabic;
+ break;
+
+ case kCFStringEncodingMacUkrainian:
+ encoding = kCFStringEncodingDOSCyrillic;
+ break;
+
+ default:
+ encoding = kCFStringEncodingDOSLatin1;
+ break;
+ }
+
+ return encoding;
+}
+#endif /* NOTPORTED */
+
+/*
+ * XXX - NLS, or CF? We should probably use the same routine for all
+ * conversions.
+ */
+char *
+convert_wincs_to_utf8(const char *windows_string)
+{
+#ifdef NOTPORTED
+ CFStringRef s;
+ CFIndex maxlen;
+ char *result;
+
+ s = CFStringCreateWithCString(NULL, windows_string,
+ get_windows_encoding_equivalent());
+ if (s == NULL) {
+ smb_error("CFStringCreateWithCString for Windows code page failed on \"%s\" ", -1,
+ windows_string);
+
+ /* kCFStringEncodingMacRoman should always succeed */
+ s = CFStringCreateWithCString(NULL, windows_string,
+ kCFStringEncodingMacRoman);
+ if (s == NULL) {
+ smb_error("CFStringCreateWithCString for Windows code page failed on \"%s\" with kCFStringEncodingMacRoman - skipping",
+ -1, windows_string);
+ return NULL;
+ }
+ }
+
+ maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(s),
+ kCFStringEncodingUTF8) + 1;
+ result = malloc(maxlen);
+ if (result == NULL) {
+ smb_error("Couldn't allocate buffer for UTF-8 string for \"%s\" - skipping", -1,
+ windows_string);
+ CFRelease(s);
+ return NULL;
+ }
+ if (!CFStringGetCString(s, result, maxlen, kCFStringEncodingUTF8)) {
+ smb_error("CFStringGetCString for UTF-8 failed on \"%s\" - skipping",
+ -1, windows_string);
+ CFRelease(s);
+ return NULL;
+ }
+ CFRelease(s);
+ return result;
+#else /* NOTPORTED */
+ return ((char*)windows_string);
+#endif /* NOTPORTED */
+}
+
+/*
+ * XXX - NLS, or CF? We should probably use the same routine for all
+ * conversions.
+ */
+char *
+convert_utf8_to_wincs(const char *utf8_string)
+{
+#ifdef NOTPORTED
+ CFStringRef s;
+ CFIndex maxlen;
+ char *result;
+
+ s = CFStringCreateWithCString(NULL, utf8_string,
+ kCFStringEncodingUTF8);
+ if (s == NULL) {
+ smb_error("CFStringCreateWithCString for UTF-8 failed on \"%s\"", -1,
+ utf8_string);
+ return NULL;
+ }
+
+ maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(s),
+ get_windows_encoding_equivalent()) + 1;
+ result = malloc(maxlen);
+ if (result == NULL) {
+ smb_error("Couldn't allocate buffer for Windows code page string for \"%s\" - skipping", -1,
+ utf8_string);
+ CFRelease(s);
+ return NULL;
+ }
+ if (!CFStringGetCString(s, result, maxlen,
+ get_windows_encoding_equivalent())) {
+ smb_error("CFStringGetCString for Windows code page failed on \"%s\" - skipping",
+ -1, utf8_string);
+ CFRelease(s);
+ return NULL;
+ }
+ CFRelease(s);
+ return result;
+#else /* NOTPORTED */
+ return ((char*)utf8_string);
+#endif /* NOTPORTED */
+}
+
+/*
+ * Convert little-endian Unicode string to UTF-8.
+ * Converts the Unicode string to host byte order in place.
+ */
+char *
+convert_leunicode_to_utf8(unsigned short *unicode_string)
+{
+ unsigned short *unicode_charp, unicode_char;
+ int len = 0;
+
+ for (unicode_charp = unicode_string;
+ (unicode_char = *unicode_charp) != 0;
+ unicode_charp++) {
+ *unicode_charp = letohs(unicode_char);
+ len = len + 2;
+ }
+ return (convert_unicode_to_utf8(unicode_string, len));
+}
+
+char *
+convert_unicode_to_utf8(unsigned short *unicode_string, int len)
+{
+ iconv_t cd;
+ char from[BUFSIZ], to[BUFSIZ];
+ char *tptr = NULL;
+ const char *fptr;
+ size_t ileft, oleft, ret;
+
+ cd = iconv_open("UTF-8", "UTF-16");
+ if (cd != (iconv_t)-1) {
+ ileft = len;
+ bcopy((char *)unicode_string, from, ileft);
+ fptr = from;
+ oleft = BUFSIZ;
+ tptr = to;
+ ret = iconv(cd, &fptr, &ileft, &tptr, &oleft);
+ if (ret != (size_t)-1) {
+ to[BUFSIZ-oleft] = '\0';
+ tptr = to;
+ } else {
+ tptr = NULL;
+ }
+ (void) iconv_close(cd);
+ }
+ return (tptr);
+}
+
+/*
+ * Convert UTF-8 string to little-endian Unicode.
+ */
+unsigned short *
+convert_utf8_to_leunicode(const char *utf8_string)
+{
+#ifdef NOTPORTED
+ CFStringRef s;
+ CFIndex maxlen;
+ unsigned short *result;
+ CFRange range;
+ int i;
+
+ s = CFStringCreateWithCString(NULL, utf8_string,
+ kCFStringEncodingUTF8);
+ if (s == NULL) {
+ smb_error("CFStringCreateWithCString for UTF-8 failed on \"%s\"", -1,
+ utf8_string);
+ return NULL;
+ }
+
+ maxlen = CFStringGetLength(s);
+ result = malloc(2*(maxlen + 1));
+ if (result == NULL) {
+ smb_error("Couldn't allocate buffer for Unicode string for \"%s\" - skipping", -1,
+ utf8_string);
+ CFRelease(s);
+ return NULL;
+ }
+ range.location = 0;
+ range.length = maxlen;
+ CFStringGetCharacters(s, range, result);
+ for (i = 0; i < maxlen; i++)
+ result[i] = CFSwapInt16HostToLittle(result[i]);
+ result[maxlen] = 0;
+ CFRelease(s);
+ return result;
+#else /* NOTPORTED */
+ /* LINTED */ /* XXX Really need to fix this! */
+ return ((ushort_t *)utf8_string); /* XXX */
+#endif /* NOTPORTED */
+}
diff --git a/usr/src/lib/libsmbfs/smb/charsets.h b/usr/src/lib/libsmbfs/smb/charsets.h
new file mode 100644
index 0000000000..5518afc783
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/charsets.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * @(#)charsets.h
+ * (c) 2004 Apple Computer, Inc. All Rights Reserved
+ *
+ *
+ * charsets.h -- Routines converting between UTF-8, 16-bit
+ * little-endian Unicode, 16-bit host-byte-order
+ * Unicode, and various Windows code pages.
+ *
+ * MODIFICATION HISTORY:
+ * 28-Nov-2004 Guy Harris New today
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifndef __CHARSETS_H__
+#define __CHARSETS_H__
+
+extern char *convert_wincs_to_utf8(const char *windows_string);
+extern char *convert_utf8_to_wincs(const char *utf8_string);
+extern char *convert_leunicode_to_utf8(unsigned short *windows_string);
+extern char *convert_unicode_to_utf8(unsigned short *windows_string, int len);
+extern unsigned short *convert_utf8_to_leunicode(const char *utf8_string);
+
+#endif /* __CHARSETS_H__ */
diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c
new file mode 100644
index 0000000000..51896bf128
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/ctx.c
@@ -0,0 +1,2140 @@
+/*
+ * 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.
+ *
+ * $Id: ctx.c,v 1.32.70.2 2005/06/02 00:55:40 lindak Exp $
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/byteorder.h>
+
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <assert.h>
+#include <nss_dbdefs.h>
+
+#include <kerberosv5/krb5.h>
+#include <kerberosv5/com_err.h>
+
+extern uid_t real_uid, eff_uid;
+
+#define NB_NEEDRESOLVER
+
+#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 "derparse.h"
+
+extern MECH_OID g_stcMechOIDList [];
+
+#define POWEROF2(x) (((x) & ((x)-1)) == 0)
+
+/* These two may be set by commands. */
+int smb_debug, smb_verbose;
+
+/*
+ * This used to call the DCE/RPC code.
+ * We want more strict layering than this.
+ * The redirector should simply export a
+ * remote pipe API, comsumed by dce rpc.
+ * Make it a no-op for now.
+ */
+#if 0
+#include <rpc_cleanup.h>
+#else
+static void
+rpc_cleanup_smbctx(struct smb_ctx *ctx)
+{
+}
+#endif
+
+void
+dump_ctx_flags(int flags)
+{
+ printf(" Flags: ");
+ if (flags == 0)
+ printf("0");
+ if (flags & SMBCF_NOPWD)
+ printf("NOPWD ");
+ if (flags & SMBCF_SRIGHTS)
+ printf("SRIGHTS ");
+ if (flags & SMBCF_LOCALE)
+ printf("LOCALE ");
+ if (flags & SMBCF_CMD_DOM)
+ printf("CMD_DOM ");
+ if (flags & SMBCF_CMD_USR)
+ printf("CMD_USR ");
+ if (flags & SMBCF_CMD_PW)
+ printf("CMD_PW ");
+ if (flags & SMBCF_RESOLVED)
+ printf("RESOLVED ");
+ if (flags & SMBCF_KCBAD)
+ printf("KCBAD ");
+ if (flags & SMBCF_KCFOUND)
+ printf("KCFOUND ");
+ if (flags & SMBCF_BROWSEOK)
+ printf("BROWSEOK ");
+ if (flags & SMBCF_AUTHREQ)
+ printf("AUTHREQ ");
+ if (flags & SMBCF_KCSAVE)
+ printf("KCSAVE ");
+ if (flags & SMBCF_XXX)
+ printf("XXX ");
+ if (flags & SMBCF_SSNACTIVE)
+ printf("SSNACTIVE ");
+ if (flags & SMBCF_KCDOMAIN)
+ printf("KCDOMAIN ");
+ printf("\n");
+}
+
+void
+dump_ctx_ssn(struct smbioc_ossn *ssn)
+{
+ 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);
+}
+
+void
+dump_ctx_sh(struct smbioc_oshare *sh)
+{
+ printf(" share_name=\"%s\", share_pw=\"%s\"\n",
+ sh->ioc_share, sh->ioc_password);
+}
+
+void
+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_fullserver)
+ printf(" fullserver=\"%s\"", ctx->ct_fullserver);
+ else
+ printf(" fullserver=NULL");
+
+ if (ctx->ct_srvaddr)
+ printf(" srvaddr=\"%s\"\n", ctx->ct_srvaddr);
+ else
+ printf(" srvaddr=NULL\n");
+
+ dump_ctx_ssn(&ctx->ct_ssn);
+ dump_ctx_sh(&ctx->ct_sh);
+}
+
+/*
+ * Initialize an smb_ctx struct.
+ *
+ * The sequence for getting all the members filled in
+ * has some tricky aspects. Here's how it works:
+ *
+ * The search order for options is as follows:
+ * command line options
+ * values parsed from UNC path (cmd)
+ * values from RC file (per-user)
+ * values from SMF (system-wide)
+ * built-in defaults
+ *
+ * Normally, one would simply get all the values starting with
+ * the bottom of the above list and working to the top, and
+ * overwriting values as you go. But we need an exception.
+ *
+ * In this function, we parse the UNC path and command line options,
+ * because we need (at least) the server name when we're getting the
+ * SMF and RC file values. However, values we get from the command
+ * should not be overwritten by SMF or RC file parsing, so we mark
+ * values from the command as "from CMD" and the RC file parser
+ * leaves in place any values so marked. See: SMBCF_CMD_*
+ *
+ * The semantics of these flags are: "This value came from the
+ * current command instance, not from sources that may apply to
+ * multiple commands." (Different from the old "FROMUSR" flag.)
+ *
+ * Note that smb_ctx_opt() is called later to handle the
+ * remaining options, which should be ignored here.
+ * The (magic) leading ":" in cf_getopt() makes it
+ * ignore options not in the options string.
+ */
+int
+smb_ctx_init(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 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;
+
+ 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;
+ }
+
+ /*
+ * 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) {
+ arg = cf_optarg;
+ 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;
+ }
+ }
+ if (aflg && uflg) {
+ printf(gettext("-A and -U flags are exclusive.\n"));
+ return (1);
+ }
+ cf_optind = cf_optreset = 1;
+
+done:
+ if (smb_debug)
+ dump_ctx("after smb_ctx_init", ctx);
+
+ return (error);
+}
+
+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_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)
+ nb_ctx_done(ctx->ct_nb);
+ if (ctx->ct_secblob)
+ free(ctx->ct_secblob);
+ if (ctx->ct_origshare)
+ free(ctx->ct_origshare);
+ if (ctx->ct_fullserver)
+ free(ctx->ct_fullserver);
+}
+
+static int
+getsubstring(const char *p, uchar_t sep, char *dest, int maxlen,
+ const char **next)
+{
+ int len;
+
+ maxlen--;
+ for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) {
+ if (*p == 0)
+ return (EINVAL);
+ *dest = *p;
+ }
+ *dest = 0;
+ *next = *p ? p + 1 : p;
+ return (0);
+}
+
+/*
+ * Parse the UNC path. Here we expect something like
+ * "//[workgroup;][user[:password]@]host[/share[/path]]"
+ * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
+ * Values found here are marked as "from CMD".
+ */
+int
+smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
+ const char **next)
+{
+ const char *p = unc;
+ char *p1, *colon, *servername;
+ char tmp[1024];
+ char tmp2[1024];
+ int error;
+
+ ctx->ct_parsedlevel = SMBL_NONE;
+ if (*p++ != '/' || *p++ != '/') {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "UNC should start with '//'"), 0);
+ return (EINVAL);
+ }
+ p1 = tmp;
+ error = getsubstring(p, ';', p1, sizeof (tmp), &p);
+ if (!error) {
+ if (*p1 == 0) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "empty workgroup name"), 0);
+ return (EINVAL);
+ }
+ nls_str_upper(tmp, tmp);
+ error = smb_ctx_setworkgroup(ctx, unpercent(tmp), TRUE);
+ if (error)
+ return (error);
+ }
+ colon = (char *)p;
+ error = getsubstring(p, '@', p1, sizeof (tmp), &p);
+ if (!error) {
+ if (ctx->ct_maxlevel < SMBL_VC) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "no user name required"), 0);
+ return (EINVAL);
+ }
+ p1 = strchr(tmp, ':');
+ if (p1) {
+ colon += p1 - tmp;
+ *p1++ = (char)0;
+ error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE);
+ if (error)
+ return (error);
+ if (p - colon > 2)
+ memset(colon+1, '*', p - colon - 2);
+ }
+ p1 = tmp;
+ if (*p1 == 0) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "empty user name"), 0);
+ return (EINVAL);
+ }
+ error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE);
+ if (error)
+ return (error);
+ ctx->ct_parsedlevel = SMBL_VC;
+ }
+ error = getsubstring(p, '/', p1, sizeof (tmp), &p);
+ if (error) {
+ error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
+ if (error) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "no server name found"), 0);
+ return (error);
+ }
+ }
+ if (*p1 == 0) {
+ smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0);
+ return (EINVAL);
+ }
+
+
+ /*
+ * It's safe to uppercase this string, which
+ * consists of ascii characters that should
+ * be uppercased, %s, and ascii characters representing
+ * 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!
+ */
+
+ nls_str_upper(tmp2, tmp);
+
+ /*
+ * scan for % in the string.
+ * If we find one, convert
+ * to the assumed codepage.
+ */
+
+ 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 (error)
+ return (error);
+ if (sharetype == SMB_ST_NONE) {
+ *next = p;
+ return (0);
+ }
+ if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
+ smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0);
+ return (EINVAL);
+ }
+ error = getsubstring(p, '/', p1, sizeof (tmp), &p);
+ if (error) {
+ error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
+ if (error) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "unexpected end of line"), 0);
+ return (error);
+ }
+ }
+ if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE &&
+ !(ctx->ct_flags & SMBCF_BROWSEOK)) {
+ smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0);
+ return (EINVAL);
+ }
+ *next = p;
+ if (*p1 == 0)
+ return (0);
+ error = smb_ctx_setshare(ctx, unpercent(p1), sharetype);
+ return (error);
+}
+
+int
+smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
+{
+ char *cp, *servercs, *localcs;
+ int cslen = sizeof (ctx->ct_ssn.ioc_localcs);
+ int scslen, lcslen, error;
+
+ cp = strchr(arg, ':');
+ lcslen = cp ? (cp - arg) : 0;
+ if (lcslen == 0 || lcslen >= cslen) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "invalid local charset specification (%s)"), 0, arg);
+ return (EINVAL);
+ }
+ scslen = (size_t)strlen(++cp);
+ if (scslen == 0 || scslen >= cslen) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "invalid server charset specification (%s)"), 0, arg);
+ return (EINVAL);
+ }
+ localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen);
+ localcs[lcslen] = 0;
+ servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp);
+ error = nls_setrecode(localcs, servercs);
+ if (error == 0)
+ return (0);
+ smb_error(dgettext(TEXT_DOMAIN,
+ "can't initialize iconv support (%s:%s)"),
+ error, localcs, servercs);
+ localcs[0] = 0;
+ servercs[0] = 0;
+ return (error);
+}
+
+int
+smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name)
+{
+ ctx->ct_fullserver = strdup(name);
+ if (ctx->ct_fullserver == NULL)
+ return (ENOMEM);
+ 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)
+{
+ char server[SMB_MAXSRVNAMELEN + 1];
+ char workgroup[SMB_MAXUSERNAMELEN + 1];
+ int error;
+#if 0
+ char *dot;
+#endif
+
+ 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);
+}
+
+/* this routine does not uppercase the server name */
+void
+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);
+}
+
+int
+smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd)
+{
+
+ if (strlen(name) >= SMB_MAXUSERNAMELEN) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "user name '%s' too long"), 0, name);
+ return (ENAMETOOLONG);
+ }
+
+ /*
+ * Don't overwrite a value from the command line
+ * with one from anywhere else.
+ */
+ if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR))
+ return (0);
+
+ /* don't uppercase the username, just copy it. */
+ strcpy(ctx->ct_ssn.ioc_user, name);
+
+ /* Mark this as "from the command line". */
+ if (from_cmd)
+ ctx->ct_flags |= SMBCF_CMD_USR;
+
+ return (0);
+}
+
+/*
+ * Never uppercase the workgroup
+ * name here, because it might come
+ * from a Windows codepage encoding.
+ *
+ * Don't overwrite a domain name from the
+ * command line with one from anywhere else.
+ * See smb_ctx_init() for notes about this.
+ */
+int
+smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name, int from_cmd)
+{
+
+ if (strlen(name) >= SMB_MAXUSERNAMELEN) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "workgroup name '%s' too long"), 0, name);
+ return (ENAMETOOLONG);
+ }
+
+ /*
+ * Don't overwrite a value from the command line
+ * with one from anywhere else.
+ */
+ if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM))
+ return (0);
+
+ strcpy(ctx->ct_ssn.ioc_workgroup, name);
+
+ /* Mark this as "from the command line". */
+ if (from_cmd)
+ ctx->ct_flags |= SMBCF_CMD_DOM;
+
+ return (0);
+}
+
+int
+smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd)
+{
+
+ if (passwd == NULL) /* XXX Huh? */
+ return (EINVAL);
+ if (strlen(passwd) >= SMB_MAXPASSWORDLEN) {
+ 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 (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW))
+ return (0);
+
+ if (strncmp(passwd, "$$1", 3) == 0)
+ smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd);
+ else
+ strcpy(ctx->ct_ssn.ioc_password, passwd);
+ strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password);
+
+ /* Mark this as "from the command line". */
+ if (from_cmd)
+ ctx->ct_flags |= SMBCF_CMD_PW;
+
+ return (0);
+}
+
+int
+smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
+{
+ if (strlen(share) >= SMB_MAXSHARENAMELEN) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "share name '%s' too long"), 0, share);
+ return (ENAMETOOLONG);
+ }
+ if (ctx->ct_origshare)
+ 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;
+ return (0);
+}
+
+int
+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)
+ return (ENOMEM);
+ return (0);
+}
+
+static int
+smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
+{
+ struct group gr;
+ struct passwd pw;
+ char buf[NSS_BUFLEN_PASSWD];
+ char *cp;
+
+ cp = strchr(pair, ':');
+ if (cp) {
+ *cp++ = '\0';
+ if (*cp) {
+ if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
+ *gid = gr.gr_gid;
+ } else
+ smb_error(dgettext(TEXT_DOMAIN,
+ "Invalid group name %s, ignored"), 0, cp);
+ }
+ }
+ if (*pair) {
+ if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) {
+ *uid = pw.pw_uid;
+ } else
+ smb_error(dgettext(TEXT_DOMAIN,
+ "Invalid user name %s, ignored"), 0, pair);
+ }
+
+ return (0);
+}
+
+/*
+ * Commands use this with getopt. See:
+ * STDPARAM_OPT, STDPARAM_ARGS
+ * Called after smb_ctx_readrc().
+ */
+int
+smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
+{
+ int error = 0;
+ char *p, *cp;
+ char tmp[1024];
+
+ switch (opt) {
+ case 'A':
+ case 'U':
+ /* Handled in smb_ctx_init() */
+ break;
+ case 'I':
+ 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;
+ }
+ break;
+ case 'N':
+ ctx->ct_flags |= SMBCF_NOPWD;
+ break;
+ 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);
+ }
+ free(p);
+ break;
+ case 'P':
+/* ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT; */
+ break;
+ case 'R':
+ ctx->ct_ssn.ioc_retrycount = atoi(arg);
+ break;
+ case 'T':
+ ctx->ct_ssn.ioc_timeout = atoi(arg);
+ break;
+ case 'W':
+ nls_str_upper(tmp, arg);
+ error = smb_ctx_setworkgroup(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
+
+
+static int
+smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
+{
+ int error;
+
+ /*
+ * 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,
+ "can not setup kernel iconv table (%s:%s)"),
+ error, from, to);
+ return (error);
+ }
+#endif
+ return (0);
+}
+
+/*
+ * Verify context before connect operation(s),
+ * lookup specified server and try to fill all forgotten fields.
+ */
+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;
+ uchar_t cstbl[256];
+ uint_t i;
+ int error = 0;
+ int browseok = ctx->ct_flags & SMBCF_BROWSEOK;
+ int renego = 0;
+
+ ctx->ct_flags &= ~SMBCF_RESOLVED;
+ if (isatty(STDIN_FILENO))
+ browseok = 0;
+ if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == 0) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "no server name specified"), 0);
+ return (EINVAL);
+ }
+ if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0 &&
+ !browseok) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "no share name specified for %s@%s"),
+ 0, ssn->ioc_user, ssn->ioc_srvname);
+ return (EINVAL);
+ }
+ error = nb_ctx_resolve(ctx->ct_nb);
+ if (error)
+ return (error);
+ if (ssn->ioc_localcs[0] == 0)
+ strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */
+ error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
+ if (error)
+ return (error);
+ error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
+ if (error)
+ return (error);
+ if (ssn->ioc_servercs[0] != 0) {
+ for (i = 0; i < sizeof (cstbl); i++)
+ cstbl[i] = i;
+ nls_mem_toext(cstbl, cstbl, sizeof (cstbl));
+ error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs,
+ cstbl);
+ if (error)
+ return (error);
+ for (i = 0; i < sizeof (cstbl); i++)
+ cstbl[i] = i;
+ nls_mem_toloc(cstbl, cstbl, sizeof (cstbl));
+ error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs,
+ cstbl);
+ 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);
+ }
+
+ /*
+ * 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.
+ */
+ 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).
+ */
+ }
+ if (error) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "can't get server address"), error);
+ return (error);
+ }
+
+ /* 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_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);
+ /*
+ * A share was selected, authenticate button was pressed,
+ * or anon-authentication failed getting browse list.
+ */
+ }
+ if ((ctx->ct_secblob == NULL) && (ctx->ct_flags & SMBCF_AUTHREQ ||
+ (ssn->ioc_password[0] == '\0' &&
+ !(ctx->ct_flags & SMBCF_NOPWD)))) {
+reauth:
+ /*
+ * 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.
+ */
+ 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);
+ /*
+ * Re-authenticate button was pressed?
+ */
+ 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);
+ }
+ }
+ ctx->ct_flags |= SMBCF_RESOLVED;
+
+ if (smb_debug)
+ dump_ctx("after smb_ctx_resolve", ctx);
+
+ return (0);
+}
+
+int
+smb_open_driver()
+{
+ char buf[20];
+ int err, fd, i;
+ 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);
+ }
+ 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 (version != NSMB_VERSION) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "incorrect driver version"), 0);
+ close(fd);
+ return (-1);
+ }
+
+ return (fd);
+}
+
+static int
+smb_ctx_gethandle(struct smb_ctx *ctx)
+{
+ int err, fd;
+
+ if (ctx->ct_fd != -1) {
+ rpc_cleanup_smbctx(ctx);
+ close(ctx->ct_fd);
+ ctx->ct_fd = -1;
+ ctx->ct_flags &= ~SMBCF_SSNACTIVE;
+ }
+
+ fd = smb_open_driver();
+ if (fd < 0)
+ return (ENODEV);
+
+ ctx->ct_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; */
+
+ seteuid(eff_uid); /* restore setuid root briefly */
+ 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:
+ seteuid(real_uid); /* and back to real user */
+ return (rc);
+}
+
+
+/*
+ * adds a GSSAPI wrapper
+ */
+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)
+{
+ 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;
+
+ /*
+ * 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
+};
+
+/*
+ * 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;
+ }
+ 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.
+ */
+ 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";
+ /*
+ * Avoid logging the typical "No credentials cache found"
+ */
+ 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);
+}
+
+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";
+ }
+ 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");
+}
+#endif
+
+
+/*
+ * We navigate the SPNEGO & ASN1 encoding to find a kerberos principal
+ * Note: driver no longer puts length at start of blob.
+ */
+char *
+smb_ctx_blob2principal(
+ struct smb_ctx *ctx,
+ smbioc_ossn_t *ssn,
+ char **prinp)
+{
+ 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
+
+ /* 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";
+ }
+ return (failure);
+}
+
+
+int
+smb_ctx_negotiate(struct smb_ctx *ctx, int level, int flags, char *workgroup)
+{
+ struct smbioc_lookup rq;
+ int error = 0;
+ char *failure = NULL;
+ char *principal = NULL;
+ char c;
+ int i;
+ ssize_t *outtoklen;
+ uchar_t *blob;
+
+ /*
+ * 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);
+ 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;
+
+ /* 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;
+
+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! */
+
+ /*
+ * Negotiate failed with "extended 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
+ */
+ if (smb_verbose) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s (extended security negotiate)"), error, failure);
+ }
+
+ /*
+ * 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.
+ */
+ 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);
+ }
+
+ /*
+ * 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.
+ */
+
+ return (error);
+}
+
+
+int
+smb_ctx_tdis(struct smb_ctx *ctx)
+{
+ struct smbioc_lookup rq; /* XXX may be used, someday */
+ int error = 0;
+
+ if (ctx->ct_fd < 0) {
+ 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);
+ }
+ return (error);
+}
+
+
+int
+smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags)
+{
+ 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);
+ 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
+ */
+ seteuid(eff_uid); /* restore setuid root briefly */
+ 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");
+ }
+
+out:
+ seteuid(real_uid); /* and back to real user */
+ if (failure) {
+ error = errno;
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s phase failed"), error, failure);
+ }
+ return (error);
+}
+
+/*
+ * Return the hflags2 word for an smb_ctx.
+ */
+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);
+ }
+ printf(dgettext(TEXT_DOMAIN, "Flags2 value is %d\n"), flags2);
+ return (flags2);
+}
+
+/*
+ * level values:
+ * 0 - default
+ * 1 - server
+ * 2 - server:user
+ * 3 - server:user:share
+ */
+static int
+smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
+{
+ char *p;
+ int error;
+
+#ifdef NOT_DEFINED
+ if (level > 0) {
+ rc_getstringptr(smb_rc, sname, "charsets", &p);
+ if (p) {
+ error = smb_ctx_setcharset(ctx, p);
+ if (error)
+ smb_error(dgettext(TEXT_DOMAIN,
+ "charset specification in the section '%s' ignored"),
+ error, sname);
+ }
+ }
+#endif
+
+ 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 {
+ /*
+ * Unknown minimum authentication level.
+ */
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid minimum authentication level \"%s\" specified in the section %s"),
+ 0, p, sname);
+ return (EINVAL);
+ }
+ }
+
+ /*
+ * Domain name. Allow both keywords:
+ * "workgroup", "domain"
+ *
+ * Note: these are NOT marked "from CMD".
+ * See long comment at smb_ctx_init()
+ */
+ rc_getstringptr(smb_rc, sname, "workgroup", &p);
+ if (p) {
+ nls_str_upper(p, p);
+ error = smb_ctx_setworkgroup(ctx, p, 0);
+ if (error)
+ smb_error(dgettext(TEXT_DOMAIN,
+ "workgroup specification in the "
+ "section '%s' ignored"), error, sname);
+ }
+ rc_getstringptr(smb_rc, sname, "domain", &p);
+ if (p) {
+ nls_str_upper(p, p);
+ error = smb_ctx_setworkgroup(ctx, p, 0);
+ if (error)
+ smb_error(dgettext(TEXT_DOMAIN,
+ "domain specification in the "
+ "section '%s' ignored"), error, sname);
+ }
+
+ rc_getstringptr(smb_rc, sname, "user", &p);
+ if (p) {
+ error = smb_ctx_setuser(ctx, p, 0);
+ if (error)
+ smb_error(dgettext(TEXT_DOMAIN,
+ "user specification in the "
+ "section '%s' ignored"), error, sname);
+ }
+ }
+
+ if (level == 1) {
+ /* Section is: [server] */
+ rc_getstringptr(smb_rc, sname, "addr", &p);
+ if (p) {
+ error = smb_ctx_setsrvaddr(ctx, p);
+ if (error) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "invalid address specified in section %s"),
+ 0, sname);
+ return (error);
+ }
+ }
+ }
+
+ rc_getstringptr(smb_rc, sname, "password", &p);
+ if (p) {
+ error = smb_ctx_setpassword(ctx, p, 0);
+ if (error)
+ smb_error(dgettext(TEXT_DOMAIN,
+ "password specification in the section '%s' ignored"),
+ error, sname);
+ }
+
+ return (0);
+}
+
+/*
+ * read rc file as follows:
+ * 0: read [default] section
+ * 1: override with [server] section
+ * 2: override with [server:user] section
+ * 3: override with [server:user:share] section
+ * Since absence of rcfile is not fatal, silently ignore this fact.
+ * smb_rc file should be closed by caller.
+ */
+int
+smb_ctx_readrc(struct smb_ctx *ctx)
+{
+ char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN +
+ SMB_MAXSHARENAMELEN + 4];
+
+ if (smb_open_rcfile(ctx) != 0)
+ goto done;
+
+ /*
+ * default parameters (level=0)
+ */
+ smb_ctx_readrcsection(ctx, "default", 0);
+ nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
+
+ /*
+ * 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)
+ goto done;
+
+ /*
+ * SERVER parameters.
+ */
+ smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 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)
+ goto done;
+
+ /*
+ * SERVER:USER parameters
+ */
+ snprintf(sname, sizeof (sname), "%s:%s",
+ ctx->ct_ssn.ioc_srvname,
+ ctx->ct_ssn.ioc_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);
+ }
+
+done:
+ if (smb_debug)
+ dump_ctx("after smb_ctx_readrc", ctx);
+
+ return (0);
+}
diff --git a/usr/src/lib/libsmbfs/smb/derparse.c b/usr/src/lib/libsmbfs/smb/derparse.c
new file mode 100644
index 0000000000..cc7d61c6bd
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/derparse.c
@@ -0,0 +1,750 @@
+/*
+// Copyright (C) 2002 Microsoft Corporation
+// All rights reserved.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+// OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Date - 10/08/2002
+// Author - Sanj Surati
+
+
+/////////////////////////////////////////////////////////////
+//
+// DERPARSE.C
+//
+// SPNEGO Token Handler Source File
+//
+// Contains implementation of ASN.1 DER read/write functions
+// as defined in DERPARSE.H.
+//
+/////////////////////////////////////////////////////////////
+
+*/
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include <sys/byteorder.h>
+#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 [] =
+{
+ {"\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02", 11, 9,
+ spnego_mech_oid_Kerberos_V5_Legacy }, // 1.2.840.48018.1.2.2
+ {"\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02", 11, 9,
+ spnego_mech_oid_Kerberos_V5 }, // 1.2.840.113554.1.2.2
+ {"\x06\x06\x2b\x06\x01\x05\x05\x02", 8, 6,
+ spnego_mech_oid_Spnego }, // 1.3.6.1.5.5.2
+ {"\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a", 12, 10,
+ spnego_mech_oid_NTLMSSP }, // 1.3.6.1.4.1.311.2.2.10
+ {"", 0, 0, spnego_mech_oid_NotUsed } // Placeholder
+};
+#pragma error_messages (default,E_INITIALIZATION_TYPE_MISMATCH)
+
+/*
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// ASNDerGetLength
+//
+// Parameters:
+// [in] pbLengthData - DER Length Data
+// [in] nBoundaryLength - Length that value must not exceed.
+// [out] pnLength - Filled out with length value
+// [out] pnNumLengthBytes - Filled out with number of bytes
+// consumed by DER length.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Interprets the data at pbLengthData as a DER length. The length must
+// fit within the bounds of nBoundary length. We do not currently
+// process lengths that take more than 4 bytes.
+//
+////////////////////////////////////////////////////////////////////////////
+*/
+
+int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength,
+ long* pnNumLengthBytes )
+{
+ int nReturn = SPNEGO_E_INVALID_LENGTH;
+ int nNumLengthBytes = 0;
+
+ // First check if the extended length bit is set
+
+ if ( *pbLengthData & LEN_XTND )
+ {
+ // Lower 7 bits contain the number of trailing bytes that describe the length
+ nNumLengthBytes = *pbLengthData & LEN_MASK;
+
+ // Check that the number of bytes we are about to read is within our boundary
+ // constraints
+
+ if ( nNumLengthBytes <= nBoundaryLength - 1 )
+ {
+
+ // For now, our handler won't deal with lengths greater than 4 bytes
+ if ( nNumLengthBytes >= 1 && nNumLengthBytes <= 4 )
+ {
+ // 0 out the initial length
+ *pnLength = 0L;
+
+ // Bump by 1 byte
+ pbLengthData++;
+
+ #ifdef _LITTLE_ENDIAN
+
+ // There may be a cleaner way to do this, but for now, this seems to be
+ // an easy way to do the transformation
+ switch ( nNumLengthBytes )
+ {
+ case 1:
+ {
+ *( ( (unsigned char*) pnLength ) ) = *pbLengthData;
+ break;
+ }
+
+ case 2:
+ {
+ *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 1);
+ *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData);
+
+ break;
+ }
+
+ case 3:
+ {
+ *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 2);
+ *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1);
+ *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData);
+ break;
+ }
+
+ case 4:
+ {
+ *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 3);
+ *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData + 2);
+ *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1);
+ *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData);
+ break;
+ }
+
+ } // SWITCH ( nNumLengthBytes )
+
+ #else
+ // We are Big-Endian, so the length can be copied in from the source
+ // as is. Ensure that we adjust for the number of bytes we actually
+ // copy.
+
+ memcpy( ( (unsigned char *) pnLength ) + ( 4 - nNumLengthBytes ),
+ pbLengthData, nNumLengthBytes );
+ #endif
+
+ // Account for the initial length byte
+ *pnNumLengthBytes = nNumLengthBytes + 1;
+ nReturn = SPNEGO_E_SUCCESS;
+
+ } // IF Valid Length
+
+ } // IF num bytes to read is within the boundary length
+
+ } // IF xtended length
+ else
+ {
+
+ // Extended bit is not set, so the length is in the value and the one
+ // byte describes the length
+ *pnLength = *pbLengthData & LEN_MASK;
+ *pnNumLengthBytes = 1;
+ nReturn = SPNEGO_E_SUCCESS;
+
+ }
+
+ return nReturn;
+}
+
+
+/*
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// ASNDerCheckToken
+//
+// Parameters:
+// [in] pbTokenData - Token Data
+// [in] nToken - Token identifier to check for
+// [in] nLengthWithToken - Expected token length (with data)
+// [in] nBoundaryLength - Length that value must not exceed.
+// [out] pnLength - Filled out with data length
+// [out] pnTokenLength - Filled out with number of bytes
+// consumed by token identifier and length.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Checks the data pointed to by pbTokenData for the specified token
+// identifier and the length that immediately follows. If
+// nLengthWithToken is > 0, the calculated length must match. The
+// length must also not exceed the specified boundary length .
+//
+////////////////////////////////////////////////////////////////////////////
+*/
+
+int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken,
+ long nLengthWithToken, long nBoundaryLength,
+ long* pnLength, long* pnTokenLength )
+{
+
+ int nReturn = SPNEGO_E_INVALID_LENGTH;
+ long nNumLengthBytes = 0L;
+
+ // Make sure that we've at least got 2 bytes of room to work with
+
+ if ( nBoundaryLength >= 2 )
+ {
+ // The first byte of the token data MUST match the specified token
+ if ( *pbTokenData == nToken )
+ {
+ // Next byte indicates the length
+ pbTokenData++;
+
+ // Get the length described by the token
+ if ( ( nReturn = ASNDerGetLength( pbTokenData, nBoundaryLength, pnLength,
+ &nNumLengthBytes ) ) == SPNEGO_E_SUCCESS )
+ {
+ // Verify that the length is LESS THAN the boundary length
+ // (this should prevent us walking out of our buffer)
+ if ( ( nBoundaryLength - ( nNumLengthBytes + 1 ) < *pnLength ) )
+ {
+
+ nReturn = SPNEGO_E_INVALID_LENGTH;
+
+ }
+
+ // If we were passed a length to check, do so now
+ if ( nLengthWithToken > 0L )
+ {
+
+ // Check that the expected length matches
+ if ( ( nLengthWithToken - ( nNumLengthBytes + 1 ) ) != *pnLength )
+ {
+
+ nReturn = SPNEGO_E_INVALID_LENGTH;
+
+ }
+
+ } // IF need to validate length
+
+ if ( SPNEGO_E_SUCCESS == nReturn )
+ {
+ *pnTokenLength = nNumLengthBytes + 1;
+ }
+
+ } // IF ASNDerGetLength
+
+ } // IF token matches
+ else
+ {
+ nReturn = SPNEGO_E_TOKEN_NOT_FOUND;
+ }
+
+ } // IF Boundary Length is at least 2 bytes
+
+ return nReturn;
+}
+
+/*
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// ASNDerCheckOID
+//
+// Parameters:
+// [in] pbTokenData - Token Data
+// [in] nMechOID - OID we are looking for
+// [in] nBoundaryLength - Length that value must not exceed.
+// [out] pnTokenLength - Filled out with number of bytes
+// consumed by token and data.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Checks the data pointed to by pbTokenData for the specified OID.
+//
+////////////////////////////////////////////////////////////////////////////
+*/
+
+int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength,
+ long* pnTokenLength )
+{
+ int nReturn = 0L;
+ long nLength = 0L;
+
+ // Verify that we have an OID token
+ if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID, 0L, nBoundaryLength,
+ &nLength, pnTokenLength ) ) == SPNEGO_E_SUCCESS )
+ {
+ // Add the data length to the Token Length
+ *pnTokenLength += nLength;
+
+ // Token Lengths plus the actual length must match the length in our OID list element.
+ // If it doesn't, we're done
+ if ( *pnTokenLength == g_stcMechOIDList[nMechOID].iLen )
+ {
+ // Memcompare the token and the expected field
+ if ( memcmp( pbTokenData, g_stcMechOIDList[nMechOID].ucOid, *pnTokenLength ) != 0 )
+ {
+ nReturn = SPNEGO_E_UNEXPECTED_OID;
+ }
+ }
+ else
+ {
+ nReturn = SPNEGO_E_UNEXPECTED_OID;
+ }
+
+ } // IF OID Token CHecks
+
+ return nReturn;
+}
+
+/*
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// ASNDerCalcNumLengthBytes
+//
+// Parameters:
+// [in] nLength - Length to calculate length bytes for.
+//
+// Returns:
+// int Number of bytes necessary to represent length
+//
+// Comments :
+// Helper function to calculate the number of length bytes necessary to
+// represent a length value. For our purposes, a 32-bit value should be
+// enough to describea length.
+//
+////////////////////////////////////////////////////////////////////////////
+*/
+
+int ASNDerCalcNumLengthBytes( long nLength )
+{
+ if ( nLength <= 0x7F )
+ {
+ // A single byte will be sufficient for describing this length.
+ // The byte will simply contain the length
+ return 1;
+ }
+ else if ( nLength <= 0xFF )
+ {
+ // Two bytes are necessary, one to say how many following bytes
+ // describe the length, and one to give the length
+ return 2;
+ }
+ else if ( nLength <= 0xFFFF )
+ {
+ // Three bytes are necessary, one to say how many following bytes
+ // describe the length, and two to give the length
+ return 3;
+ }
+ else if ( nLength <= 0xFFFFFF )
+ {
+ // Four bytes are necessary, one to say how many following bytes
+ // describe the length, and three to give the length
+ return 4;
+ }
+ else
+ {
+ // Five bytes are necessary, one to say how many following bytes
+ // describe the length, and four to give the length
+ return 5;
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// ASNDerCalcTokenLength
+//
+// Parameters:
+// [in] nLength - Length to calculate length bytes for.
+// [in] nDataLength - Actual Data length value.
+//
+// Returns:
+// long Number of bytes necessary to represent a token, length and data
+//
+// Comments :
+// Helper function to calculate a token and value size, based on a
+// supplied length value, and any binary data that will need to be
+// written out.
+//
+////////////////////////////////////////////////////////////////////////////
+
+long ASNDerCalcTokenLength( long nLength, long nDataLength )
+{
+ // Add a byte to the length size to account for a single byte to
+ // hold the token type.
+ long nTotalLength = ASNDerCalcNumLengthBytes( nLength ) + 1;
+
+ return nTotalLength + nDataLength;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// ASNDerCalcElementLength
+//
+// Parameters:
+// [in] nDataLength - Length of data.
+// [out] pnInternalLength - Filled out with length of element
+// without sequence info.
+//
+// Returns:
+// long Number of bytes necessary to represent an element
+//
+// Comments :
+// Helper function to calculate an element length. An element consists
+// of a sequence token, a type token and then the data.
+//
+////////////////////////////////////////////////////////////////////////////
+
+long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength )
+{
+ // First the type token and the actual data
+ long nTotalLength = ASNDerCalcTokenLength( nDataLength, nDataLength );
+
+ // Internal length is the length without the element sequence token
+ if ( NULL != pnInternalLength )
+ {
+ *pnInternalLength = nTotalLength;
+ }
+
+ // Next add in the element's sequence token (remember that its
+ // length is the total length of the type token and data)
+ nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+ return nTotalLength;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// ASNDerCalcMechListLength
+//
+// Parameters:
+// [in] mechoid - Mech OID to put in list.
+// [out] pnInternalLength - Filled out with length of element
+// without the primary sequence token.
+//
+// Returns:
+// long Number of bytes necessary to represent a mechList
+//
+// Comments :
+// Helper function to calculate a MechList length. A mechlist consists
+// of a NegTokenInit sequence token, a sequence token for the MechList
+// and finally a list of OIDs. In our case, we only really have one
+// OID.
+//
+////////////////////////////////////////////////////////////////////////////
+
+long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength )
+{
+ // First the OID
+ long nTotalLength = g_stcMechOIDList[mechoid].iLen;
+
+ // Next add in a sequence token
+ nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+ // Internal length is the length without the element sequence token
+ if ( NULL != pnInternalLength )
+ {
+ *pnInternalLength = nTotalLength;
+ }
+
+ // Finally add in the element's sequence token
+ nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+ return nTotalLength;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// ASNDerWriteLength
+//
+// Parameters:
+// [out] pbData - Buffer to write into.
+// [in] nLength - Length to write out.
+//
+// Returns:
+// int Number of bytes written out
+//
+// Comments :
+// Helper function to write out a length value following DER rules .
+//
+////////////////////////////////////////////////////////////////////////////
+
+int ASNDerWriteLength( unsigned char* pbData, long nLength )
+{
+ int nNumBytesRequired = ASNDerCalcNumLengthBytes( nLength );
+ int nNumLengthBytes = nNumBytesRequired - 1;
+
+
+ if ( nNumBytesRequired > 1 )
+ {
+
+ // Write out the number of bytes following which will be used
+ *pbData = (unsigned char ) ( LEN_XTND | nNumLengthBytes );
+
+ // Point to where we'll actually write the length
+ pbData++;
+
+#ifdef _LITTLE_ENDIAN
+
+ // There may be a cleaner way to do this, but for now, this seems to be
+ // an easy way to do the transformation
+ switch ( nNumLengthBytes )
+ {
+ case 1:
+ {
+ // Cast the length to a single byte, since we know that it
+ // is 0x7F or less (or we wouldn't only need a single byte).
+
+ *pbData = (unsigned char) nLength;
+ break;
+ }
+
+ case 2:
+ {
+ *pbData = *( ( (unsigned char*) &nLength ) + 1 );
+ *( pbData + 1) = *( ( (unsigned char*) &nLength ) );
+ break;
+ }
+
+ case 3:
+ {
+ *pbData = *( ( (unsigned char*) &nLength ) + 3 );
+ *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 );
+ *( pbData + 2) = *( ( (unsigned char*) &nLength ) );
+ break;
+ }
+
+ case 4:
+ {
+ *pbData = *( ( (unsigned char*) &nLength ) + 3 );
+ *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 );
+ *( pbData + 2) = *( ( (unsigned char*) &nLength ) + 1 );
+ *( pbData + 3) = *( ( (unsigned char*) &nLength ) );
+ break;
+ }
+
+ } // SWITCH ( nNumLengthBytes )
+
+#else
+ // We are Big-Endian, so the length can be copied in from the source
+ // as is. Ensure that we adjust for the number of bytes we actually
+ // copy.
+
+ memcpy( pbData,
+ ( (unsigned char *) &nLength ) + ( 4 - nNumLengthBytes ), nNumLengthBytes );
+#endif
+
+ } // IF > 1 byte for length
+ else
+ {
+ // Cast the length to a single byte, since we know that it
+ // is 0x7F or less (or we wouldn't only need a single byte).
+
+ *pbData = (unsigned char) nLength;
+ }
+
+ return nNumBytesRequired;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// ASNDerWriteToken
+//
+// Parameters:
+// [out] pbData - Buffer to write into.
+// [in] ucType - Token Type
+// [in] pbTokenValue - Actual Value
+// [in] nLength - Length of Data.
+//
+// Returns:
+// int Number of bytes written out
+//
+// Comments :
+// Helper function to write out a token and any associated data. If
+// pbTokenValue is non-NULL, then it is written out in addition to the
+// token identifier and the length bytes.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType,
+ unsigned char* pbTokenValue, long nLength )
+{
+ int nTotalBytesWrittenOut = 0L;
+ int nNumLengthBytesWritten = 0L;
+
+ // Write out the type
+ *pbData = ucType;
+
+ // Wrote 1 byte, and move data pointer
+ nTotalBytesWrittenOut++;
+ pbData++;
+
+ // Now write out the length and adjust the number of bytes written out
+ nNumLengthBytesWritten = ASNDerWriteLength( pbData, nLength );
+
+ nTotalBytesWrittenOut += nNumLengthBytesWritten;
+ pbData += nNumLengthBytesWritten;
+
+ // Write out the token value if we got one. The assumption is that the
+ // nLength value indicates how many bytes are in pbTokenValue.
+
+ if ( NULL != pbTokenValue )
+ {
+ memcpy( pbData, pbTokenValue, nLength );
+ nTotalBytesWrittenOut += nLength;
+ }
+
+ return nTotalBytesWrittenOut;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// ASNDerWriteOID
+//
+// Parameters:
+// [out] pbData - Buffer to write into.
+// [in] eMechOID - OID to write out.
+//
+// Returns:
+// int Number of bytes written out
+//
+// Comments :
+// Helper function to write out an OID. For these we have the raw bytes
+// listed in a global structure. The caller simply indicates which OID
+// should be written and we will splat out the data.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID )
+{
+
+ memcpy( pbData, g_stcMechOIDList[eMechOID].ucOid, g_stcMechOIDList[eMechOID].iLen );
+
+ return g_stcMechOIDList[eMechOID].iLen;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// ASNDerWriteMechList
+//
+// Parameters:
+// [out] pbData - Buffer to write into.
+// [in] eMechOID - OID to put in MechList.
+//
+// Returns:
+// int Number of bytes written out
+//
+// Comments :
+// Helper function to write out a MechList. A MechList consists of the
+// Init Token Sequence, a sequence token and then the list of OIDs. In
+// our case the OID is from a global array of known OIDs.
+//
+////////////////////////////////////////////////////////////////////////////
+
+long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid )
+{
+ // First get the length
+ long nInternalLength = 0L;
+ long nMechListLength = ASNDerCalcMechListLength( mechoid, &nInternalLength );
+ long nTempLength = 0L;
+
+ nTempLength = ASNDerWriteToken( pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES,
+ NULL, nInternalLength );
+
+ // Adjust the data pointer
+ pbData += nTempLength;
+
+ // Now write the Sequence token and the OID (the OID is a BLOB in the global
+ // structure.
+
+ nTempLength = ASNDerWriteToken( pbData, SPNEGO_CONSTRUCTED_SEQUENCE,
+ g_stcMechOIDList[mechoid].ucOid,
+ g_stcMechOIDList[mechoid].iLen );
+
+ return nMechListLength;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// ASNDerWriteElement
+//
+// Parameters:
+// [out] pbData - Buffer to write into.
+// [in] ucElementSequence - Sequence Token
+// [in] ucType - Token Type
+// [in] pbTokenValue - Actual Value
+// [in] nLength - Length of Data.
+//
+// Returns:
+// int Number of bytes written out
+//
+// Comments :
+// Helper function to write out a SPNEGO Token element. An element
+// consists of a sequence token, a type token and the associated data.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int ASNDerWriteElement( unsigned char* pbData, unsigned char ucElementSequence,
+ unsigned char ucType, unsigned char* pbTokenValue, long nLength )
+{
+ // First get the length
+ long nInternalLength = 0L;
+ long nElementLength = ASNDerCalcElementLength( nLength, &nInternalLength );
+ long nTempLength = 0L;
+
+ // Write out the sequence byte and the length of the type and data
+ nTempLength = ASNDerWriteToken( pbData, ucElementSequence, NULL, nInternalLength );
+
+ // Adjust the data pointer
+ pbData += nTempLength;
+
+ // Now write the type and the data.
+ nTempLength = ASNDerWriteToken( pbData, ucType, pbTokenValue, nLength );
+
+ return nElementLength;
+}
diff --git a/usr/src/lib/libsmbfs/smb/derparse.h b/usr/src/lib/libsmbfs/smb/derparse.h
new file mode 100644
index 0000000000..dcdf5828dc
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/derparse.h
@@ -0,0 +1,196 @@
+// Copyright (C) 2002 Microsoft Corporation
+// All rights reserved.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+// OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Date - 10/08/2002
+// Author - Sanj Surati
+
+/////////////////////////////////////////////////////////////
+//
+// DERPARSE.H
+//
+// SPNEGO Token Handler Header File
+//
+// Contains the definitions required to properly parse the
+// SPNEGO DER encoding.
+//
+/////////////////////////////////////////////////////////////
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifndef __DERPARSE_H__
+#define __DERPARSE_H__
+
+// C++ Specific
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/* Identifier Types */
+#define IDENTIFIER_MASK 0xC0 // Bits 7 and 8
+#define IDENTIFIER_UNIVERSAL 0x00 // 00 = universal
+#define IDENTIFIER_APPLICATION 0x40 // 01 = application
+#define IDENTIFIER_CONTEXT_SPECIFIC 0x80 // 10 = context specific
+#define IDENTIFIER_PRIVATE 0xC0 // 11 = Private
+
+/* Encoding type */
+
+#define FORM_MASK 0x20 /* Bit 6 */
+#define PRIMITIVE 0x00 /* 0 = primitive */
+#define CONSTRUCTED 0x20 /* 1 = constructed */
+
+/* Universal tags */
+
+#define TAG_MASK 0x1F /* Bits 5 - 1 */
+#define BOOLEAN 0x01 /* 1: TRUE or FALSE */
+#define INTEGER 0x02 /* 2: Arbitrary precision integer */
+#define BITSTRING 0x03 /* 2: Sequence of bits */
+#define OCTETSTRING 0x04 /* 4: Sequence of bytes */
+#define NULLTAG 0x05 /* 5: NULL */
+#define OID 0x06 /* 6: Object Identifier (numeric sequence) */
+#define OBJDESCRIPTOR 0x07 /* 7: Object Descriptor (human readable) */
+#define EXTERNAL 0x08 /* 8: External / Instance Of */
+#define REAL 0x09 /* 9: Real (Mantissa * Base^Exponent) */
+#define ENUMERATED 0x0A /* 10: Enumerated */
+#define EMBEDDED_PDV 0x0B /* 11: Embedded Presentation Data Value */
+#define SEQUENCE 0x10 /* 16: Constructed Sequence / Sequence Of */
+#define SET 0x11 /* 17: Constructed Set / Set Of */
+#define NUMERICSTR 0x12 /* 18: Numeric String (digits only) */
+#define PRINTABLESTR 0x13 /* 19: Printable String */
+#define T61STR 0x14 /* 20: T61 String (Teletex) */
+#define VIDEOTEXSTR 0x15 /* 21: Videotex String */
+#define IA5STR 0x16 /* 22: IA5 String */
+#define UTCTIME 0x17 /* 23: UTC Time */
+#define GENERALIZEDTIME 0x18 /* 24: Generalized Time */
+#define GRAPHICSTR 0x19 /* 25: Graphic String */
+#define VISIBLESTR 0x1A /* 26: Visible String (ISO 646) */
+#define GENERALSTR 0x1B /* 27: General String */
+#define UNIVERSALSTR 0x1C /* 28: Universal String */
+#define BMPSTR 0x1E /* 30: Basic Multilingual Plane String */
+
+/* Length encoding */
+
+#define LEN_XTND 0x80 /* Indefinite or long form */
+#define LEN_MASK 0x7f /* Bits 7 - 1 */
+
+#define SEQ_ELM(n) (IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | ((n)&TAG_MASK))
+
+//
+// SPNEGO Token Parsing Constants
+//
+
+
+// Fixed Length of NegTokenInit ReqFlags field
+#define SPNEGO_NEGINIT_MAXLEN_REQFLAGS 2
+
+// Difference in bits for ReqFlags token
+#define SPNEGO_NEGINIT_REQFLAGS_BITDIFF 1
+
+// Fixed Length of NegTokenTarg NegResult field
+#define SPNEGO_NEGTARG_MAXLEN_NEGRESULT 1
+
+// Application Specific Construct - Always at the start of a NegTokenInit
+#define SPNEGO_NEGINIT_APP_CONSTRUCT ( IDENTIFIER_APPLICATION | CONSTRUCTED ) // 0x60
+
+// Constructed Sequence token - after the actual token identifier token
+#define SPNEGO_CONSTRUCTED_SEQUENCE ( SEQUENCE | CONSTRUCTED )
+
+// MechList Type Identifier
+#define SPNEGO_MECHLIST_TYPE ( SEQUENCE | CONSTRUCTED | OID )
+
+//
+// NegTokenInit - Token Identifier and Elements
+//
+
+// NegTokenInit - 0xa0
+#define SPNEGO_NEGINIT_TOKEN_IDENTIFIER ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \
+ SPNEGO_TOKEN_INIT )
+
+// Structure elements for NegTokenInit
+#define SPNEGO_NEGINIT_MECHTYPES 0x0 // MechTypes is element 0
+#define SPNEGO_NEGINIT_REQFLAGS 0x1 // ReqFlags is element 1
+#define SPNEGO_NEGINIT_MECHTOKEN 0x2 // MechToken is element 2
+#define SPNEGO_NEGINIT_MECHLISTMIC 0x3 // MechListMIC is element 3
+
+// MechTypes element is 0xa0
+#define SPNEGO_NEGINIT_ELEMENT_MECHTYPES SEQ_ELM(SPNEGO_NEGINIT_MECHTYPES)
+// ReqFlags element is 0xa1
+#define SPNEGO_NEGINIT_ELEMENT_REQFLAGS SEQ_ELM(SPNEGO_NEGINIT_REQFLAGS)
+// MechToken element is 0xa2
+#define SPNEGO_NEGINIT_ELEMENT_MECHTOKEN SEQ_ELM(SPNEGO_NEGINIT_MECHTOKEN)
+// MechListMIC element is 0xa3
+#define SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC SEQ_ELM(SPNEGO_NEGINIT_MECHLISTMIC)
+
+//
+// NegTokenTarg - Token Identifier and Elements
+//
+
+// NegTokenTarg - 0xa1
+#define SPNEGO_NEGTARG_TOKEN_IDENTIFIER ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \
+ SPNEGO_TOKEN_TARG )
+
+// Structure elements for NegTokenTarg
+#define SPNEGO_NEGTARG_NEGRESULT 0x0 // NegResult is element 0
+#define SPNEGO_NEGTARG_SUPPORTEDMECH 0x1 // SupportedMech is element 1
+#define SPNEGO_NEGTARG_RESPONSETOKEN 0x2 // ResponseToken is element 2
+#define SPNEGO_NEGTARG_MECHLISTMIC 0x3 // MechListMIC is element 3
+
+// NegResult element is 0xa0
+#define SPNEGO_NEGTARG_ELEMENT_NEGRESULT SEQ_ELM(SPNEGO_NEGTARG_NEGRESULT)
+// SupportedMech element is 0xa1
+#define SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH SEQ_ELM(SPNEGO_NEGTARG_SUPPORTEDMECH)
+// ResponseToken element is 0xa2
+#define SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN SEQ_ELM(SPNEGO_NEGTARG_RESPONSETOKEN)
+// MechListMIC element is 0xa3
+#define SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC SEQ_ELM(SPNEGO_NEGTARG_MECHLISTMIC)
+
+//
+// Defines a GSS Mechanism OID. We keep a single static array
+// of these which we'll use for validation/searches/parsing.
+//
+
+typedef struct _mechOID
+{
+ unsigned char* ucOid; // Byte representation of OID
+ int iLen; // Length of the OID, length and identifier
+ int iActualDataLen; // Length of the actual OID
+ SPNEGO_MECH_OID eMechanismOID; // Which OID is this?
+} MECH_OID;
+
+
+//
+// ASN Der functions
+//
+
+int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength,
+ long* pnNumLengthBytes );
+int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken,
+ long nCheckLength, long nBoundaryLength, long* pnLength,
+ long* pnTokenLength );
+int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength,
+ long* pnTokenLength );
+int ASNDerCalcNumLengthBytes( long nLength );
+long ASNDerCalcTokenLength( long nLength, long nDataLength );
+long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength );
+long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength );
+int ASNDerWriteLength( unsigned char* pbData, long nLength );
+int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType,
+ unsigned char* pbTokenValue, long nLength );
+int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID );
+long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid );
+int ASNDerWriteElement( unsigned char* pbData, unsigned char ucElementSequence,
+ unsigned char ucType, unsigned char* pbTokenValue, long nLength );
+
+
+ // C++ Specific
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/usr/src/lib/libsmbfs/smb/file.c b/usr/src/lib/libsmbfs/smb/file.c
new file mode 100644
index 0000000000..dd738e8d97
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/file.c
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ *
+ * $Id: file.c,v 1.4 2004/12/13 00:25:21 lindak Exp $
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+extern uid_t real_uid, eff_uid;
+
+#include <netsmb/smb_lib.h>
+#include <cflib.h>
+
+int
+smb_read(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count, char *dst)
+{
+ struct smbioc_rw rwrq;
+
+ bzero(&rwrq, sizeof (rwrq));
+ rwrq.ioc_fh = fh;
+ rwrq.ioc_base = dst;
+ rwrq.ioc_cnt = count;
+ rwrq.ioc_offset = offset;
+ seteuid(eff_uid);
+ if (ioctl(ctx->ct_fd, SMBIOC_READ, &rwrq) == -1) {
+ seteuid(real_uid); /* and back to real user */
+ return (-1);
+ }
+ seteuid(real_uid); /* and back to real user */
+ return (rwrq.ioc_cnt);
+}
+
+int
+smb_write(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
+ const char *src)
+{
+ struct smbioc_rw rwrq;
+
+ bzero(&rwrq, sizeof (rwrq));
+ rwrq.ioc_fh = fh;
+ rwrq.ioc_base = (char *)src;
+ rwrq.ioc_cnt = count;
+ rwrq.ioc_offset = offset;
+ seteuid(eff_uid);
+ if (ioctl(ctx->ct_fd, SMBIOC_WRITE, &rwrq) == -1) {
+ seteuid(real_uid); /* and back to real user */
+ return (-1);
+ }
+ seteuid(real_uid); /* and back to real user */
+ return (rwrq.ioc_cnt);
+}
diff --git a/usr/src/lib/libsmbfs/smb/keychain.c b/usr/src/lib/libsmbfs/smb/keychain.c
new file mode 100644
index 0000000000..72a979022f
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/keychain.c
@@ -0,0 +1,199 @@
+/*
+ * 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 2008 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
+ * the "smbutil" commands: login, logout, ...
+ * and by the SMBFS PAM module.
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <libintl.h>
+
+#include <netsmb/smb_dev.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/smb_keychain.h>
+
+#include <cflib.h>
+
+/* common func. for add/del/chk */
+static int
+smbfs_keychain_cmn(
+ int cmd,
+ uid_t uid,
+ const char *dom,
+ const char *usr,
+ const char *pass)
+{
+ smbioc_pk_t pk;
+ int err, fd;
+
+ memset(&pk, 0, sizeof (pk));
+
+ pk.pk_uid = uid;
+
+ 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);
+ /* 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);
+ 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
+ * common code path below.
+ */
+ break;
+
+ default:
+ return (SMB_KEYCHAIN_UNKNOWN);
+ }
+
+ fd = smb_open_driver();
+ if (fd < 0) {
+ err = SMB_KEYCHAIN_NODRIVER;
+ goto out;
+ }
+
+ err = 0;
+ if (ioctl(fd, cmd, &pk) < 0)
+ err = errno;
+
+ close(fd);
+out:
+ memset(&pk, 0, sizeof (pk));
+ return (err);
+}
+
+/* Add a password to the keychain. */
+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));
+}
+
+/* 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));
+}
+
+/*
+ * Check for existence of a keychain entry.
+ * Returns 0 if it exists, else ENOENT.
+ */
+int
+smbfs_keychain_chk(const char *dom, const char *usr)
+{
+ return (smbfs_keychain_cmn(SMBIOC_PK_CHK, (uid_t)-1, dom, usr, NULL));
+}
+
+/*
+ * Delete all keychain entries owned by the caller.
+ */
+int
+smbfs_keychain_del_owner()
+{
+ return (smbfs_keychain_cmn(SMBIOC_PK_DEL_OWNER, getuid(), 0, 0, 0));
+}
+
+/*
+ * Delete all keychain entries (regardless of onwer).
+ * Requires super-user privliege.
+ */
+int
+smbfs_keychain_del_everyone()
+{
+ return (smbfs_keychain_cmn(SMBIOC_PK_DEL_EVERYONE, getuid(), 0, 0, 0));
+}
+
+
+/*
+ * This is not really part of the keychain library,
+ * but is typically needed in code that wants to
+ * provide (editable) defaults for domain/user
+ *
+ * Get default domain and user names
+ * Server name is optional.
+ */
+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;
+ int err;
+
+ err = smb_ctx_init(ctx, 0, NULL, SMBL_VC, SMBL_VC, SMB_ST_ANY);
+ if (err)
+ return (err);
+ if (server)
+ smb_ctx_setserver(ctx, server);
+ if (home && *home)
+ ctx->ct_home = (char *)home;
+ err = smb_ctx_readrc(ctx);
+ if (err)
+ return (err);
+ if (smb_rc)
+ rc_close(smb_rc);
+
+ if (dom)
+ strlcpy(dom, ctx->ct_ssn.ioc_workgroup, maxdom);
+
+ if (usr)
+ strlcpy(usr, ctx->ct_ssn.ioc_user, maxusr);
+
+ return (0);
+}
diff --git a/usr/src/lib/libsmbfs/smb/llib-lsmbfs b/usr/src/lib/libsmbfs/smb/llib-lsmbfs
new file mode 100644
index 0000000000..05e1967055
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/llib-lsmbfs
@@ -0,0 +1,32 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <netsmb/smb_lib.h>
diff --git a/usr/src/lib/libsmbfs/smb/mapfile-vers b/usr/src/lib/libsmbfs/smb/mapfile-vers
new file mode 100644
index 0000000000..1dadbbe825
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/mapfile-vers
@@ -0,0 +1,72 @@
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate_1.0 {
+ global:
+ dropsuid;
+ nb_ctx_create;
+ nb_ctx_done;
+ nb_ctx_readrcsection;
+ nb_ctx_resolve;
+ nb_ctx_setns;
+ nb_resolvehost_in;
+ nbns_getnodestatus;
+ nbns_resolvename;
+ nls_str_upper;
+ rc_close;
+ rc_open;
+ smb_ctx_done;
+ smb_ctx_flags2;
+ smb_ctx_init;
+ smb_ctx_lookup;
+ smb_ctx_opt;
+ smb_ctx_readrc;
+ smb_ctx_resolve;
+ smb_ctx_setshare;
+ smb_ctx_tdis;
+ smb_debug;
+ smb_error;
+ smb_getprogname;
+ smb_lib_init;
+ smb_netshareenum;
+ smb_open_rcfile;
+ smb_simplecrypt;
+ smb_simpledecrypt;
+ smb_strerror;
+ smb_rc; # data
+ smb_read;
+ smb_write;
+ smb_verbose;
+ smbfs_default_dom_usr;
+ smbfs_keychain_add;
+ smbfs_keychain_chk;
+ smbfs_keychain_del;
+ smbfs_keychain_del_everyone;
+ smbfs_keychain_del_owner;
+ unpercent;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libsmbfs/smb/mbuf.c b/usr/src/lib/libsmbfs/smb/mbuf.c
new file mode 100644
index 0000000000..f03c4fedc3
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/mbuf.c
@@ -0,0 +1,476 @@
+/*
+ * 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.
+ *
+ * $Id: mbuf.c,v 1.3 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>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <libintl.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/mchain.h>
+
+#ifdef APPLE
+#define __func__ ""
+#define MBERROR(format, args...) \
+ printf("%s(%d): "format, __func__, __LINE__, ## args)
+#endif
+
+static int
+m_get(size_t len, struct mbuf **mpp)
+{
+ struct mbuf *m;
+
+ len = M_ALIGN(len);
+ if (len < M_MINSIZE)
+ len = M_MINSIZE;
+ m = malloc(M_BASESIZE + len);
+ if (m == NULL)
+ return (ENOMEM);
+ bzero(m, M_BASESIZE + len);
+ m->m_maxlen = len;
+ m->m_data = M_TOP(m);
+ *mpp = m;
+ return (0);
+}
+
+static void
+m_free(struct mbuf *m)
+{
+ free(m);
+}
+
+static void
+m_freem(struct mbuf *m0)
+{
+ struct mbuf *m;
+
+ while (m0) {
+ m = m0->m_next;
+ m_free(m0);
+ m0 = m;
+ }
+}
+
+static size_t
+m_totlen(struct mbuf *m0)
+{
+ struct mbuf *m = m0;
+ int len = 0;
+
+ while (m) {
+ len += m->m_len;
+ m = m->m_next;
+ }
+ return (len);
+}
+
+int
+m_lineup(struct mbuf *m0, struct mbuf **mpp)
+{
+ struct mbuf *nm, *m;
+ char *dp;
+ size_t len;
+ int error;
+
+ if (m0->m_next == NULL) {
+ *mpp = m0;
+ return (0);
+ }
+ if ((error = m_get(m_totlen(m0), &nm)) != 0)
+ return (error);
+ dp = mtod(nm, char *);
+ while (m0) {
+ len = m0->m_len;
+ bcopy(m0->m_data, dp, len);
+ dp += len;
+ m = m0->m_next;
+ m_free(m0);
+ m0 = m;
+ }
+ *mpp = nm;
+ return (0);
+}
+
+int
+mb_init(struct mbdata *mbp, size_t size)
+{
+ struct mbuf *m;
+ int error;
+
+ if ((error = m_get(size, &m)) != 0)
+ return (error);
+ return (mb_initm(mbp, m));
+}
+
+int
+mb_initm(struct mbdata *mbp, struct mbuf *m)
+{
+ bzero(mbp, sizeof (*mbp));
+ mbp->mb_top = mbp->mb_cur = m;
+ mbp->mb_pos = mtod(m, char *);
+ return (0);
+}
+
+int
+mb_done(struct mbdata *mbp)
+{
+ if (mbp->mb_top) {
+ m_freem(mbp->mb_top);
+ mbp->mb_top = NULL;
+ }
+ return (0);
+}
+
+int
+m_getm(struct mbuf *top, size_t len, struct mbuf **mpp)
+{
+ struct mbuf *m, *mp;
+ int error;
+
+ for (mp = top; ; mp = mp->m_next) {
+ len -= M_TRAILINGSPACE(mp);
+ if (mp->m_next == NULL)
+ break;
+
+ }
+ if (len > 0) {
+ if ((error = m_get(len, &m)) != 0)
+ return (error);
+ mp->m_next = m;
+ }
+ *mpp = top;
+ return (0);
+}
+
+/*
+ * Routines to put data in a buffer
+ */
+#define MB_PUT(t) int error; t *p; \
+ if ((error = mb_fit(mbp, sizeof (t), (char **)&p)) != 0) \
+ return (error)
+
+/*
+ * Check if object of size 'size' fit to the current position and
+ * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
+ * Return pointer to the object placeholder or NULL if any error occured.
+ */
+int
+mb_fit(struct mbdata *mbp, size_t size, char **pp)
+{
+ struct mbuf *m, *mn;
+ int error;
+
+ m = mbp->mb_cur;
+ if (M_TRAILINGSPACE(m) < (int)size) {
+ if ((error = m_get(size, &mn)) != 0)
+ return (error);
+ mbp->mb_pos = mtod(mn, char *);
+ mbp->mb_cur = m->m_next = mn;
+ m = mn;
+ }
+ m->m_len += size;
+ *pp = mbp->mb_pos;
+ mbp->mb_pos += size;
+ mbp->mb_count += size;
+ return (0);
+}
+
+int
+mb_put_uint8(struct mbdata *mbp, uint8_t x)
+{
+ MB_PUT(uint8_t);
+ *p = x;
+ return (0);
+}
+
+int
+mb_put_uint16be(struct mbdata *mbp, uint16_t x)
+{
+ MB_PUT(uint16_t);
+ /* LINTED */
+ setwbe(p, 0, x);
+ return (0);
+}
+
+int
+mb_put_uint16le(struct mbdata *mbp, uint16_t x)
+{
+ MB_PUT(uint16_t);
+ /* LINTED */
+ setwle(p, 0, x);
+ return (0);
+}
+
+int
+mb_put_uint32be(struct mbdata *mbp, uint32_t x)
+{
+ MB_PUT(uint32_t);
+ /* LINTED */
+ setdbe(p, 0, x);
+ return (0);
+}
+
+int
+mb_put_uint32le(struct mbdata *mbp, uint32_t x)
+{
+ MB_PUT(uint32_t);
+ /* LINTED */
+ setdle(p, 0, x);
+ return (0);
+}
+
+int
+mb_put_uint64be(struct mbdata *mbp, uint64_t x)
+{
+ MB_PUT(uint64_t);
+ *p = htobeq(x);
+ return (0);
+}
+
+int
+mb_put_uint64le(struct mbdata *mbp, uint64_t x)
+{
+ MB_PUT(uint64_t);
+ *p = htoleq(x);
+ return (0);
+}
+
+int
+mb_put_mem(struct mbdata *mbp, const char *source, size_t size)
+{
+ struct mbuf *m;
+ char *dst;
+ size_t cplen;
+ int error;
+
+ 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 > size)
+ cplen = size;
+ dst = mtod(m, char *) + m->m_len;
+ if (source) {
+ bcopy(source, dst, cplen);
+ source += cplen;
+ } else
+ bzero(dst, cplen);
+ size -= cplen;
+ m->m_len += cplen;
+ mbp->mb_count += cplen;
+ }
+ mbp->mb_pos = mtod(m, char *) + m->m_len;
+ mbp->mb_cur = m;
+ return (0);
+}
+
+int
+mb_put_mbuf(struct mbdata *mbp, struct mbuf *m)
+{
+ mbp->mb_cur->m_next = m;
+ while (m) {
+ mbp->mb_count += m->m_len;
+ if (m->m_next == NULL)
+ break;
+ m = m->m_next;
+ }
+ mbp->mb_pos = mtod(m, char *) + m->m_len;
+ mbp->mb_cur = m;
+ return (0);
+}
+
+int
+mb_put_pstring(struct mbdata *mbp, const char *s)
+{
+ int error, len = strlen(s);
+
+ if (len > 255) {
+ len = 255;
+ }
+ if ((error = mb_put_uint8(mbp, len)) != 0)
+ return (error);
+ return (mb_put_mem(mbp, s, len));
+}
+
+/*
+ * Routines for fetching data from an mbuf chain
+ */
+#define mb_left(m, p) (mtod(m, char *) + (m)->m_len - (p))
+
+int
+mb_get_uint8(struct mbdata *mbp, uint8_t *x)
+{
+ return (mb_get_mem(mbp, (char *)x, 1));
+}
+
+int
+mb_get_uint16(struct mbdata *mbp, uint16_t *x)
+{
+ return (mb_get_mem(mbp, (char *)x, 2));
+}
+
+int
+mb_get_uint16le(struct mbdata *mbp, uint16_t *x)
+{
+ uint16_t v;
+ int error = mb_get_uint16(mbp, &v);
+
+ if (x != NULL)
+ *x = letohs(v);
+ return (error);
+}
+
+int
+mb_get_uint16be(struct mbdata *mbp, uint16_t *x) {
+ uint16_t v;
+ int error = mb_get_uint16(mbp, &v);
+
+ if (x != NULL)
+ *x = betohs(v);
+ return (error);
+}
+
+int
+mb_get_uint32(struct mbdata *mbp, uint32_t *x)
+{
+ return (mb_get_mem(mbp, (char *)x, 4));
+}
+
+int
+mb_get_uint32be(struct mbdata *mbp, uint32_t *x)
+{
+ uint32_t v;
+ int error;
+
+ error = mb_get_uint32(mbp, &v);
+ if (x != NULL)
+ *x = betohl(v);
+ return (error);
+}
+
+int
+mb_get_uint32le(struct mbdata *mbp, uint32_t *x)
+{
+ uint32_t v;
+ int error;
+
+ error = mb_get_uint32(mbp, &v);
+ if (x != NULL)
+ *x = letohl(v);
+ return (error);
+}
+
+int
+mb_get_uint64(struct mbdata *mbp, uint64_t *x)
+{
+ return (mb_get_mem(mbp, (char *)x, 8));
+}
+
+int
+mb_get_uint64be(struct mbdata *mbp, uint64_t *x)
+{
+ uint64_t v;
+ int error;
+
+ error = mb_get_uint64(mbp, &v);
+ if (x != NULL)
+ *x = betohq(v);
+ return (error);
+}
+
+int
+mb_get_uint64le(struct mbdata *mbp, uint64_t *x)
+{
+ uint64_t v;
+ int error;
+
+ error = mb_get_uint64(mbp, &v);
+ if (x != NULL)
+ *x = letohq(v);
+ return (error);
+}
+
+int
+mb_get_mem(struct mbdata *mbp, char *target, size_t size)
+{
+ struct mbuf *m = mbp->mb_cur;
+ 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
+ return (EBADRPC);
+ }
+ count = mb_left(m, mbp->mb_pos);
+ if (count == 0) {
+ mbp->mb_cur = m = m->m_next;
+ if (m)
+ mbp->mb_pos = mtod(m, char *);
+ continue;
+ }
+ if (count > size)
+ count = size;
+ size -= count;
+ if (target) {
+ if (count == 1) {
+ *target++ = *mbp->mb_pos;
+ } else {
+ bcopy(mbp->mb_pos, target, count);
+ target += count;
+ }
+ }
+ mbp->mb_pos += count;
+ }
+ return (0);
+}
diff --git a/usr/src/lib/libsmbfs/smb/nb.c b/usr/src/lib/libsmbfs/smb/nb.c
new file mode 100644
index 0000000000..f60ae0b314
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/nb.c
@@ -0,0 +1,265 @@
+/*
+ * 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: nb.c,v 1.1.1.2 2001/07/06 22:38:42 conrad Exp $
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+#include <sys/socket.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 <libintl.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+
+#include <cflib.h>
+
+int
+nb_ctx_create(struct nb_ctx **ctxpp)
+{
+ struct nb_ctx *ctx;
+
+ ctx = malloc(sizeof (struct nb_ctx));
+ if (ctx == NULL)
+ return (ENOMEM);
+ bzero(ctx, sizeof (struct nb_ctx));
+ ctx->nb_flags = NBCF_NS_ENABLE | NBCF_BC_ENABLE;
+ *ctxpp = ctx;
+ return (0);
+}
+
+void
+nb_ctx_done(struct nb_ctx *ctx)
+{
+ if (ctx == NULL)
+ return;
+ if (ctx->nb_scope)
+ free(ctx->nb_scope);
+ if (ctx)
+ free(ctx);
+}
+
+static int
+nb_ctx_setwins(in_addr_t *ina_p, const char *str)
+{
+ struct in_addr ina;
+ struct sockaddr *sap;
+ int error;
+
+ if (str == NULL || str[0] == 0)
+ return (EINVAL);
+
+ if (inet_aton(str, &ina)) {
+ *ina_p = ina.s_addr;
+ } else {
+ error = nb_resolvehost_in(str, &sap);
+ if (error) {
+ smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
+ error, str);
+ 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);
+ }
+
+ return (0);
+}
+
+/*
+ * This is called by "smbutil lookup" to handle the
+ * "-w wins_server" option. Let the semantics of
+ * this option be: Use specified WINS server only.
+ * If specified server is the broadcast address,
+ * set broadcast mode (and no WINS servers).
+ */
+int
+nb_ctx_setns(struct nb_ctx *ctx, const char *addr)
+{
+ int error;
+
+ error = nb_ctx_setwins(&ctx->nb_wins1, addr);
+ if (error)
+ return (error);
+ ctx->nb_wins2 = 0;
+
+ /* Deal with explicit request for broadcast. */
+ if (ctx->nb_wins1 == INADDR_BROADCAST) {
+ ctx->nb_wins1 = 0;
+ ctx->nb_flags |= NBCF_BC_ENABLE;
+ }
+ return (0);
+}
+
+int
+nb_ctx_setscope(struct nb_ctx *ctx, const char *scope)
+{
+ size_t slen = strlen(scope);
+
+ if (slen >= 128) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "scope '%s' is too long"), 0, scope);
+ return (ENAMETOOLONG);
+ }
+ if (ctx->nb_scope)
+ free(ctx->nb_scope);
+ ctx->nb_scope = malloc(slen + 1);
+ if (ctx->nb_scope == NULL)
+ return (ENOMEM);
+ nls_str_upper(ctx->nb_scope, scope);
+ return (0);
+}
+
+/*
+ * Now get the WINS server IP addresses directly
+ * when reading the RC files, so no longer need to
+ * lookup any names here.
+ */
+int
+nb_ctx_resolve(struct nb_ctx *ctx)
+{
+ ctx->nb_flags |= NBCF_RESOLVED;
+ return (0);
+}
+
+/*
+ * used level values:
+ * 0 - default
+ * 1 - server
+ *
+ * All of these are normally system-wide settings;
+ * the checks are in rc_parse() in rcfile.c.
+ */
+int
+nb_ctx_readrcsection(struct rcfile *rcfile, struct nb_ctx *ctx,
+ const char *sname, int level)
+{
+ char *p;
+ int error;
+ int nbns_enable;
+ int nbns_broadcast;
+
+ if (level > 1)
+ return (EINVAL);
+#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);
+ if (error) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "invalid address specified in the section %s"),
+ 0, sname);
+ return (error);
+ }
+ }
+ error = rc_getbool(rcfile, sname, "nbns_enable", &nbns_enable);
+ if (error == 0 && nbns_enable == 0)
+ ctx->nb_flags &= ~NBCF_NS_ENABLE;
+ error = rc_getbool(rcfile, sname, "nbns_broadcast", &nbns_broadcast);
+ if (error == 0 && nbns_broadcast == 0)
+ ctx->nb_flags &= ~NBCF_BC_ENABLE;
+ return (0);
+}
+
+#ifdef I18N /* never defined, permits xgettext(1) to pick out strings */
+static const char *nb_err_rcode[] = {
+ gettext("bad request/response format"),
+ gettext("NBNS server failure"),
+ gettext("no such name"),
+ gettext("unsupported request"),
+ gettext("request rejected"),
+ gettext("name already registered)"
+};
+
+static const char *nb_err[] = {
+ gettext("host not found"),
+ gettext("too many redirects"),
+ gettext("invalid response"),
+ gettext("NETBIOS name too long"),
+ gettext("no interface to broadcast on and no NBNS server specified")
+};
+#else
+static const char *nb_err_rcode[] = {
+ "bad request/response format",
+ "NBNS server failure",
+ "no such name",
+ "unsupported request",
+ "request rejected",
+ "name already registered"
+};
+
+static const char *nb_err[] = {
+ "host not found",
+ "too many redirects",
+ "invalid response",
+ "NETBIOS name too long",
+ "no interface to broadcast on and no NBNS server specified"
+};
+#endif
+
+const char *
+nb_strerror(int error)
+{
+ if (error == 0)
+ return (NULL);
+ if (error <= NBERR_ACTIVE)
+ return (nb_err_rcode[error - 1]);
+ else if (error >= NBERR_HOSTNOTFOUND && error < NBERR_MAX)
+ return (nb_err[error - NBERR_HOSTNOTFOUND]);
+ else
+ return (NULL);
+}
diff --git a/usr/src/lib/libsmbfs/smb/nb_name.c b/usr/src/lib/libsmbfs/smb/nb_name.c
new file mode 100644
index 0000000000..1c631d73d1
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/nb_name.c
@@ -0,0 +1,273 @@
+/*
+ * 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.
+ *
+ * $Id: nb_name.c,v 1.11 2004/12/11 05:23:59 lindak Exp $
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <libintl.h>
+#include <assert.h>
+
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/mchain.h>
+
+int
+nb_snballoc(int namelen, struct sockaddr_nb **dst)
+{
+ struct sockaddr_nb *snb;
+ int slen;
+
+ slen = sizeof (struct sockaddr_nb);
+ snb = malloc(slen);
+ if (snb == NULL)
+ return (ENOMEM);
+ bzero(snb, slen);
+ snb->snb_family = AF_NETBIOS;
+ *dst = snb;
+ return (0);
+}
+
+void
+nb_snbfree(struct sockaddr *snb)
+{
+ free(snb);
+}
+
+/*
+ * Create a full NETBIOS address
+ */
+int
+nb_sockaddr(struct sockaddr *peer, struct nb_name *np,
+ struct sockaddr_nb **dst)
+
+{
+ struct sockaddr_nb *snb;
+ struct sockaddr_in *sin;
+ struct hostent *hst;
+ int nmlen, 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);
+ 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*/
+ sin = (struct sockaddr_in *)peer;
+ snb->snb_ipaddr = sin->sin_addr.s_addr;
+ }
+ *dst = snb;
+ return (0);
+}
+
+int
+nb_name_len(struct nb_name *np)
+{
+ char *name;
+ int len, sclen;
+
+ len = 1 + NB_ENCNAMELEN;
+ if (np->nn_scope == NULL)
+ return (len + 1);
+ sclen = 0;
+ for (name = np->nn_scope; *name; name++) {
+ if (*name == '.') {
+ sclen = 0;
+ } else {
+ if (sclen < NB_MAXLABLEN) {
+ sclen++;
+ len++;
+ }
+ }
+ }
+ return (len + 1);
+}
+
+int
+nb_encname_len(const uchar_t *str)
+{
+ const uchar_t *cp = str;
+ int len, blen;
+
+ if ((cp[0] & 0xc0) == 0xc0)
+ return (-1); /* first two bytes are offset to name */
+
+ len = 1;
+ for (;;) {
+ blen = *cp;
+ if (blen++ == 0)
+ break;
+ len += blen;
+ cp += blen;
+ }
+ return (len);
+}
+
+int
+nb_name_encode(struct nb_name *np, uchar_t *dst)
+{
+ char *name;
+ uchar_t *plen;
+ uchar_t ch, *cp = dst;
+ char *p, buf1[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;
+
+ /*
+ * 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
+ *
+ * Here is what we marshall:
+ * uint8_t NAME_LENGTH (always 32)
+ * uint8_t ENCODED_NAME[32]
+ * uint8_t SCOPE_LENGTH
+ * Scope follows here, then another null.
+ */
+
+ /* NAME_LENGTH */
+ *cp++ = (2 * NB_NAMELEN);
+
+ /* ENCODED_NAME */
+ for (i = 0; i < NB_NAMELEN; i++) {
+ ch = name[i];
+ *cp++ = 'A' + ((ch >> 4) & 0xF);
+ *cp++ = 'A' + ((ch) & 0xF);
+ }
+
+ /*
+ * NetBIOS "scope" sting encoding,
+ * a.k.a second-level encoding.
+ * See RFC1002 for the details.
+ *
+ * Note: plen points to the length byte at the
+ * start of each string. This keeps a pointer
+ * to the location and fills it in after the
+ * length of the string is determined.
+ */
+#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++;
+ }
+ }
+ }
+ } else
+#endif /* XXX: not yet */
+ {
+ *cp++ = 0;
+ }
+
+ return (cp - dst);
+}
diff --git a/usr/src/lib/libsmbfs/smb/nb_net.c b/usr/src/lib/libsmbfs/smb/nb_net.c
new file mode 100644
index 0000000000..7398cff0e0
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/nb_net.c
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ *
+ * $Id: nb_net.c,v 1.8 2004/03/19 01:49:47 lindak Exp $
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#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 <err.h>
+
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+
+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)
+{
+ struct hostent *h;
+ struct sockaddr_in *sinp;
+ in_addr_t addr;
+ struct in_addr in;
+ int len;
+ char **p;
+
+
+ h = gethostbyname(name);
+ if (!h) {
+#ifdef DEBUG
+ warnx("can't get server address `%s': ", name);
+#endif
+ return (ENETDOWN);
+ }
+ if (h->h_addrtype != AF_INET) {
+#ifdef DEBUG
+ warnx("address for `%s' is not in the AF_INET family", name);
+#endif
+ return (EAFNOSUPPORT);
+ }
+ if (h->h_length != 4) {
+#ifdef DEBUG
+ warnx("address for `%s' has invalid length", name);
+#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;
+ return (0);
+}
+
+#ifdef NOT_DEFINED
+int
+nb_enum_if(struct nb_ifdesc **iflist) {
+ struct lifconf ifc;
+ struct lifreq *ifrqp;
+ struct nb_ifdesc *ifd;
+ struct in_addr iaddr, imask;
+ struct lifnum ifn;
+ char *ifrdata, *iname;
+ int s, rdlen, ifcnt, error, iflags, i;
+
+ *iflist = NULL;
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s == -1)
+ return (errno);
+
+ /* Get number of interfaces. */
+ ifn.lifn_family = AF_INET;
+ ifn.lifn_flags = 0;
+ ifn.lifn_count = 0;
+ if (ioctl(s, SIOCGLIFNUM, &ifn) != 0) {
+ error = errno;
+ goto bad;
+ }
+
+ rdlen = ifn.lifn_count * sizeof (struct lifreq);
+ ifrdata = malloc(rdlen);
+ if (ifrdata == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ ifc.lifc_flags = 0;
+ ifc.lifc_family = AF_INET;
+ ifc.lifc_len = rdlen;
+ ifc.lifc_buf = ifrdata;
+ if (ioctl(s, SIOCGLIFCONF, &ifc) != 0) {
+ error = errno;
+ goto bad;
+ }
+ ifrqp = ifc.lifc_req;
+ ifcnt = ifc.lifc_len / sizeof (struct lifreq);
+ error = 0;
+ for (i = 0; i < ifcnt; i++, ifrqp++) {
+ /* XXX for now, avoid IP6 broadcast performance costs */
+ if (ifrqp->lifr_addr.ss_family != AF_INET)
+ continue;
+ if (ioctl(s, SIOCGLIFFLAGS, ifrqp) != 0)
+ continue;
+ iflags = ifrqp->lifr_flags;
+ if ((iflags & IFF_UP) == 0 || (iflags & IFF_BROADCAST) == 0)
+ continue;
+
+ if (ioctl(s, SIOCGLIFADDR, ifrqp) != 0 ||
+ ifrqp->lifr_addr.ss_family != AF_INET) {
+ continue;
+ }
+ iname = ifrqp->lifr_name;
+ if (strlen(iname) >= sizeof (ifd->id_name))
+ continue;
+ iaddr = (*(struct sockaddr_in *)&ifrqp->lifr_addr).sin_addr;
+
+ if (ioctl(s, SIOCGLIFNETMASK, ifrqp) != 0)
+ continue;
+ imask = ((struct sockaddr_in *)&ifrqp->lifr_addr)->sin_addr;
+
+ ifd = malloc(sizeof (struct nb_ifdesc));
+ if (ifd == NULL)
+ return (ENOMEM);
+ bzero(ifd, sizeof (struct nb_ifdesc));
+ strcpy(ifd->id_name, iname);
+ ifd->id_flags = iflags;
+ ifd->id_addr = iaddr;
+ ifd->id_mask = imask;
+ ifd->id_next = *iflist;
+ *iflist = ifd;
+ }
+bad:
+ free(ifrdata);
+ close(s);
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+nbns_resolvename(const char *name, struct sockaddr **dest)
+{
+ printf("NetBIOS name resolver is not included in this distribution.\n");
+ printf("Please use '-I' option to specify an IP address of server.\n");
+ return (EHOSTUNREACH);
+}
+
+int
+nb_hostlookup(struct nb_name *np, const char *server, const char *hint,
+ struct sockaddr_nb **dst)
+{
+ struct sockaddr_nb *snb;
+ int error;
+
+ error = nb_sockaddr(NULL, np, &snb);
+ if (error)
+ return (error);
+ do {
+ if (hint) {
+ error = nb_resolvehost_in(host, snb);
+ if (error)
+ break;
+ } else {
+ error = nb_resolvename(server);
+ }
+ } while (0);
+ if (!error) {
+ *dst = snb;
+ } else
+ nb_snbfree(snb);
+ return (error);
+}
+#endif
diff --git a/usr/src/lib/libsmbfs/smb/nbns_rq.c b/usr/src/lib/libsmbfs/smb/nbns_rq.c
new file mode 100644
index 0000000000..17de0a103a
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/nbns_rq.c
@@ -0,0 +1,581 @@
+/*
+ * 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.
+ *
+ * $Id: nbns_rq.c,v 1.9 2005/02/24 02:04:38 lindak Exp $
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.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 <libintl.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <tsol/label.h>
+
+#define NB_NEEDRESOLVER
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/mchain.h>
+
+static int nbns_rq_create(int opcode, struct nb_ctx *ctx,
+ struct nbns_rq **rqpp);
+static void nbns_rq_done(struct nbns_rq *rqp);
+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;
+
+int
+nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
+{
+ struct nbns_rq *rqp;
+ struct nb_name nn;
+ struct nbns_rr rr;
+ struct sockaddr_in *dest;
+ int error, rdrcount, len;
+
+ if (strlen(name) > NB_NAMELEN)
+ return (NBERROR(NBERR_NAMETOOLONG));
+ error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
+ if (error)
+ return (error);
+ /*
+ * Pad the name with blanks, but
+ * leave the "type" byte NULL.
+ * nb_name_encode adds the type.
+ */
+ bzero(&nn, sizeof (nn));
+ snprintf(nn.nn_name, NB_NAMELEN, "%-15.15s", name);
+ nn.nn_type = NBT_SERVER;
+ nn.nn_scope = ctx->nb_scope;
+ rqp->nr_nmflags = NBNS_NMFLAG_RD;
+ rqp->nr_qdname = &nn;
+ rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB;
+ rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
+ rqp->nr_qdcount = 1;
+ rqp->nr_maxretry = 5;
+
+ error = nbns_rq_prepare(rqp);
+ if (error) {
+ nbns_rq_done(rqp);
+ return (error);
+ }
+ rdrcount = NBNS_MAXREDIRECTS;
+ for (;;) {
+ error = nbns_rq(rqp);
+ if (error)
+ break;
+ if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) {
+ /*
+ * Not an authoritative answer. Query again
+ * using the NS address in the 2nd record.
+ */
+ if (rdrcount-- == 0) {
+ error = NBERROR(NBERR_TOOMANYREDIRECTS);
+ break;
+ }
+ error = nbns_rq_getrr(rqp, &rr);
+ if (error)
+ break;
+ error = nbns_rq_getrr(rqp, &rr);
+ if (error)
+ break;
+ bcopy(rr.rr_data, &rqp->nr_dest, 4);
+ continue;
+ }
+ if (rqp->nr_rpancount == 0) {
+ error = NBERROR(NBERR_HOSTNOTFOUND);
+ break;
+ }
+ error = nbns_rq_getrr(rqp, &rr);
+ if (error)
+ break;
+ len = sizeof (struct sockaddr_in);
+ dest = malloc(len);
+ if (dest == NULL)
+ return (ENOMEM);
+ bzero(dest, len);
+ /*
+ * Solaris sockaddr_in doesn't have this field.
+ * dest->sin_len = len;
+ */
+ dest->sin_family = AF_INET;
+ 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;
+ }
+ nbns_rq_done(rqp);
+ 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);
+}
+
+
+int
+nbns_getnodestatus(struct sockaddr *targethost,
+ struct nb_ctx *ctx, char *system, char *workgroup)
+{
+ struct nbns_rq *rqp;
+ struct nbns_rr rr;
+ struct nb_name nn;
+ 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;
+
+ if (targethost->sa_family != AF_INET)
+ return (EINVAL);
+ error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
+ if (error)
+ return (error);
+ bzero(&nn, sizeof (nn));
+ strcpy((char *)nn.nn_name, "*");
+ nn.nn_scope = ctx->nb_scope;
+ nn.nn_type = NBT_WKSTA;
+ rqp->nr_nmflags = 0;
+ rqp->nr_qdname = &nn;
+ rqp->nr_qdtype = NBNS_QUESTION_TYPE_NBSTAT;
+ rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
+ rqp->nr_qdcount = 1;
+ rqp->nr_maxretry = 2;
+
+ /* LINTED */
+ dest = (struct sockaddr_in *)targethost;
+ rqp->nr_dest = dest->sin_addr;
+
+ error = nbns_rq_prepare(rqp);
+ if (error) {
+ nbns_rq_done(rqp);
+ return (error);
+ }
+
+ /*
+ * Darwin had a loop here, allowing redirect, etc.
+ * but we only handle point-to-point for node status.
+ */
+ error = nbns_rq(rqp);
+ if (error)
+ goto out;
+ if (rqp->nr_rpancount == 0) {
+ error = NBERROR(NBERR_HOSTNOTFOUND);
+ goto out;
+ }
+ error = nbns_rq_getrr(rqp, &rr);
+ if (error)
+ goto out;
+
+ /* Compiler didn't like cast on lvalue++ */
+ nrcount = *((unsigned char *)rr.rr_data);
+ rr.rr_data++;
+ /* LINTED */
+ for (i = 1, nrp = (struct nbns_nr *)rr.rr_data;
+ i <= nrcount; ++i, ++nrp) {
+ nrtype = nrp->ns_name[NB_NAMELEN-1];
+ /* Terminate the string: */
+ nrp->ns_name[NB_NAMELEN-1] = (char)0;
+ /* Strip off trailing spaces */
+ for (cp = &nrp->ns_name[NB_NAMELEN-2];
+ cp >= nrp->ns_name; --cp) {
+ if (*cp != (char)0x20)
+ break;
+ *cp = (char)0;
+ }
+ nrp->ns_flags = ntohs(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);
+ foundgroup = nrtype+1;
+ }
+ } else {
+ /*
+ * Track at least ONE name, in case
+ * no server name is found
+ */
+ retname = nrp->ns_name;
+ }
+ if (nrtype == NBT_SERVER) {
+ smb_optstrncpy(system, nrp->ns_name,
+ SMB_MAXSRVNAMELEN);
+ foundserver = 1;
+ }
+ }
+ if (!foundserver)
+ smb_optstrncpy(system, retname, SMB_MAXSRVNAMELEN);
+ ctx->nb_lastns = rqp->nr_sender;
+
+out:
+ nbns_rq_done(rqp);
+ return (error);
+}
+
+int
+nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp)
+{
+ struct nbns_rq *rqp;
+ static uint16_t trnid;
+ int error;
+
+ if (trnid == 0)
+ trnid = getpid();
+ rqp = malloc(sizeof (*rqp));
+ if (rqp == NULL)
+ return (ENOMEM);
+ bzero(rqp, sizeof (*rqp));
+ error = mb_init(&rqp->nr_rq, NBDG_MAXSIZE);
+ if (error) {
+ free(rqp);
+ return (error);
+ }
+ rqp->nr_opcode = opcode;
+ rqp->nr_nbd = ctx;
+ rqp->nr_trnid = trnid++;
+ *rqpp = rqp;
+ return (0);
+}
+
+void
+nbns_rq_done(struct nbns_rq *rqp)
+{
+ if (rqp == NULL)
+ return;
+ if (rqp->nr_fd >= 0)
+ close(rqp->nr_fd);
+ mb_done(&rqp->nr_rq);
+ mb_done(&rqp->nr_rp);
+ if (rqp->nr_if)
+ free(rqp->nr_if);
+ free(rqp);
+}
+
+/*
+ * Extract resource record from the packet. Assume that there is only
+ * one mbuf.
+ */
+int
+nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp)
+{
+ struct mbdata *mbp = &rqp->nr_rp;
+ uchar_t *cp;
+ int error, len;
+
+ bzero(rrp, sizeof (*rrp));
+ cp = (uchar_t *)mbp->mb_pos;
+ len = nb_encname_len(cp);
+ if (len < 1)
+ return (NBERROR(NBERR_INVALIDRESPONSE));
+ rrp->rr_name = cp;
+ error = mb_get_mem(mbp, NULL, len);
+ if (error)
+ return (error);
+ mb_get_uint16be(mbp, &rrp->rr_type);
+ mb_get_uint16be(mbp, &rrp->rr_class);
+ mb_get_uint32be(mbp, &rrp->rr_ttl);
+ mb_get_uint16be(mbp, &rrp->rr_rdlength);
+ rrp->rr_data = (uchar_t *)mbp->mb_pos;
+ error = mb_get_mem(mbp, NULL, rrp->rr_rdlength);
+ return (error);
+}
+
+int
+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;
+
+ /*
+ * Replacing with one argument.
+ * error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE);
+ */
+ error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE);
+ if (error)
+ return (error);
+
+ /*
+ * When looked into the ethereal trace, 'nmblookup' command sets this
+ * flag. We will also set.
+ */
+ mb_put_uint16be(mbp, rqp->nr_trnid);
+ ofr = ((rqp->nr_opcode & 0x1F) << 11) |
+ ((rqp->nr_nmflags & 0x7F) << 4); /* rcode=0 */
+ mb_put_uint16be(mbp, ofr);
+ mb_put_uint16be(mbp, rqp->nr_qdcount);
+ mb_put_uint16be(mbp, rqp->nr_ancount);
+ mb_put_uint16be(mbp, rqp->nr_nscount);
+ mb_put_uint16be(mbp, rqp->nr_arcount);
+ 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);
+ mb_put_uint16be(mbp, rqp->nr_qdtype);
+ mb_put_uint16be(mbp, rqp->nr_qdclass);
+ }
+ m_lineup(mbp->mb_top, &mbp->mb_top);
+ if (ctx->nb_timo == 0)
+ ctx->nb_timo = 1; /* by default 1 second */
+ return (0);
+}
+
+static int
+nbns_rq_recv(struct nbns_rq *rqp)
+{
+ struct mbdata *mbp = &rqp->nr_rp;
+ void *rpdata = mtod(mbp->mb_top, void *);
+ fd_set rd, wr, ex;
+ struct timeval tv;
+ struct sockaddr_in sender;
+ int s = rqp->nr_fd;
+ int n, len;
+
+ FD_ZERO(&rd);
+ FD_ZERO(&wr);
+ FD_ZERO(&ex);
+ FD_SET(s, &rd);
+
+ tv.tv_sec = rqp->nr_nbd->nb_timo;
+ tv.tv_usec = 0;
+
+ n = select(s + 1, &rd, &wr, &ex, &tv);
+ if (n == -1)
+ return (-1);
+ if (n == 0)
+ return (ETIMEDOUT);
+ if (FD_ISSET(s, &rd) == 0)
+ return (ETIMEDOUT);
+ len = sizeof (sender);
+ n = recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0,
+ (struct sockaddr *)&sender, &len);
+ if (n < 0)
+ return (errno);
+ mbp->mb_top->m_len = mbp->mb_count = n;
+ rqp->nr_sender = sender;
+ return (0);
+}
+
+static int
+nbns_rq_opensocket(struct nbns_rq *rqp)
+{
+ struct sockaddr_in locaddr;
+ int opt = 1, s;
+ struct nb_ctx *ctx = rqp->nr_nbd;
+
+ s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return (errno);
+ if (ctx->nb_flags & NBCF_BC_ENABLE) {
+ if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt,
+ sizeof (opt)) < 0)
+ return (errno);
+ }
+ if (is_system_labeled())
+ (void) setsockopt(s, SOL_SOCKET, SO_MAC_EXEMPT, &opt,
+ sizeof (opt));
+ bzero(&locaddr, sizeof (locaddr));
+ locaddr.sin_family = AF_INET;
+ /* locaddr.sin_len = sizeof (locaddr); */
+ if (bind(s, (struct sockaddr *)&locaddr, sizeof (locaddr)) < 0)
+ return (errno);
+ return (0);
+}
+
+static int
+nbns_rq_send(struct nbns_rq *rqp, in_addr_t ina)
+{
+ struct sockaddr_in dest;
+ struct mbdata *mbp = &rqp->nr_rq;
+ int s = rqp->nr_fd;
+ uint16_t ofr, ofr_save; /* opcode, nmflags, rcode */
+ uint16_t *datap;
+ uint8_t nmflags;
+ int rc;
+
+ bzero(&dest, sizeof (dest));
+ dest.sin_family = AF_INET;
+ dest.sin_port = htons(NBNS_UDP_PORT);
+ dest.sin_addr.s_addr = ina;
+
+ if (ina == INADDR_BROADCAST) {
+ /* Turn on the broadcast bit. */
+ nmflags = rqp->nr_nmflags | NBNS_NMFLAG_BCAST;
+ /*LINTED*/
+ datap = mtod(mbp->mb_top, uint16_t *);
+ ofr = ((rqp->nr_opcode & 0x1F) << 11) |
+ ((nmflags & 0x7F) << 4); /* rcode=0 */
+ ofr_save = datap[1];
+ datap[1] = htons(ofr);
+ }
+
+ rc = sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0,
+ (struct sockaddr *)&dest, sizeof (dest));
+
+ if (ina == INADDR_BROADCAST) {
+ /* Turn the broadcast bit back off. */
+ datap[1] = ofr_save;
+ }
+
+
+ if (rc < 0)
+ return (errno);
+
+ return (0);
+}
+
+int
+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);
+ if (error)
+ return (error);
+
+ maxretry = rqp->nr_maxretry;
+ for (tries = 0; tries < maxretry; tries++) {
+
+ /*
+ * Minor hack: If nr_dest is set, send there only.
+ * Used by _getnodestatus, _resolvname redirects.
+ */
+ if (rqp->nr_dest.s_addr) {
+ error = nbns_rq_send(rqp, rqp->nr_dest.s_addr);
+ if (error) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "nbns error %d sending to %s"),
+ 0, error, inet_ntoa(rqp->nr_dest));
+ }
+ goto do_recv;
+ }
+
+ if (ctx->nb_wins1) {
+ error = nbns_rq_send(rqp, ctx->nb_wins1);
+ if (error) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "nbns error %d sending to wins1"),
+ 0, error);
+ }
+ }
+
+ if (ctx->nb_wins2 && (tries > 0)) {
+ error = nbns_rq_send(rqp, ctx->nb_wins2);
+ if (error) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "nbns error %d sending to wins2"),
+ 0, error);
+ }
+ }
+
+ /*
+ * If broadcast is enabled, start broadcasting
+ * only after wins servers fail to respond, or
+ * immediately if no WINS servers configured.
+ */
+ if ((ctx->nb_flags & NBCF_BC_ENABLE) &&
+ ((tries > 1) || (ctx->nb_wins1 == 0))) {
+ error = nbns_rq_send(rqp, INADDR_BROADCAST);
+ if (error) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "nbns error %d sending broadcast"),
+ 0, error);
+ }
+ }
+
+ /*
+ * Wait for responses from ANY of the above.
+ */
+do_recv:
+ error = nbns_rq_recv(rqp);
+ if (error == ETIMEDOUT)
+ continue;
+ if (error) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "nbns recv error %d"),
+ 0, error);
+ return (error);
+ }
+
+ mbp = &rqp->nr_rp;
+ if (mbp->mb_count < 12)
+ return (NBERROR(NBERR_INVALIDRESPONSE));
+ mb_get_uint16be(mbp, &rpid);
+ if (rpid != rqp->nr_trnid)
+ return (NBERROR(NBERR_INVALIDRESPONSE));
+ break;
+ }
+
+ mb_get_uint16be(mbp, &ofr);
+ rqp->nr_rpnmflags = (ofr >> 4) & 0x7F;
+ rqp->nr_rprcode = ofr & 0xf;
+ if (rqp->nr_rprcode)
+ return (NBERROR(rqp->nr_rprcode));
+ mb_get_uint16be(mbp, &rpid); /* QDCOUNT */
+ mb_get_uint16be(mbp, &rqp->nr_rpancount);
+ mb_get_uint16be(mbp, &rqp->nr_rpnscount);
+ mb_get_uint16be(mbp, &rqp->nr_rparcount);
+ return (0);
+}
diff --git a/usr/src/lib/libsmbfs/smb/netshareenum.c b/usr/src/lib/libsmbfs/smb/netshareenum.c
new file mode 100644
index 0000000000..4da5fd17a2
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/netshareenum.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/* BEGIN CSTYLED */
+/*
+ * @(#)ui.c *
+ * (c) 2004 Apple Computer, Inc. All Rights Reserved
+ *
+ *
+ * netshareenum.c -- Routines for getting a list of share information
+ * from a server.
+ *
+ * MODIFICATION HISTORY:
+ * 27-Nov-2004 Guy Harris New today
+ */
+/* END CSTYLED */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <netsmb/mchain.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/smb_rap.h>
+#include <netsmb/smb_netshareenum.h>
+#include "charsets.h"
+
+#if 0 /* XXX see below */
+#include <dce/exc_handling.h>
+#include <attrb.h>
+#include "srvsvc.h"
+#endif
+
+/*
+ * Don't want RPC client-side code in here.
+ * It's good code; just doesn't belong here.
+ *
+ * The API provided by this library should be
+ * just files and pipes (and not much more).
+ * It MAY be useful to provide some of the
+ * RAP (remote API) functions functions like
+ * rap_netshareenum below...
+ *
+ * XXX: Not sure this file belongs here at all.
+ * smb_rap.h looks like a reasonable API
+ * for this library to export.
+ */
+#if 0 /* XXX */
+
+static int
+rpc_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
+ struct share_info **entries_listp)
+{
+ char ctx_string[2+16+1]; /* enough for 64-bit pointer, in hex */
+ unsigned_char_p_t binding;
+ unsigned32 binding_status;
+ rpc_binding_handle_t binding_h;
+ int error, i, entries;
+ char *addrstr, *srvnamestr;
+ unsigned short *usrvnamestr;
+ unsigned32 level;
+ SHARE_ENUM_STRUCT share_info;
+ SHARE_INFO_1_CONTAINER share_info_1_container;
+ SHARE_INFO_1 *shares, *share;
+ unsigned32 total_entries;
+ unsigned32 status, free_status;
+ struct share_info *entry_list, *elp;
+ static EXCEPTION rpc_x_connect_rejected;
+ static int exceptions_initialized;
+
+ sprintf(ctx_string, "%p", ctx);
+ rpc_string_binding_compose(NULL, "ncacn_np", ctx_string,
+ "srvsvc", NULL, &binding, &binding_status);
+ if (binding_status != rpc_s_ok) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "rpc_string_binding_compose failed with %d"),
+ 0, binding_status);
+ return (EINVAL);
+ }
+ rpc_binding_from_string_binding(binding, &binding_h, &status);
+ if (binding_status != rpc_s_ok) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "rpc_binding_from_string_binding failed with %d"), 0,
+ binding_status);
+ return (EINVAL);
+ }
+ level = 1;
+ share_info.share_union.level = 1;
+ share_info.share_union.tagged_union.share1 = &share_info_1_container;
+ share_info_1_container.share_count = 0;
+ share_info_1_container.shares = NULL;
+ /*
+ * Convert the server IP address to a string, and send that as
+ * the "server name" - that's what Windows appears to do, and
+ * that avoids problems with NetBIOS names containing
+ * non-ASCII characters.
+ */
+ addrstr = inet_ntoa(ctx->ct_srvinaddr.sin_addr);
+ srvnamestr = malloc(strlen(addrstr) + 3);
+ if (srvnamestr == NULL) {
+ status = errno;
+ smb_error(dgettext(TEXT_DOMAIN,
+ "can't allocate string for server address"), status);
+ rpc_binding_free(&binding_h, &free_status);
+ return (status);
+ }
+ strcpy(srvnamestr, "\\\\");
+ strcat(srvnamestr, addrstr);
+#ifdef NOTYETDEFINED
+ usrvnamestr = convert_utf8_to_leunicode(srvnamestr);
+#endif
+ usrvnamestr = srvnamestr;
+ if (usrvnamestr == NULL) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "can't convert string for server address to Unicode"), 0);
+ rpc_binding_free(&binding_h, &free_status);
+ return (EINVAL);
+ }
+ if (!exceptions_initialized) {
+ EXCEPTION_INIT(rpc_x_connect_rejected);
+ exc_set_status(&rpc_x_connect_rejected, rpc_s_connect_rejected);
+ exceptions_initialized = 1;
+ }
+ /* printf("Calling NetrShareEnum.."); XXX */
+ TRY
+ status = NetrShareEnum(binding_h, usrvnamestr, &level,
+ &share_info, 4294967295U, &total_entries, NULL);
+ if (status != 0)
+ smb_error(dgettext(TEXT_DOMAIN,
+ "error from NetrShareEnum call: status = 0x%08x"),
+ 0, status);
+ /*CSTYLED*/
+ CATCH (rpc_x_connect_rejected)
+ /*
+ * This is what we get if we can't open the pipe.
+ * That's a normal occurrence when we're talking
+ * to a system that (presumably) doesn't support
+ * DCE RPC on the server side, such as Windows 95/98/Me,
+ * so we don't log an error.
+ */
+ /*CSTYLED*/
+ status = ENOTSUP;
+ CATCH_ALL
+ /*
+ * XXX - should we handle some exceptions differently,
+ * returning different errors, and try RAP only for
+ * ENOTSUP?
+ */
+ smb_error(dgettext(TEXT_DOMAIN,
+ "error from NetrShareEnum call: exception = %u"),
+ 0, THIS_CATCH->match.value);
+ status = ENOTSUP;
+ ENDTRY
+ rpc_binding_free(&binding_h, &free_status);
+ free(srvnamestr);
+ free(usrvnamestr);
+ if (status != 0)
+ return (ENOTSUP);
+
+ /*
+ * XXX - if the IDL is correct, it's not clear whether the
+ * unmarshalling code will properly handle the case where
+ * a packet where "share_count" and the max count for the
+ * array of shares don't match; a valid DCE RPC implementation
+ * won't marshal something like that, but there's no guarantee
+ * that the server we're talking to has a valid implementation
+ * (which could be a *malicious* implementation!).
+ */
+ entries = share_info.share_union.tagged_union.share1->share_count;
+ shares = share_info.share_union.tagged_union.share1->shares;
+ entry_list = calloc(entries, sizeof (struct share_info));
+ if (entry_list == NULL) {
+ error = errno;
+ goto cleanup_and_return;
+ }
+ for (share = shares, elp = entry_list, i = 0; i < entries;
+ i++, share++) {
+ elp->type = share->shi1_type;
+#ifdef NOTYETDEFINED
+ elp->netname = convert_unicode_to_utf8(share->shi1_share);
+#endif
+ elp->netname = share->shi1_share;
+ if (elp->netname == NULL)
+ goto fail;
+#ifdef NOTYETDEFINED
+ elp->remark = convert_unicode_to_utf8(share->shi1_remark);
+#endif
+ elp->remark = share->shi1_remark;
+ if (elp->remark == NULL)
+ goto fail;
+ elp++;
+ }
+ *entriesp = entries;
+ *totalp = total_entries;
+ *entries_listp = entry_list;
+ error = 0;
+ goto cleanup_and_return;
+
+fail:
+ error = errno;
+ for (elp = entry_list, i = 0; i < entries; i++, elp++) {
+ /*
+ * elp->netname is set before elp->remark, so if
+ * elp->netname is null, elp->remark is also null.
+ * If either of them is null, we haven't done anything
+ * to any entries after this one.
+ */
+ if (elp->netname == NULL)
+ break;
+ free(elp->netname);
+ if (elp->remark == NULL)
+ break;
+ free(elp->remark);
+ }
+ free(entry_list);
+
+cleanup_and_return:
+ for (share = shares, i = 0; i < entries; i++, share++) {
+ free(share->shi1_share);
+ free(share->shi1_remark);
+ }
+ free(shares);
+ /*
+ * XXX - "share1" should be a unique pointer, but we haven't
+ * changed the marshalling code to support non-full pointers
+ * in unions, so we leave it as a full pointer.
+ *
+ * That means that this might, or might not, be changed from
+ * pointing to "share_info_1_container" to pointing to a
+ * mallocated structure, according to the DCE RPC 1.1 IDL spec;
+ * we free it only if it's changed.
+ */
+ if (share_info.share_union.tagged_union.share1 !=
+ &share_info_1_container)
+ free(share_info.share_union.tagged_union.share1);
+ return (error);
+}
+#endif /* XXX */
+
+static int
+rap_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
+ struct share_info **entries_listp)
+{
+ int error, bufsize, i, entries, total, nreturned;
+ struct smb_share_info_1 *rpbuf, *ep;
+ struct share_info *entry_list, *elp;
+ char *cp;
+ int lbound, rbound;
+
+ bufsize = 0xffe0; /* samba notes win2k bug for 65535 */
+ rpbuf = malloc(bufsize);
+ if (rpbuf == NULL)
+ return (errno);
+
+ error = smb_rap_NetShareEnum(ctx, 1, rpbuf, &bufsize, &entries, &total);
+ if (error &&
+ error != (SMB_ERROR_MORE_DATA | SMB_RAP_ERROR)) {
+ free(rpbuf);
+ return (error);
+ }
+ entry_list = malloc(entries * sizeof (struct share_info));
+ if (entry_list == NULL) {
+ error = errno;
+ free(rpbuf);
+ return (error);
+ }
+ lbound = entries * (sizeof (struct smb_share_info_1));
+ rbound = bufsize;
+ for (ep = rpbuf, elp = entry_list, i = 0, nreturned = 0; i < entries;
+ i++, ep++) {
+ elp->type = letohs(ep->shi1_type);
+ ep->shi1_pad = '\0'; /* ensure null termination */
+ elp->netname = strdup(ep->shi1_netname);
+#ifdef NOTYETDEFINED
+ elp->netname = convert_wincs_to_utf8(ep->shi1_netname);
+#endif
+ if (elp->netname == NULL)
+ continue; /* punt on this entry */
+ /*
+ * Check for validity of offset.
+ */
+ if (ep->shi1_remark >= lbound && ep->shi1_remark < rbound) {
+ cp = (char *)rpbuf + ep->shi1_remark;
+ elp->remark = cp;
+#ifdef NOTYETDEFINED
+ elp->remark = nls_str_toloc(cp, cp);
+#endif
+ } else
+ elp->remark = NULL;
+ elp++;
+ nreturned++;
+ }
+ *entriesp = nreturned;
+ *totalp = total;
+ *entries_listp = entry_list;
+ free(rpbuf);
+ return (0);
+}
+
+/*
+ * First we try the RPC-based NetrShareEnum, and, if that fails, we fall
+ * back on the RAP-based NetShareEnum.
+ */
+int
+smb_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
+ struct share_info **entry_listp)
+{
+ int error;
+
+#ifdef NOTYETDEFINED
+ /*
+ * Try getting a list of shares with the SRVSVC RPC service.
+ */
+ error = rpc_netshareenum(ctx, entriesp, totalp, entry_listp);
+ if (error == 0)
+ return (0);
+#endif
+
+ /*
+ * OK, that didn't work - try RAP.
+ * XXX - do so only if it failed because we couldn't open
+ * the pipe?
+ */
+ return (rap_netshareenum(ctx, entriesp, totalp, entry_listp));
+}
diff --git a/usr/src/lib/libsmbfs/smb/nls.c b/usr/src/lib/libsmbfs/smb/nls.c
new file mode 100644
index 0000000000..03fe1bec13
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/nls.c
@@ -0,0 +1,179 @@
+/*
+ * 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: 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>
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <errno.h>
+
+#include <netsmb/smb_lib.h>
+
+/*
+ * prototype iconv* functions
+ */
+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];
+
+static iconv_t nls_toext, nls_toloc;
+static int iconv_loaded;
+
+int
+nls_setlocale(const char *name)
+{
+ int i;
+
+ if (setlocale(LC_CTYPE, name) == NULL) {
+ fprintf(stdout, dgettext(TEXT_DOMAIN,
+ "can't set locale '%s'\n"), name);
+ }
+ for (i = 0; i < 256; i++) {
+ nls_lower[i] = tolower(i);
+ nls_upper[i] = toupper(i);
+ }
+ return 0;
+}
+
+int
+nls_setrecode(const char *local, const char *external)
+{
+ return ENOENT;
+}
+
+char *
+nls_str_toloc(char *dst, const char *src)
+{
+ char *p = dst;
+ size_t inlen, outlen;
+
+ if (!iconv_loaded)
+ return strcpy(dst, src);
+
+ if (nls_toloc == (iconv_t)0)
+ 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;
+}
+
+char *
+nls_str_toext(char *dst, const char *src)
+{
+ char *p = dst;
+ size_t inlen, outlen;
+
+ if (!iconv_loaded)
+ return strcpy(dst, src);
+
+ if (nls_toext == (iconv_t)0)
+ 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;
+}
+
+void *
+nls_mem_toloc(void *dst, const void *src, int size)
+{
+ char *p = dst;
+ const char *s = src;
+ size_t inlen, outlen;
+
+ if (!iconv_loaded)
+ return memcpy(dst, src, size);
+
+ if (size == 0)
+ return NULL;
+
+ if (nls_toloc == (iconv_t)0)
+ 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;
+}
+
+void *
+nls_mem_toext(void *dst, const void *src, int size)
+{
+ char *p = dst;
+ const char *s = src;
+ size_t inlen, outlen;
+
+ if (size == 0)
+ return NULL;
+
+ if (!iconv_loaded || nls_toext == (iconv_t)0)
+ 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;
+}
+
+char *
+nls_str_upper(char *dst, const char *src)
+{
+ char *p = dst;
+
+ while (*src)
+ *dst++ = toupper(*src++);
+ *dst = 0;
+ return p;
+}
+
+char *
+nls_str_lower(char *dst, const char *src)
+{
+ char *p = dst;
+
+ while (*src)
+ *dst++ = tolower(*src++);
+ *dst = 0;
+ return p;
+}
diff --git a/usr/src/lib/libsmbfs/smb/print.c b/usr/src/lib/libsmbfs/smb/print.c
new file mode 100644
index 0000000000..7b87c06e41
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/print.c
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ *
+ * $Id: print.c,v 1.1.1.3 2001/07/06 22:38:43 conrad Exp $
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+
+#include <netsmb/smb_lib.h>
+#include <cflib.h>
+
+int
+smb_smb_open_print_file(struct smb_ctx *ctx, int setuplen, int mode,
+ const char *ident, smbfh *fhp)
+{
+ struct smb_rq *rqp;
+ struct mbdata *mbp;
+ int error;
+
+ error = smb_rq_init(ctx, SMB_COM_OPEN_PRINT_FILE, 2, &rqp);
+ if (error)
+ return (error);
+ mbp = smb_rq_getrequest(rqp);
+ mb_put_uint16le(mbp, setuplen);
+ mb_put_uint16le(mbp, mode);
+ smb_rq_wend(rqp);
+ mb_put_uint8(mbp, SMB_DT_ASCII);
+ smb_rq_dstring(mbp, ident);
+ error = smb_rq_simple(rqp);
+ if (!error) {
+ mbp = smb_rq_getreply(rqp);
+ mb_get_uint16(mbp, fhp);
+ }
+ smb_rq_done(rqp);
+ return (error);
+}
+
+int
+smb_smb_close_print_file(struct smb_ctx *ctx, smbfh fh)
+{
+ struct smb_rq *rqp;
+ struct mbdata *mbp;
+ int error;
+
+ error = smb_rq_init(ctx, SMB_COM_CLOSE_PRINT_FILE, 0, &rqp);
+ if (error)
+ return (error);
+ mbp = smb_rq_getrequest(rqp);
+ mb_put_mem(mbp, (char *)&fh, 2);
+ smb_rq_wend(rqp);
+ error = smb_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return (error);
+}
diff --git a/usr/src/lib/libsmbfs/smb/queue.h b/usr/src/lib/libsmbfs/smb/queue.h
new file mode 100644
index 0000000000..6c99fb946d
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/queue.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file [used to define] five types of data structures:
+ * singly-linked lists, ...
+ * [ all other types of lists removed ]
+ *
+ * Using excerpts of FreeBSD 4.5 sys/queue.h here,
+ * but only temporarily, until rcfile.c is replaced
+ * by SMF integration code.
+ *
+ * Yes we also have queue.h in uts/common/fs/smbclnt
+ * but don't want to make that part of the exported
+ * interface to the user-level code.
+ */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
+
+#define SLIST_FIRST(head) ((head)->slh_first)
+
+#define SLIST_FOREACH(var, head, field) \
+ for ((var) = SLIST_FIRST((head)); \
+ (var); \
+ (var) = SLIST_NEXT((var), field))
+
+#define SLIST_INIT(head) do { \
+ SLIST_FIRST((head)) = NULL; \
+} while (0)
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
+ SLIST_NEXT((slistelm), field) = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
+ SLIST_FIRST((head)) = (elm); \
+} while (0)
+
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ if (SLIST_FIRST((head)) == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } \
+ else { \
+ struct type *curelm = SLIST_FIRST((head)); \
+ while (SLIST_NEXT(curelm, field) != (elm)) \
+ curelm = SLIST_NEXT(curelm, field); \
+ SLIST_NEXT(curelm, field) = \
+ SLIST_NEXT(SLIST_NEXT(curelm, field), field); \
+ } \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
+} while (0)
+
diff --git a/usr/src/lib/libsmbfs/smb/rap.c b/usr/src/lib/libsmbfs/smb/rap.c
new file mode 100644
index 0000000000..00ccbd54a2
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/rap.c
@@ -0,0 +1,468 @@
+/*
+ * 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.
+ *
+ * $Id: rap.c,v 1.5 2004/12/13 00:25:23 lindak Exp $
+ *
+ * This is very simple implementation of RAP protocol.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/isa_defs.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <libintl.h>
+#include <sysexits.h>
+
+#include <netsmb/mchain.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/smb_rap.h>
+
+static int
+smb_rap_parserqparam(const char *s, char **next, int *rlen)
+{
+ char *np;
+ int len;
+
+ switch (*s++) {
+ case 'L':
+ case 'T':
+ case 'W':
+ len = 2;
+ break;
+ case 'D':
+ case 'O':
+ len = 4;
+ break;
+ case 'b':
+ case 'F':
+ len = 1;
+ break;
+ case 'r':
+ case 's':
+ len = 0;
+ break;
+ default:
+ return (EINVAL);
+ }
+ if (isdigit(*s)) {
+ len *= strtoul(s, &np, 10);
+ s = np;
+ }
+ *rlen = len;
+ *(const char **)next = s;
+ return (0);
+}
+
+static int
+smb_rap_parserpparam(const char *s, char **next, int *rlen)
+{
+ char *np;
+ int len = 0;
+
+ switch (*s++) {
+ case 'e':
+ case 'h':
+ len = 2;
+ break;
+ case 'i':
+ len = 4;
+ break;
+ case 'g':
+ len = 1;
+ break;
+ default:
+ return (EINVAL);
+ }
+ if (isdigit(*s)) {
+ len *= strtoul(s, &np, 10);
+ s = np;
+ }
+ *rlen = len;
+ *(const char **)next = s;
+ return (0);
+}
+
+static int
+smb_rap_parserpdata(const char *s, char **next, int *rlen)
+{
+ char *np;
+ int len;
+
+ switch (*s++) {
+ case 'B':
+ len = 1;
+ break;
+ case 'W':
+ len = 2;
+ break;
+ case 'D':
+ case 'O':
+ case 'z':
+ len = 4;
+ break;
+ default:
+ return (EINVAL);
+ }
+ if (isdigit(*s)) {
+ len *= strtoul(s, &np, 10);
+ s = np;
+ }
+ *rlen = len;
+ *(const char **)next = s;
+ return (0);
+}
+
+static int
+smb_rap_rqparam_z(struct smb_rap *rap, const char *value)
+{
+ int len = strlen(value) + 1;
+
+ bcopy(value, rap->r_npbuf, len);
+ rap->r_npbuf += len;
+ rap->r_plen += len;
+ return (0);
+}
+
+/*
+ * Marshal RAP request parameters.
+ * Note: value is in host order.
+ */
+static int
+smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, int value)
+{
+ char *p = rap->r_npbuf;
+ int len = 0;
+ uint_t uv = (uint_t)value;
+
+ switch (ptype) {
+ case 'L':
+ case 'W':
+ /* LINTED */
+ setwle(p, 0, uv);
+ len = 2;
+ break;
+ case 'D':
+ /* LINTED */
+ setdle(p, 0, uv);
+ len = 4;
+ break;
+ case 'b':
+ memset(p, uv, plen);
+ len = plen;
+ default:
+ return (EINVAL);
+ }
+ rap->r_npbuf += len;
+ rap->r_plen += len;
+ return (0);
+}
+
+int
+smb_rap_create(int fn, const char *param, const char *data,
+ struct smb_rap **rapp)
+{
+ struct smb_rap *rap;
+ char *p;
+ int plen = 0, len = 0;
+ int i;
+
+ rap = malloc(sizeof (*rap));
+ if (rap == NULL)
+ return (ENOMEM);
+ bzero(rap, sizeof (*rap));
+ p = rap->r_sparam = rap->r_nparam = strdup(param);
+ rap->r_sdata = rap->r_ndata = strdup(data);
+
+ /*
+ * Calculate length of request parameter block
+ */
+ len = 2 + strlen(param) + 1 + strlen(data) + 1;
+ while (*p) {
+ if (smb_rap_parserqparam(p, &p, &plen) != 0)
+ break;
+ len += plen;
+ }
+ rap->r_pbuf = rap->r_npbuf = malloc(len);
+ smb_rap_rqparam(rap, 'W', 1, fn);
+ smb_rap_rqparam_z(rap, rap->r_sparam);
+ smb_rap_rqparam_z(rap, rap->r_sdata);
+ *rapp = rap;
+ return (0);
+}
+
+void
+smb_rap_done(struct smb_rap *rap)
+{
+ if (rap->r_sparam)
+ free(rap->r_sparam);
+ if (rap->r_sdata)
+ free(rap->r_sdata);
+ if (rap->r_pbuf)
+ free(rap->r_pbuf);
+#ifdef NOTYETDEFINED
+ if (rap->r_npbuf)
+ free(rap->r_npbuf);
+ if (rap->r_dbuf)
+ free(rap->r_dbuf);
+ if (rap->r_rcvbuf)
+ free(rap->r_rcvbuf);
+#endif
+ free(rap);
+}
+
+int
+smb_rap_setNparam(struct smb_rap *rap, int value)
+{
+ char *p = rap->r_nparam;
+ char ptype = *p;
+ int error, plen;
+
+ error = smb_rap_parserqparam(p, &p, &plen);
+ if (error)
+ return (error);
+ switch (ptype) {
+ case 'L':
+ rap->r_rcvbuflen = value;
+ /* FALLTHROUGH */
+ case 'W':
+ case 'D':
+ case 'b':
+ error = smb_rap_rqparam(rap, ptype, plen, value);
+ break;
+ default:
+ return (EINVAL);
+ }
+ rap->r_nparam = p;
+ return (0);
+}
+
+int
+smb_rap_setPparam(struct smb_rap *rap, void *value)
+{
+ char *p = rap->r_nparam;
+ char ptype = *p;
+ int error, plen;
+
+ error = smb_rap_parserqparam(p, &p, &plen);
+ if (error)
+ return (error);
+ switch (ptype) {
+ case 'r':
+ rap->r_rcvbuf = value;
+ break;
+ default:
+ return (EINVAL);
+ }
+ rap->r_nparam = p;
+ return (0);
+}
+
+static int
+smb_rap_getNparam(struct smb_rap *rap, long *value)
+{
+ char *p = rap->r_nparam;
+ char ptype = *p;
+ int error, plen;
+ uint16_t *te;
+
+ error = smb_rap_parserpparam(p, &p, &plen);
+ if (error)
+ return (error);
+ switch (ptype) {
+ case 'h':
+ /* LINTED */
+ te = (uint16_t *)rap->r_npbuf;
+ *value = letohs(*te);
+ break;
+ default:
+ return (EINVAL);
+ }
+ rap->r_npbuf += plen;
+ rap->r_nparam = p;
+ return (0);
+}
+
+int
+smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
+{
+ uint16_t *rp, conv, *tmp;
+ uint32_t *p32, ps1;
+ char *dp, *p = rap->r_nparam;
+ char ptype;
+ int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow, i;
+
+ rdatacnt = rap->r_rcvbuflen;
+ rparamcnt = rap->r_plen;
+ error = smb_t2_request(ctx, 0, NULL, "\\PIPE\\LANMAN",
+ rap->r_plen, rap->r_pbuf, /* int tparamcnt,void *tparam */
+ 0, NULL, /* int tdatacnt, void *tdata */
+ &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */
+ &rdatacnt, rap->r_rcvbuf, /* int *rdatacnt, void *rdata */
+ &buffer_oflow);
+ if (error)
+ return (error);
+
+ /* LINTED */
+ rp = (uint16_t *)rap->r_pbuf;
+
+ /*
+ * Note: First is a "LanMan API" error code.
+ * See: usr/src/uts/common/smbsrv/lmerr.h
+ */
+ if (rparamcnt < 2)
+ return (EBADRPC);
+ rap->r_result = letohs(*rp);
+ rp++; rparamcnt -= 2;
+
+ if (rap->r_result != 0) {
+ /*
+ * Could also return zero and let the caller
+ * come get r_result via smb_rap_error(),
+ * but in case they dont...
+ */
+ return (rap->r_result | SMB_RAP_ERROR);
+ }
+
+ if (rparamcnt < 2)
+ return (EBADRPC);
+ conv = letohs(*rp);
+ rp++; rparamcnt -= 2;
+
+ rap->r_npbuf = (char *)rp;
+ rap->r_entries = entries = 0;
+ /* Save the returned data length */
+ rap->r_rcvbuflen = rdatacnt;
+ done = 0;
+
+ while (!done && *p) {
+ ptype = *p;
+ switch (ptype) {
+ case 'e':
+ if (rparamcnt < 2)
+ return (EBADRPC);
+ /* LINTED */
+ tmp = (uint16_t *)rap->r_npbuf;
+ rap->r_entries = entries = letohs(*tmp);
+ rap->r_npbuf += 2;
+ rparamcnt -= 2;
+ p++;
+ break;
+ default:
+ done = 1;
+ }
+#if 0 /* commented out in Darwin. Why? */
+ error = smb_rap_parserpparam(p, &p, &plen);
+ if (error) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "reply parameter mismatch %s"), 0, p);
+ return (EBADRPC);
+ }
+#endif
+ }
+ rap->r_nparam = p;
+ /*
+ * In general, unpacking entries we may need to relocate
+ * entries for proper aligning. For now use them as is.
+ */
+ dp = rap->r_rcvbuf;
+ while (entries--) {
+ p = rap->r_sdata;
+ while (*p) {
+ ptype = *p;
+ error = smb_rap_parserpdata(p, &p, &dlen);
+ if (error) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "reply data mismatch %s"), 0, p);
+ return (EBADRPC);
+ }
+ if (rdatacnt < dlen)
+ return (EBADRPC);
+ switch (ptype) {
+ case 'z':
+ /* LINTED */
+ p32 = (uint32_t *)dp;
+ *p32 = (letohl(*p32) & 0xffff) - conv;
+ break;
+ }
+ dp += dlen;
+ rdatacnt -= dlen;
+ }
+ }
+ return (error);
+}
+
+int
+smb_rap_error(struct smb_rap *rap, int error)
+{
+ if (error)
+ return (error);
+ if (rap->r_result == 0)
+ return (0);
+ return (rap->r_result | SMB_RAP_ERROR);
+}
+
+/* todo: move this function to libnetapi */
+int
+smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer,
+ int *cbBuffer, int *pcEntriesRead, int *pcTotalAvail)
+{
+ struct smb_rap *rap;
+ long lval = -1;
+ int error;
+ char *pass;
+ int i;
+
+ error = smb_rap_create(0, "WrLeh", "B13BWz", &rap);
+ if (error)
+ return (error);
+ smb_rap_setNparam(rap, sLevel); /* W - sLevel */
+ smb_rap_setPparam(rap, pbBuffer); /* r - pbBuffer */
+ smb_rap_setNparam(rap, *cbBuffer); /* L - cbBuffer */
+ error = smb_rap_request(rap, ctx);
+ if (error == 0) {
+ *pcEntriesRead = rap->r_entries;
+ error = smb_rap_getNparam(rap, &lval);
+ *pcTotalAvail = lval;
+ /* Copy the data length into the IN/OUT variable. */
+ *cbBuffer = rap->r_rcvbuflen;
+ }
+ error = smb_rap_error(rap, error);
+ smb_rap_done(rap);
+ return (error);
+}
diff --git a/usr/src/lib/libsmbfs/smb/rcfile.c b/usr/src/lib/libsmbfs/smb/rcfile.c
new file mode 100644
index 0000000000..498b91c0d8
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/rcfile.c
@@ -0,0 +1,644 @@
+/*
+ * 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.
+ *
+ * $Id: rcfile.c,v 1.1.1.2 2001/07/06 22:38:43 conrad Exp $
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <fcntl.h>
+#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 <unistd.h>
+#include <sys/debug.h>
+
+#include <cflib.h>
+#include "rcfile_priv.h"
+
+SLIST_HEAD(rcfile_head, rcfile);
+static struct rcfile_head pf_head = {NULL};
+
+static struct rcfile *rc_cachelookup(const char *filename);
+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 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);
+
+int insecure_nsmbrc;
+
+/*
+ * open rcfile and load its content, if already open - return previous handle
+ */
+int
+rc_open(const char *filename, const char *mode, struct rcfile **rcfile)
+{
+ struct rcfile *rcp;
+ FILE *f;
+ struct stat statbuf;
+
+ rcp = rc_cachelookup(filename);
+ if (rcp) {
+ *rcfile = rcp;
+ return (0);
+ }
+ f = fopen(filename, mode);
+ if (f == NULL)
+ return (errno);
+ insecure_nsmbrc = 0;
+ if (fstat(fileno(f), &statbuf) >= 0 &&
+ (statbuf.st_mode & 077) != 0)
+ insecure_nsmbrc = 1;
+ rcp = malloc(sizeof (struct rcfile));
+ if (rcp == NULL) {
+ fclose(f);
+ return (ENOMEM);
+ }
+ bzero(rcp, sizeof (struct rcfile));
+ rcp->rf_name = strdup(filename);
+ rcp->rf_f = f;
+ SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
+ rc_parse(rcp);
+ *rcfile = rcp;
+ return (0);
+}
+
+int
+rc_merge(const char *filename, struct rcfile **rcfile)
+{
+ struct rcfile *rcp = *rcfile;
+ FILE *f, *t;
+
+ insecure_nsmbrc = 0;
+ if (rcp == NULL) {
+ return (rc_open(filename, "r", rcfile));
+ }
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return (errno);
+ t = rcp->rf_f;
+ rcp->rf_f = f;
+ rc_parse(rcp);
+ rcp->rf_f = t;
+ fclose(f);
+ return (0);
+}
+
+int
+rc_merge_pipe(const char *command, struct rcfile **rcfile)
+{
+ struct rcfile *rcp = *rcfile;
+ FILE *f, *t;
+
+ insecure_nsmbrc = 0;
+ f = popen(command, "r");
+ if (f == NULL)
+ return (errno);
+ 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 (0);
+}
+
+int
+rc_close(struct rcfile *rcp)
+{
+ struct rcsection *p, *n;
+
+ fclose(rcp->rf_f);
+ for (p = SLIST_FIRST(&rcp->rf_sect); p; ) {
+ n = p;
+ p = SLIST_NEXT(p, rs_next);
+ rc_freesect(rcp, n);
+ }
+ free(rcp->rf_name);
+ SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next);
+ free(rcp);
+ return (0);
+}
+
+static struct rcfile *
+rc_cachelookup(const char *filename)
+{
+ struct rcfile *p;
+
+ SLIST_FOREACH(p, &pf_head, rf_next)
+ if (strcmp(filename, p->rf_name) == 0)
+ return (p);
+ return (0);
+}
+
+/* static */ struct rcsection *
+rc_findsect(struct rcfile *rcp, const char *sectname)
+{
+ struct rcsection *p;
+
+ SLIST_FOREACH(p, &rcp->rf_sect, rs_next)
+ if (strcasecmp(p->rs_name, sectname) == 0)
+ return (p);
+ return (NULL);
+}
+
+static struct rcsection *
+rc_addsect(struct rcfile *rcp, const char *sectname)
+{
+ struct rcsection *p;
+
+ p = rc_findsect(rcp, sectname);
+ if (p)
+ return (p);
+ p = malloc(sizeof (*p));
+ if (!p)
+ return (NULL);
+ p->rs_name = strdup(sectname);
+ SLIST_INIT(&p->rs_keys);
+ SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next);
+ return (p);
+}
+
+static int
+rc_freesect(struct rcfile *rcp, struct rcsection *rsp)
+{
+ struct rckey *p, *n;
+
+ SLIST_REMOVE(&rcp->rf_sect, rsp, rcsection, rs_next);
+ for (p = SLIST_FIRST(&rsp->rs_keys); p; ) {
+ n = p;
+ p = SLIST_NEXT(p, rk_next);
+ rc_key_free(n);
+ }
+ free(rsp->rs_name);
+ free(rsp);
+ return (0);
+}
+
+/* static */ struct rckey *
+rc_sect_findkey(struct rcsection *rsp, const char *keyname)
+{
+ struct rckey *p;
+
+ SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
+ if (strcmp(p->rk_name, keyname) == 0)
+ return (p);
+ return (NULL);
+}
+
+static struct rckey *
+rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value)
+{
+ struct rckey *p;
+
+ p = rc_sect_findkey(rsp, name);
+ if (!p) {
+ p = malloc(sizeof (*p));
+ if (!p)
+ return (NULL);
+ SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next);
+ p->rk_name = strdup(name);
+ p->rk_value = value ? strdup(value) : strdup("");
+ }
+ return (p);
+}
+
+#if 0
+void
+rc_sect_delkey(struct rcsection *rsp, struct rckey *p)
+{
+
+ SLIST_REMOVE(&rsp->rs_keys, p, rckey, rk_next);
+ rc_key_free(p);
+}
+#endif
+
+static void
+rc_key_free(struct rckey *p)
+{
+ free(p->rk_value);
+ free(p->rk_name);
+ free(p);
+}
+
+enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
+
+int home_nsmbrc = 0;
+
+static char *minauth[] = {
+ "kerberos",
+ "ntlmv2",
+ "ntlm",
+ "lm",
+ "none",
+ NULL
+};
+
+static int
+eval_minauth(char *auth)
+{
+ int i;
+
+ for (i = 0; minauth[i]; i++)
+ if (strcmp(auth, minauth[i]) == 0)
+ break;
+ return (i);
+}
+
+/*
+ * Ensure that "minauth" is set to the highest level (lowest array offset)
+ */
+static void
+set_value(struct rcfile *rcp, struct rcsection *rsp, struct rckey *rkp,
+ char *ptr)
+{
+ int now, new;
+
+ if (strcmp(rkp->rk_name, "minauth") == 0) {
+ now = eval_minauth(rkp->rk_value);
+ new = eval_minauth(ptr);
+ if (new >= now) {
+#ifdef DEBUG
+ printf("set_value: rejecting %s=%s from %s\n",
+ rkp->rk_name, ptr, home_nsmbrc ? "user file" : "SMF");
+#endif
+ return;
+ }
+ }
+#ifdef DEBUG
+ printf("set_value: applying %s=%s from %s\n",
+ rkp->rk_name, ptr, home_nsmbrc ? "user file" : "SMF");
+#endif
+ rkp->rk_value = strdup(ptr);
+}
+
+static void
+rc_parse(struct rcfile *rcp)
+{
+ FILE *f = rcp->rf_f;
+ int state = stNewLine, c;
+ struct rcsection *rsp = NULL;
+ struct rckey *rkp = NULL;
+ char buf[2048];
+ char *next = buf, *last = &buf[sizeof (buf)-1];
+
+ while ((c = getc(f)) != EOF) {
+ if (c == '\r')
+ continue;
+ if (state == stNewLine) {
+ next = buf;
+ if (isspace(c))
+ continue; /* skip leading junk */
+ if (c == '[') {
+ state = stHeader;
+ rsp = NULL;
+ continue;
+ }
+ if (c == '#' || c == ';') {
+ state = stSkipToEOL;
+ } else { /* something meaningfull */
+ state = stGetKey;
+ }
+ }
+ /* ignore long lines */
+ if (state == stSkipToEOL || next == last) {
+ if (c == '\n') {
+ state = stNewLine;
+ next = buf;
+ }
+ continue;
+ }
+ if (state == stHeader) {
+ if (c == ']') {
+ *next = 0;
+ next = buf;
+ rsp = rc_addsect(rcp, buf);
+ state = stSkipToEOL;
+ } else
+ *next++ = c;
+ continue;
+ }
+ if (state == stGetKey) {
+ /* side effect: 'key name=' */
+ if (c == ' ' || c == '\t')
+ continue; /* become 'keyname=' */
+ if (c == '\n') { /* silently ignore ... */
+ state = stNewLine;
+ continue;
+ }
+ if (c != '=') {
+ *next++ = c;
+ continue;
+ }
+ *next = 0;
+ if (rsp == NULL) {
+ fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "Key '%s' defined before section\n"), buf);
+ state = stSkipToEOL;
+ continue;
+ }
+ if (home_nsmbrc &&
+ (strcmp(buf, "nbns") == 0 ||
+ strcmp(buf, "nbns_enable") == 0 ||
+ strcmp(buf, "nbns_broadcast") == 0)) {
+ fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "option %s may not be set "
+ "in user .nsmbrc file\n"), buf);
+ next = buf;
+ state = stNewLine;
+ continue;
+ }
+ if (insecure_nsmbrc && (strcmp(buf, "password") == 0)) {
+ fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "Warning: .nsmbrc file not secure, "
+ "ignoring passwords\n"));
+ next = buf;
+ state = stNewLine;
+ continue;
+ }
+ rkp = rc_sect_addkey(rsp, buf, NULL);
+ next = buf;
+ state = stGetValue;
+ continue;
+ }
+ /* only stGetValue left */
+ if (state != stGetValue) {
+ fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "Well, I can't parse file '%s'\n"), rcp->rf_name);
+ state = stSkipToEOL;
+ }
+ if (c != '\n') {
+ *next++ = c;
+ continue;
+ }
+ *next = 0;
+ set_value(rcp, rsp, rkp, buf);
+ state = stNewLine;
+ rkp = NULL;
+ } /* while */
+ if (c == EOF && state == stGetValue) {
+ *next = 0;
+ set_value(rcp, rsp, rkp, buf);
+ }
+}
+
+int
+rc_getstringptr(struct rcfile *rcp, const char *section, const char *key,
+ char **dest)
+{
+ struct rcsection *rsp;
+ struct rckey *rkp;
+
+ *dest = NULL;
+ rsp = rc_findsect(rcp, section);
+ if (!rsp)
+ return (ENOENT);
+ rkp = rc_sect_findkey(rsp, key);
+ if (!rkp)
+ return (ENOENT);
+ *dest = rkp->rk_value;
+ return (0);
+}
+
+int
+rc_getstring(struct rcfile *rcp, const char *section, const char *key,
+ size_t maxlen, char *dest)
+{
+ char *value;
+ int error;
+
+ error = rc_getstringptr(rcp, section, key, &value);
+ if (error)
+ return (error);
+ if (strlen(value) >= maxlen) {
+ fprintf(stdout, dgettext(TEXT_DOMAIN,
+ "line too long for key '%s' in section '%s', max = %d\n"),
+ key, section, maxlen);
+ return (EINVAL);
+ }
+ strcpy(dest, value);
+ return (0);
+}
+
+int
+rc_getint(struct rcfile *rcp, const char *section, const char *key, int *value)
+{
+ struct rcsection *rsp;
+ struct rckey *rkp;
+
+ rsp = rc_findsect(rcp, section);
+ if (!rsp)
+ return (ENOENT);
+ rkp = rc_sect_findkey(rsp, key);
+ if (!rkp)
+ return (ENOENT);
+ errno = 0;
+ *value = strtol(rkp->rk_value, NULL, 0);
+ if (errno) {
+ fprintf(stdout, dgettext(TEXT_DOMAIN,
+ "invalid int value '%s' for key '%s' in section '%s'\n"),
+ rkp->rk_value, key, section);
+ return (errno);
+ }
+ return (0);
+}
+
+/*
+ * 1,yes,true
+ * 0,no,false
+ */
+int
+rc_getbool(struct rcfile *rcp, const char *section, const char *key, int *value)
+{
+ struct rcsection *rsp;
+ struct rckey *rkp;
+ char *p;
+
+ rsp = rc_findsect(rcp, section);
+ if (!rsp)
+ return (ENOENT);
+ rkp = rc_sect_findkey(rsp, key);
+ if (!rkp)
+ return (ENOENT);
+ p = rkp->rk_value;
+ while (*p && isspace(*p)) p++;
+ if (*p == '0' ||
+ strcasecmp(p, "no") == 0 ||
+ strcasecmp(p, "false") == 0) {
+ *value = 0;
+ return (0);
+ }
+ if (*p == '1' ||
+ strcasecmp(p, "yes") == 0 ||
+ strcasecmp(p, "true") == 0) {
+ *value = 1;
+ return (0);
+ }
+ fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "invalid boolean value '%s' for key '%s' in section '%s' \n"),
+ p, key, section);
+ return (EINVAL);
+}
+
+/*
+ * Unified command line/rc file parser
+ */
+int
+opt_args_parse(struct rcfile *rcp, struct opt_args *ap, const char *sect,
+ opt_callback_t *callback)
+{
+ 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;
+ }
+ }
+ return (0);
+}
+
+int
+opt_args_parseopt(struct opt_args *ap, int opt, char *arg,
+ opt_callback_t *callback)
+{
+ int len;
+
+ 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;
+ }
+ return (0);
+}
diff --git a/usr/src/lib/libsmbfs/smb/rcfile_priv.h b/usr/src/lib/libsmbfs/smb/rcfile_priv.h
new file mode 100644
index 0000000000..85ed97e1fd
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/rcfile_priv.h
@@ -0,0 +1,21 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+struct rckey {
+ SLIST_ENTRY(rckey) rk_next;
+ char *rk_name;
+ char *rk_value;
+};
+
+struct rcsection {
+ SLIST_ENTRY(rcsection) rs_next;
+ 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;
+};
+
diff --git a/usr/src/lib/libsmbfs/smb/rq.c b/usr/src/lib/libsmbfs/smb/rq.c
new file mode 100644
index 0000000000..c31c271819
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/rq.c
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ *
+ * $Id: rq.c,v 1.4 2004/12/13 00:25:23 lindak Exp $
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <libintl.h>
+
+#include <netsmb/smb_lib.h>
+
+extern uid_t real_uid, eff_uid;
+
+
+int
+smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, size_t rpbufsz,
+ struct smb_rq **rqpp)
+{
+ struct smb_rq *rqp;
+
+ rqp = malloc(sizeof (*rqp));
+ if (rqp == NULL)
+ return (ENOMEM);
+ 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);
+ *rqpp = rqp;
+ return (0);
+}
+
+void
+smb_rq_done(struct smb_rq *rqp)
+{
+ mb_done(&rqp->rq_rp);
+ mb_done(&rqp->rq_rq);
+ free(rqp);
+}
+
+void
+smb_rq_wend(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;
+}
+
+int
+smb_rq_dmem(struct mbdata *mbp, const char *src, size_t size)
+{
+ struct mbuf *m;
+ char *dst;
+ int cplen, error;
+
+ 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;
+ }
+ mbp->mb_pos = mtod(m, char *) + m->m_len;
+ mbp->mb_cur = m;
+ return (0);
+}
+
+int
+smb_rq_dstring(struct mbdata *mbp, const char *s)
+{
+ return (smb_rq_dmem(mbp, s, strlen(s) + 1));
+}
+
+int
+smb_rq_simple(struct smb_rq *rqp)
+{
+ struct smbioc_rq krq;
+ struct mbdata *mbp;
+ char *data;
+ int i;
+
+ 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;
+
+ mbp = smb_rq_getreply(rqp);
+ krq.ioc_rpbufsz = mbp->mb_top->m_maxlen;
+ krq.ioc_rpbuf = mtod(mbp->mb_top, char *);
+ seteuid(eff_uid);
+ if (ioctl(rqp->rq_ctx->ct_fd, SMBIOC_REQUEST, &krq) == -1) {
+ seteuid(real_uid); /* and back to real user */
+ 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;
+ seteuid(real_uid); /* and back to real user */
+ return (0);
+}
+
+
+int
+smb_t2_request(struct smb_ctx *ctx, int setupcount, uint16_t *setup,
+ const char *name,
+ int tparamcnt, void *tparam,
+ int tdatacnt, void *tdata,
+ int *rparamcnt, void *rparam,
+ int *rdatacnt, void *rdata,
+ int *buffer_oflow)
+{
+ 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) {
+ /* Bogus setup count, or too many setup words */
+ return (EINVAL);
+ }
+ for (i = 0; i < setupcount; i++)
+ krq->ioc_setup[i] = setup[i];
+ krq->ioc_setupcnt = setupcount;
+ strcpy(krq->ioc_name, name);
+ krq->ioc_tparamcnt = tparamcnt;
+ krq->ioc_tparam = tparam;
+ krq->ioc_tdatacnt = tdatacnt;
+ krq->ioc_tdata = tdata;
+
+ krq->ioc_rparamcnt = *rparamcnt;
+ krq->ioc_rdatacnt = *rdatacnt;
+ krq->ioc_rparam = rparam;
+ krq->ioc_rdata = rdata;
+
+ seteuid(eff_uid);
+ if (ioctl(ctx->ct_fd, SMBIOC_T2RQ, krq) == -1) {
+ seteuid(real_uid); /* and back to real user */
+ return (errno);
+ }
+
+ *rparamcnt = krq->ioc_rparamcnt;
+ *rdatacnt = krq->ioc_rdatacnt;
+ *buffer_oflow = (krq->ioc_rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
+ (krq->ioc_error == NT_STATUS_BUFFER_OVERFLOW);
+ seteuid(real_uid); /* and back to real user */
+ free(krq);
+ return (0);
+}
diff --git a/usr/src/lib/libsmbfs/smb/spnego.c b/usr/src/lib/libsmbfs/smb/spnego.c
new file mode 100644
index 0000000000..3e300cd606
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/spnego.c
@@ -0,0 +1,797 @@
+// Copyright (C) 2002 Microsoft Corporation
+// All rights reserved.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+// OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Date - 10/08/2002
+// Author - Sanj Surati
+
+/////////////////////////////////////////////////////////////
+//
+// SPNEGO.C
+//
+// SPNEGO Token Handler Source File
+//
+// Contains implementation of SPNEGO Token Handling API
+// as defined in SPNEGO.H.
+//
+/////////////////////////////////////////////////////////////
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include "spnego.h"
+#include "derparse.h"
+#include "spnegoparse.h"
+
+//
+// Defined in DERPARSE.C
+//
+
+extern MECH_OID g_stcMechOIDList [];
+
+
+/**********************************************************************/
+/** **/
+/** **/
+/** **/
+/** **/
+/** SPNEGO Token Handler API implementation **/
+/** **/
+/** **/
+/** **/
+/** **/
+/**********************************************************************/
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// spnegoInitFromBinary
+//
+// Parameters:
+// [in] pbTokenData - Binary Token Data
+// [in] ulLength - Length of binary Token Data
+// [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Initializes a SPNEGO_TOKEN_HANDLE from the supplied
+// binary data. Data is copied locally. Returned data structure
+// must be freed by calling spnegoFreeData().
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoInitFromBinary( unsigned char* pbTokenData, unsigned long ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken )
+{
+ int nReturn = SPNEGO_E_INVALID_PARAMETER;
+ SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken;
+
+ // Pass off to a handler function that allows tighter control over how the token structure
+ // is handled. In this case, we want the token data copied and we want the associated buffer
+ // freed.
+ nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYDATA,
+ SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA, pbTokenData,
+ ulLength, ppSpnegoToken );
+
+ return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// spnegoCreateNegTokenInit
+//
+// Parameters:
+// [in] MechType - MechType to specify in MechTypeList element
+// [in] ucContextFlags - Context Flags element value
+// [in] pbMechToken - Pointer to binary MechToken Data
+// [in] ulMechTokenLen - Length of MechToken Data
+// [in] pbMechListMIC - Pointer to binary MechListMIC Data
+// [in] ulMechListMICLen - Length of MechListMIC Data
+// [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenInit type
+// from the supplied parameters. ucContextFlags may be 0 or must be
+// a valid flag combination. MechToken data can be NULL - if not, it
+// must correspond to the MechType. MechListMIC can also be NULL.
+// Returned data structure must be freed by calling spnegoFreeData().
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType,
+ unsigned char ucContextFlags, unsigned char* pbMechToken,
+ unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
+ unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken )
+{
+ int nReturn = SPNEGO_E_INVALID_PARAMETER;
+ long nTokenLength = 0L;
+ long nInternalTokenLength = 0L;
+ unsigned char* pbTokenData = NULL;
+ SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken;
+
+ if ( NULL != ppSpnegoToken &&
+ IsValidMechOid( MechType ) &&
+ IsValidContextFlags( ucContextFlags ) )
+ {
+ // Get the actual token size
+
+ if ( ( nReturn = CalculateMinSpnegoInitTokenSize( ulMechTokenLen, ulMechListMICLen,
+ MechType, ( ucContextFlags != 0L ),
+ &nTokenLength, &nInternalTokenLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+ // Allocate a buffer to hold the data.
+ pbTokenData = calloc( 1, nTokenLength );
+
+ if ( NULL != pbTokenData )
+ {
+
+ // Now write the token
+ if ( ( nReturn = CreateSpnegoInitToken( MechType,
+ ucContextFlags, pbMechToken,
+ ulMechTokenLen, pbMechListMIC,
+ ulMechListMICLen, pbTokenData,
+ nTokenLength, nInternalTokenLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+
+ // This will copy our allocated pointer, and ensure that the sructure cleans
+ // up the data later
+ nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYPTR,
+ SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA,
+ pbTokenData, nTokenLength, ppSpnegoToken );
+
+ }
+
+ // Cleanup on failure
+ if ( SPNEGO_E_SUCCESS != nReturn )
+ {
+ free( pbTokenData );
+ }
+
+ } // IF alloc succeeded
+ else
+ {
+ nReturn = SPNEGO_E_OUT_OF_MEMORY;
+ }
+
+ } // If calculated token size
+
+ } // IF Valid Parameters
+
+ return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// spnegoCreateNegTokenTarg
+//
+// Parameters:
+// [in] MechType - MechType to specify in supported MechType element
+// [in] spnegoNegResult - NegResult value
+// [in] pbMechToken - Pointer to response MechToken Data
+// [in] ulMechTokenLen - Length of MechToken Data
+// [in] pbMechListMIC - Pointer to binary MechListMIC Data
+// [in] ulMechListMICLen - Length of MechListMIC Data
+// [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenTarg type
+// from the supplied parameters. MechToken data can be NULL - if not,
+// it must correspond to the MechType. MechListMIC can also be NULL.
+// Returned data structure must be freed by calling spnegoFreeData().
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoCreateNegTokenTarg( SPNEGO_MECH_OID MechType,
+ SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken,
+ unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
+ unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken )
+{
+ int nReturn = SPNEGO_E_INVALID_PARAMETER;
+ long nTokenLength = 0L;
+ long nInternalTokenLength = 0L;
+ unsigned char* pbTokenData = NULL;
+ SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken;
+
+ //
+ // spnego_mech_oid_NotUsed and spnego_negresult_NotUsed
+ // are okay here, however a valid MechOid is required
+ // if spnego_negresult_success or spnego_negresult_incomplete
+ // is specified.
+ //
+
+ if ( NULL != ppSpnegoToken &&
+
+ ( IsValidMechOid( MechType ) ||
+ spnego_mech_oid_NotUsed == MechType ) &&
+
+ ( IsValidNegResult( spnegoNegResult ) ||
+ spnego_negresult_NotUsed == spnegoNegResult ) &&
+
+ !( !IsValidMechOid( MechType ) &&
+ ( spnego_negresult_success == spnegoNegResult ||
+ spnego_negresult_incomplete == spnegoNegResult ) ) )
+ {
+
+ // Get the actual token size
+
+ if ( ( nReturn = CalculateMinSpnegoTargTokenSize( MechType, spnegoNegResult, ulMechTokenLen,
+ ulMechListMICLen, &nTokenLength,
+ &nInternalTokenLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+ // Allocate a buffer to hold the data.
+ pbTokenData = calloc( 1, nTokenLength );
+
+ if ( NULL != pbTokenData )
+ {
+
+ // Now write the token
+ if ( ( nReturn = CreateSpnegoTargToken( MechType,
+ spnegoNegResult, pbMechToken,
+ ulMechTokenLen, pbMechListMIC,
+ ulMechListMICLen, pbTokenData,
+ nTokenLength, nInternalTokenLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+
+ // This will copy our allocated pointer, and ensure that the sructure cleans
+ // up the data later
+ nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYPTR,
+ SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA,
+ pbTokenData, nTokenLength, ppSpnegoToken );
+
+ }
+
+ // Cleanup on failure
+ if ( SPNEGO_E_SUCCESS != nReturn )
+ {
+ free( pbTokenData );
+ }
+
+ } // IF alloc succeeded
+ else
+ {
+ nReturn = SPNEGO_E_OUT_OF_MEMORY;
+ }
+
+ } // If calculated token size
+
+ } // IF Valid Parameters
+
+ return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// spnegoTokenGetBinary
+//
+// Parameters:
+// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
+// [out] pbTokenData - Buffer to copy token into
+// [in/out] pulDataLen - Length of pbTokenData buffer, filled out
+// with actual size used upon function return.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Copies binary SPNEGO token data from hSpnegoToken into the user
+// supplied buffer. If pbTokenData is NULL, or the value in pulDataLen
+// is too small, the function will return SPNEGO_E_BUFFER_TOO_SMALL and
+// fill out pulDataLen with the minimum required buffer size.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoTokenGetBinary( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData,
+ unsigned long * pulDataLen )
+{
+ int nReturn = SPNEGO_E_INVALID_PARAMETER;
+ SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+
+ // Check parameters - pbTokenData is optional
+ if ( IsValidSpnegoToken( pSpnegoToken ) &&
+ NULL != pulDataLen )
+ {
+
+ // Check for Buffer too small conditions
+ if ( NULL == pbTokenData ||
+ pSpnegoToken->ulBinaryDataLen > *pulDataLen )
+ {
+ *pulDataLen = pSpnegoToken->ulBinaryDataLen;
+ nReturn = SPNEGO_E_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ memcpy( pbTokenData, pSpnegoToken->pbBinaryData, pSpnegoToken->ulBinaryDataLen );
+ *pulDataLen = pSpnegoToken->ulBinaryDataLen;
+ nReturn = SPNEGO_E_SUCCESS;
+ }
+
+ } // IF parameters OK
+
+ return nReturn;;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// spnegoFreeData
+//
+// Parameters:
+// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
+//
+// Returns:
+// void
+//
+// Comments :
+// Frees up resources consumed by hSpnegoToken. The supplied data
+// pointer is invalidated by this function.
+//
+////////////////////////////////////////////////////////////////////////////
+
+void spnegoFreeData( SPNEGO_TOKEN_HANDLE hSpnegoToken )
+{
+ FreeSpnegoToken( (SPNEGO_TOKEN*) hSpnegoToken);
+ return;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// spnegoGetTokenType
+//
+// Parameters:
+// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
+// [out] piTokenType - Filled out with token type value.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// The function will analyze hSpnegoToken and return the appropriate
+// type in piTokenType.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoGetTokenType( SPNEGO_TOKEN_HANDLE hSpnegoToken, int * piTokenType )
+{
+ int nReturn = SPNEGO_E_INVALID_PARAMETER;
+ SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+
+ // Check parameters
+ if ( IsValidSpnegoToken( pSpnegoToken ) &&
+ NULL != piTokenType &&
+ pSpnegoToken)
+ {
+
+ // Check that the type in the structure makes sense
+ if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ||
+ SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType )
+ {
+ *piTokenType = pSpnegoToken->ucTokenType;
+ nReturn = SPNEGO_E_SUCCESS;
+ }
+
+ } // IF parameters OK
+
+ return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// spnegoIsMechTypeAvailable
+//
+// Parameters:
+// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
+// [in] MechOID - MechOID to search MechTypeList for
+// [out] piMechTypeIndex - Filled out with index in MechTypeList
+// element if MechOID is found.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// hSpnegoToken must reference a token of type NegTokenInit. The
+// function will search the MechTypeList element for an OID corresponding
+// to the specified MechOID. If one is found, the index (0 based) will
+// be passed into the piMechTypeIndex parameter.
+//
+////////////////////////////////////////////////////////////////////////////
+
+// Returns the Initial Mech Type in the MechList element in the NegInitToken.
+int spnegoIsMechTypeAvailable( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int * piMechTypeIndex )
+{
+ int nReturn = SPNEGO_E_INVALID_PARAMETER;
+ SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+
+ // Check parameters
+ if ( IsValidSpnegoToken( pSpnegoToken ) &&
+ NULL != piMechTypeIndex &&
+ IsValidMechOid( MechOID ) &&
+ SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
+ {
+
+ // Check if MechList is available
+ if ( pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT].iElementPresent
+ == SPNEGO_TOKEN_ELEMENT_AVAILABLE )
+ {
+ // Locate the MechOID in the list element
+ nReturn = FindMechOIDInMechList(
+ &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT],
+ MechOID, piMechTypeIndex );
+ }
+ else
+ {
+ nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
+ }
+
+ } // IF parameters OK
+
+ return nReturn;;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// spnegoGetContextFlags
+//
+// Parameters:
+// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
+// [out] pucContextFlags - Filled out with ContextFlags value.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// hSpnegoToken must reference a token of type NegTokenInit. The
+// function will copy data from the ContextFlags element into the
+// location pucContextFlags points to. Note that the function will
+// fail if the actual ContextFlags data appears invalid.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoGetContextFlags( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags )
+{
+ int nReturn = SPNEGO_E_INVALID_PARAMETER;
+ SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+
+ // Check parameters
+ if ( IsValidSpnegoToken( pSpnegoToken ) &&
+ NULL != pucContextFlags &&
+ SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
+ {
+
+ // Check if ContextFlags is available
+ if ( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].iElementPresent
+ == SPNEGO_TOKEN_ELEMENT_AVAILABLE )
+ {
+ // The length should be two, the value should show a 1 bit difference in the difference byte, and
+ // the value must be valid
+ if ( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].nDatalength == SPNEGO_NEGINIT_MAXLEN_REQFLAGS &&
+ pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[0] == SPNEGO_NEGINIT_REQFLAGS_BITDIFF &&
+ IsValidContextFlags( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[1] ) )
+ {
+ *pucContextFlags = pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[1];
+ nReturn = SPNEGO_E_SUCCESS;
+ }
+ else
+ {
+ nReturn = SPNEGO_E_INVALID_ELEMENT;
+ }
+
+ }
+ else
+ {
+ nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
+ }
+
+ } // IF parameters OK
+
+ return nReturn;;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// spnegoGetNegotiationResult
+//
+// Parameters:
+// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
+// [out] pnegResult - Filled out with NegResult value.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// hSpnegoToken must reference a token of type NegTokenTarg. The
+// function will copy data from the NegResult element into the
+// location pointed to by pnegResult. Note that the function will
+// fail if the actual NegResult data appears invalid.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoGetNegotiationResult( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult )
+{
+ int nReturn = SPNEGO_E_INVALID_PARAMETER;
+ SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+
+ // Check parameters
+ if ( IsValidSpnegoToken( pSpnegoToken ) &&
+ NULL != pnegResult &&
+ SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType )
+ {
+
+ // Check if NegResult is available
+ if ( pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].iElementPresent
+ == SPNEGO_TOKEN_ELEMENT_AVAILABLE )
+ {
+ // Must be 1 byte long and a valid value
+ if ( pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].nDatalength == SPNEGO_NEGTARG_MAXLEN_NEGRESULT &&
+ IsValidNegResult( *pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData ) )
+ {
+ *pnegResult = *pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData;
+ nReturn = SPNEGO_E_SUCCESS;
+ }
+ else
+ {
+ nReturn = SPNEGO_E_INVALID_ELEMENT;
+ }
+ }
+ else
+ {
+ nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
+ }
+
+ } // IF parameters OK
+
+ return nReturn;;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// spnegoGetSupportedMechType
+//
+// Parameters:
+// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
+// [out] pMechOID - Filled out with Supported MechType value.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// hSpnegoToken must reference a token of type NegTokenTarg. The
+// function will check the Supported MechType element, and if it
+// corresponds to a supported MechType ( spnego_mech_oid_Kerberos_V5_Legacy
+// or spnego_mech_oid_Kerberos_V5 ), will set the location pointed
+// to by pMechOID equal to the appropriate value.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoGetSupportedMechType( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID )
+{
+ int nReturn = SPNEGO_E_INVALID_PARAMETER;
+ int nCtr = 0L;
+ long nLength = 0L;
+ SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+
+ // Check parameters
+ if ( IsValidSpnegoToken( pSpnegoToken ) &&
+ NULL != pMechOID &&
+ SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType )
+ {
+
+ // Check if MechList is available
+ if ( pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].iElementPresent
+ == SPNEGO_TOKEN_ELEMENT_AVAILABLE )
+ {
+
+ for ( nCtr = 0;
+ nReturn != SPNEGO_E_SUCCESS &&
+ g_stcMechOIDList[nCtr].eMechanismOID != spnego_mech_oid_NotUsed;
+ nCtr++ )
+ {
+
+ if ( ( nReturn = ASNDerCheckOID(
+ pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].pbData,
+ nCtr,
+ pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].nDatalength,
+ &nLength ) ) == SPNEGO_E_SUCCESS )
+ {
+ *pMechOID = nCtr;
+ }
+
+ } // For enum MechOIDs
+
+
+ }
+ else
+ {
+ nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
+ }
+
+ } // IF parameters OK
+
+ return nReturn;;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// spnegoTokenGetMechToken
+//
+// Parameters:
+// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
+// [out] pbTokenData - Buffer to copy MechToken into
+// [in/out] pulDataLen - Length of pbTokenData buffer, filled out
+// with actual size used upon function return.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token.
+// The function will copy the MechToken (the initial MechToken if
+// NegTokenInit, the response MechToken if NegTokenTarg) from the
+// underlying token into the buffer pointed to by pbTokenData. If
+// pbTokenData is NULL, or the value in pulDataLen is too small, the
+// function will return SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen
+// with the minimum required buffer size. The token can then be passed
+// to a GSS-API function for processing.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoGetMechToken( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned long* pulDataLen )
+{
+ int nReturn = SPNEGO_E_INVALID_PARAMETER;
+ SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+ SPNEGO_ELEMENT* pSpnegoElement = NULL;
+
+ // Check parameters
+ if ( IsValidSpnegoToken( pSpnegoToken ) &&
+ NULL != pulDataLen )
+ {
+
+ // Point at the proper Element
+ if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
+ {
+ pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTOKEN_ELEMENT];
+ }
+ else
+ {
+ pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_TARG_RESPTOKEN_ELEMENT];
+ }
+
+ // Check if MechType is available
+ if ( SPNEGO_TOKEN_ELEMENT_AVAILABLE == pSpnegoElement->iElementPresent )
+ {
+ // Check for Buffer too small conditions
+ if ( NULL == pbTokenData ||
+ pSpnegoElement->nDatalength > *pulDataLen )
+ {
+ *pulDataLen = pSpnegoElement->nDatalength;
+ nReturn = SPNEGO_E_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ // Copy Memory
+ memcpy( pbTokenData, pSpnegoElement->pbData, pSpnegoElement->nDatalength );
+ *pulDataLen = pSpnegoElement->nDatalength;
+ nReturn = SPNEGO_E_SUCCESS;
+ }
+ }
+ else
+ {
+ nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
+ }
+
+ } // IF parameters OK
+
+ return nReturn;;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// spnegoTokenGetMechListMIC
+//
+// Parameters:
+// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
+// [out] pbTokenData - Buffer to copy MechListMIC data into
+// [in/out] pulDataLen - Length of pbTokenData buffer, filled out
+// with actual size used upon function return.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token.
+// The function will copy the MechListMIC data from the underlying token
+// into the buffer pointed to by pbTokenData. If pbTokenData is NULL,
+// or the value in pulDataLen is too small, the function will return
+// SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen with the minimum
+// required buffer size.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoGetMechListMIC( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned long* pulDataLen )
+{
+ int nReturn = SPNEGO_E_INVALID_PARAMETER;
+ SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+ SPNEGO_ELEMENT* pSpnegoElement = NULL;
+
+ // Check parameters
+ if ( IsValidSpnegoToken( pSpnegoToken ) &&
+ NULL != pulDataLen )
+ {
+
+ // Point at the proper Element
+ if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
+ {
+ pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHLISTMIC_ELEMENT];
+ }
+ else
+ {
+ pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_TARG_MECHLISTMIC_ELEMENT];
+ }
+
+ // Check if MechType is available
+ if ( SPNEGO_TOKEN_ELEMENT_AVAILABLE == pSpnegoElement->iElementPresent )
+ {
+ // Check for Buffer too small conditions
+ if ( NULL == pbMICData ||
+ pSpnegoElement->nDatalength > *pulDataLen )
+ {
+ *pulDataLen = pSpnegoElement->nDatalength;
+ nReturn = SPNEGO_E_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ // Copy Memory
+ memcpy( pbMICData, pSpnegoElement->pbData, pSpnegoElement->nDatalength );
+ *pulDataLen = pSpnegoElement->nDatalength;
+ nReturn = SPNEGO_E_SUCCESS;
+ }
+ }
+ else
+ {
+ nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
+ }
+
+ } // IF parameters OK
+
+ return nReturn;;
+}
+
diff --git a/usr/src/lib/libsmbfs/smb/spnego.h b/usr/src/lib/libsmbfs/smb/spnego.h
new file mode 100644
index 0000000000..9865fbd85d
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/spnego.h
@@ -0,0 +1,244 @@
+// Copyright (C) 2002 Microsoft Corporation
+// All rights reserved.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+// OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Date - 10/08/2002
+// Author - Sanj Surati
+
+/////////////////////////////////////////////////////////////
+//
+// SPNEGO.H
+//
+// SPNEGO Token Handler Header File
+//
+// Contains the definitions required to interpret and create
+// SPNEGO tokens so that Kerberos GSS tokens can be
+// Unpackaged/packaged.
+//
+/////////////////////////////////////////////////////////////
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifndef __SPNEGO_H__
+#define __SPNEGO_H__
+
+// C++ Specific
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+// Type Definitions
+
+//
+// Users of SPNEGO Token Handler API will request
+// these as well as free them,
+//
+typedef void* SPNEGO_TOKEN_HANDLE;
+
+//
+// Defines the element types that are found
+// in each of the tokens.
+//
+
+typedef enum spnego_element_type
+{
+ spnego_element_min, // Lower bound
+
+ // Init token elements
+ spnego_init_mechtypes,
+ spnego_init_reqFlags,
+ spnego_init_mechToken,
+ spnego_init_mechListMIC,
+
+ // Targ token elements
+ spnego_targ_negResult,
+ spnego_targ_supportedMech,
+ spnego_targ_responseToken,
+ spnego_targ_mechListMIC,
+
+ spnego_element_max // Upper bound
+
+} SPNEGO_ELEMENT_TYPE;
+
+//
+// Token Element Availability. Elements in both
+// token types are optional. Since there are only
+// 4 elements in each Token, we will allocate space
+// to hold the information, but we need a way to
+// indicate whether or not an element is available
+//
+
+#define SPNEGO_TOKEN_ELEMENT_UNAVAILABLE 0
+#define SPNEGO_TOKEN_ELEMENT_AVAILABLE 1
+
+//
+// Token type values. SPNEGO has 2 token types:
+// NegTokenInit and NegTokenTarg
+//
+
+#define SPNEGO_TOKEN_INIT 0
+#define SPNEGO_TOKEN_TARG 1
+
+//
+// GSS Mechanism OID enumeration. We only really handle
+// 3 different OIDs. These are stored in an array structure
+// defined in the parsing code.
+//
+
+typedef enum spnego_mech_oid
+{
+ // Init token elements
+ spnego_mech_oid_Kerberos_V5_Legacy, // Really V5, but OID off by 1 bit
+ spnego_mech_oid_Kerberos_V5,
+ spnego_mech_oid_Spnego,
+ spnego_mech_oid_NTLMSSP,
+ spnego_mech_oid_NotUsed = -1
+
+} SPNEGO_MECH_OID;
+
+//
+// Defines the negResult values.
+//
+
+typedef enum spnego_negResult
+{
+ spnego_negresult_success,
+ spnego_negresult_incomplete,
+ spnego_negresult_rejected,
+ spnego_negresult_NotUsed = -1
+} SPNEGO_NEGRESULT;
+
+//
+// Context Flags in NegTokenInit
+//
+
+//
+// ContextFlags values MUST be zero or a combination
+// of the below
+//
+
+#define SPNEGO_NEGINIT_CONTEXT_DELEG_FLAG 0x80
+#define SPNEGO_NEGINIT_CONTEXT_MUTUAL_FLAG 0x40
+#define SPNEGO_NEGINIT_CONTEXT_REPLAY_FLAG 0x20
+#define SPNEGO_NEGINIT_CONTEXT_SEQUENCE_FLAG 0x10
+#define SPNEGO_NEGINIT_CONTEXT_ANON_FLAG 0x8
+#define SPNEGO_NEGINIT_CONTEXT_CONF_FLAG 0x4
+#define SPNEGO_NEGINIT_CONTEXT_INTEG_FLAG 0x2
+
+//
+// Mask to retrieve valid values.
+//
+
+#define SPNEGO_NEGINIT_CONTEXT_MASK 0xFE // Logical combination of above flags
+
+//
+// SPNEGO API return codes.
+//
+
+// API function was successful
+#define SPNEGO_E_SUCCESS 0
+
+// The supplied Token was invalid
+#define SPNEGO_E_INVALID_TOKEN -1
+
+// An invalid length was encountered
+#define SPNEGO_E_INVALID_LENGTH -2
+
+// The Token Parse failed
+#define SPNEGO_E_PARSE_FAILED -3
+
+// The requested value was not found
+#define SPNEGO_E_NOT_FOUND -4
+
+// The requested element is not available
+#define SPNEGO_E_ELEMENT_UNAVAILABLE -5
+
+// Out of Memory
+#define SPNEGO_E_OUT_OF_MEMORY -6
+
+// Not Implemented
+#define SPNEGO_E_NOT_IMPLEMENTED -7
+
+// Invalid Parameter
+#define SPNEGO_E_INVALID_PARAMETER -8
+
+// Token Handler encountered an unexpected OID
+#define SPNEGO_E_UNEXPECTED_OID -9
+
+// The requested token was not found
+#define SPNEGO_E_TOKEN_NOT_FOUND -10
+
+// An unexpected type was encountered in the encoding
+#define SPNEGO_E_UNEXPECTED_TYPE -11
+
+// The buffer was too small
+#define SPNEGO_E_BUFFER_TOO_SMALL -12
+
+// A Token Element was invalid (e.g. improper length or value)
+#define SPNEGO_E_INVALID_ELEMENT -13
+
+/* Miscelaneous API Functions */
+
+// Frees opaque data
+void spnegoFreeData( SPNEGO_TOKEN_HANDLE hSpnegoToken );
+
+// Initializes SPNEGO_TOKEN structure from DER encoded binary data
+int spnegoInitFromBinary( unsigned char* pbTokenData, unsigned long ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken );
+
+// Initializes SPNEGO_TOKEN structure for a NegTokenInit type using the
+// supplied parameters
+int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType,
+ unsigned char ucContextFlags, unsigned char* pbMechToken,
+ unsigned long ulMechTokenLen, unsigned char* pbMechTokenMIC,
+ unsigned long ulMechTokenMIC, SPNEGO_TOKEN_HANDLE* phSpnegoToken );
+
+// Initializes SPNEGO_TOKEN structure for a NegTokenTarg type using the
+// supplied parameters
+int spnegoCreateNegTokenTarg( SPNEGO_MECH_OID MechType,
+ SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken,
+ unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
+ unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken );
+
+// Copies binary representation of SPNEGO Data into user supplied buffer
+int spnegoTokenGetBinary( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData,
+ unsigned long * pulDataLen );
+
+// Returns SPNEGO Token Type
+int spnegoGetTokenType( SPNEGO_TOKEN_HANDLE hSpnegoToken, int * piTokenType );
+
+/* Reading an Init Token */
+
+// Returns the Initial Mech Type in the MechList element in the NegInitToken.
+int spnegoIsMechTypeAvailable( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int * piMechTypeIndex );
+
+// Returns the value from the context flags element in the NegInitToken as an unsigned long
+int spnegoGetContextFlags( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags );
+
+/* Reading a Response Token */
+
+// Returns the value from the negResult element (Status code of GSS call - 0,1,2)
+int spnegoGetNegotiationResult( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult );
+
+// Returns the Supported Mech Type from the NegTokenTarg.
+int spnegoGetSupportedMechType( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID );
+
+/* Reading either Token Type */
+
+// Returns the actual Mechanism data from the token (this is what is passed into GSS-API functions
+int spnegoGetMechToken( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned long* pulDataLen );
+
+// Returns the Message Integrity BLOB in the token
+int spnegoGetMechListMIC( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned long* pulDataLen );
+
+// C++ Specific
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/usr/src/lib/libsmbfs/smb/spnegoparse.c b/usr/src/lib/libsmbfs/smb/spnegoparse.c
new file mode 100644
index 0000000000..5da1983c27
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/spnegoparse.c
@@ -0,0 +1,1883 @@
+// Copyright (C) 2002 Microsoft Corporation
+// All rights reserved.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+// OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Date - 10/08/2002
+// Author - Sanj Surati
+
+/////////////////////////////////////////////////////////////
+//
+// SPNEGOPARSE.C
+//
+// SPNEGO Token Handler Source File
+//
+// Contains implementation of SPNEGO Token parsing functions.
+//
+/////////////////////////////////////////////////////////////
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include "spnego.h"
+#include "derparse.h"
+#include "spnegoparse.h"
+
+//
+// Defined in DERPARSE.C
+//
+
+extern MECH_OID g_stcMechOIDList [];
+
+/**********************************************************************/
+/** **/
+/** **/
+/** **/
+/** **/
+/** Local SPNEGO Helper definitions **/
+/** **/
+/** **/
+/** **/
+/** **/
+/**********************************************************************/
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// CalculateMinSpnegoInitTokenSize
+//
+// Parameters:
+// [in] nMechTokenLength - Length of the MechToken Element
+// [in] nMechListMICLength - Length of the MechListMIC Element
+// [in] mechOID - OID for MechList
+// [in] nReqFlagsAvailable - Is ContextFlags element available
+// [out] pnTokenSize - Filled out with total size of token
+// [out] pnInternalTokenLength - Filled out with length minus length
+// for initial token.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Calculates the required length for a SPNEGO NegTokenInit token based
+// on the supplied variable length values and which elements are present.
+// Note that because the lengths can be represented by an arbitrary
+// number of bytes in DER encodings, we actually calculate the lengths
+// backwards, so we always know how many bytes we will potentially be
+// writing out.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int CalculateMinSpnegoInitTokenSize( long nMechTokenLength,
+ long nMechListMICLength, SPNEGO_MECH_OID mechOid,
+ int nReqFlagsAvailable, long* pnTokenSize,
+ long* pnInternalTokenLength )
+{
+ int nReturn = SPNEGO_E_INVALID_LENGTH;
+
+ // Start at 0.
+ long nTotalLength = 0;
+ long nTempLength= 0L;
+
+ // We will calculate this by walking the token backwards
+
+ // Start with MIC Element
+ if ( nMechListMICLength > 0L )
+ {
+ nTempLength = ASNDerCalcElementLength( nMechListMICLength, NULL );
+
+ // Check for rollover error
+ if ( nTempLength < nMechListMICLength )
+ {
+ goto xEndTokenInitLength;
+ }
+
+ nTotalLength += nTempLength;
+ }
+
+ // Next is the MechToken
+ if ( nMechTokenLength > 0L )
+ {
+ nTempLength += ASNDerCalcElementLength( nMechTokenLength, NULL );
+
+ // Check for rollover error
+ if ( nTempLength < nTotalLength )
+ {
+ goto xEndTokenInitLength;
+ }
+
+ nTotalLength = nTempLength;
+ }
+
+ // Next is the ReqFlags
+ if ( nReqFlagsAvailable )
+ {
+ nTempLength += ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, NULL );
+
+ // Check for rollover error
+ if ( nTempLength < nTotalLength )
+ {
+ goto xEndTokenInitLength;
+ }
+
+ nTotalLength = nTempLength;
+ }
+
+ // Next is the MechList - This is REQUIRED
+ nTempLength += ASNDerCalcMechListLength( mechOid, NULL );
+
+ // Check for rollover error
+ if ( nTempLength < nTotalLength )
+ {
+ goto xEndTokenInitLength;
+ }
+
+ nTotalLength = nTempLength;
+
+ // Following four fields are the basic header tokens
+
+ // Sequence Token
+ nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+ // Check for rollover error
+ if ( nTempLength < nTotalLength )
+ {
+ goto xEndTokenInitLength;
+ }
+
+ nTotalLength = nTempLength;
+
+ // Neg Token Identifier Token
+ nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+ // Check for rollover error
+ if ( nTempLength < nTotalLength )
+ {
+ goto xEndTokenInitLength;
+ }
+
+ nTotalLength = nTempLength;
+
+ // SPNEGO OID Token
+ nTempLength += g_stcMechOIDList[spnego_mech_oid_Spnego].iLen;
+
+ // Check for rollover error
+ if ( nTempLength < nTotalLength )
+ {
+ goto xEndTokenInitLength;
+ }
+
+ nTotalLength = nTempLength;
+
+ // App Constructed Token
+ nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+ // Check for rollover error
+ if ( nTempLength < nTotalLength )
+ {
+ goto xEndTokenInitLength;
+ }
+
+ // The internal length doesn't include the number of bytes
+ // for the initial token
+ *pnInternalTokenLength = nTotalLength;
+ nTotalLength = nTempLength;
+
+ // We're done
+ *pnTokenSize = nTotalLength;
+ nReturn = SPNEGO_E_SUCCESS;
+
+xEndTokenInitLength:
+
+ return nReturn;
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// CreateSpnegoInitToken
+//
+// Parameters:
+// [in] MechType - OID in MechList
+// [in] ucContextFlags - ContextFlags value
+// [in] pbMechToken - Mech Token Binary Data
+// [in] ulMechTokenLen - Length of Mech Token
+// [in] pbMechListMIC - MechListMIC Binary Data
+// [in] ulMechListMICn - Length of MechListMIC
+// [out] pbTokenData - Buffer to write token into.
+// [in] nTokenLength - Length of pbTokenData buffer
+// [in] nInternalTokenLength - Length of full token without leading
+// token bytes.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Uses DER to fill out pbTokenData with a SPNEGO NegTokenInit Token
+// Note that because the lengths can be represented by an arbitrary
+// number of bytes in DER encodings, we actually calculate the lengths
+// backwards, so we always know how many bytes we will potentially be
+// writing out.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType,
+ unsigned char ucContextFlags, unsigned char* pbMechToken,
+ unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
+ unsigned long ulMechListMICLen, unsigned char* pbTokenData,
+ long nTokenLength, long nInternalTokenLength )
+{
+ int nReturn = SPNEGO_E_INVALID_LENGTH;
+
+ // Start at 0.
+ long nTempLength= 0L;
+ long nTotalBytesWritten = 0L;
+ long nInternalLength = 0L;
+
+ unsigned char* pbWriteTokenData = pbTokenData + nTokenLength;
+
+ // Temporary buffer to hold the REQ Flags as BIT String Data
+ unsigned char abTempReqFlags[SPNEGO_NEGINIT_MAXLEN_REQFLAGS];
+
+
+ // We will write the token out backwards to properly handle the cases
+ // where the length bytes become adjustable
+
+ // Start with MIC Element
+ if ( ulMechListMICLen > 0L )
+ {
+ nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength );
+
+ // Decrease the pbWriteTokenData, now we know the length and
+ // write it out.
+
+ pbWriteTokenData -= nTempLength;
+ nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC,
+ OCTETSTRING, pbMechListMIC, ulMechListMICLen );
+
+ // Adjust Values and sanity check
+ nTotalBytesWritten += nTempLength;
+ nInternalTokenLength -= nTempLength;
+
+ if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+ {
+ goto xEndWriteNegTokenInit;
+ }
+
+ } // IF MechListMIC is present
+
+ // Next is the MechToken
+ if ( ulMechTokenLen > 0L )
+ {
+ nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength );
+
+ // Decrease the pbWriteTokenData, now we know the length and
+ // write it out.
+ pbWriteTokenData -= nTempLength;
+ nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHTOKEN,
+ OCTETSTRING, pbMechToken, ulMechTokenLen );
+ // Adjust Values and sanity check
+ nTotalBytesWritten += nTempLength;
+ nInternalTokenLength -= nTempLength;
+
+ if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+ {
+ goto xEndWriteNegTokenInit;
+ }
+
+ } // IF MechToken Length is present
+
+ // Next is the ReqFlags
+ if ( ucContextFlags > 0L )
+ {
+
+ nTempLength = ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, &nInternalLength );
+
+ // We need a byte that indicates how many bits difference between the number
+ // of bits used in final octet (we only have one) and the max (8)
+
+ abTempReqFlags[0] = SPNEGO_NEGINIT_REQFLAGS_BITDIFF;
+ abTempReqFlags[1] = ucContextFlags;
+
+ // Decrease the pbWriteTokenData, now we know the length and
+ // write it out.
+ pbWriteTokenData -= nTempLength;
+ nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_REQFLAGS,
+ BITSTRING, abTempReqFlags, SPNEGO_NEGINIT_MAXLEN_REQFLAGS );
+
+ // Adjust Values and sanity check
+ nTotalBytesWritten += nTempLength;
+ nInternalTokenLength -= nTempLength;
+
+ if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+ {
+ goto xEndWriteNegTokenInit;
+ }
+
+ } // IF ContextFlags
+
+ // Next is the MechList - This is REQUIRED
+ nTempLength = ASNDerCalcMechListLength( MechType, &nInternalLength );
+
+ // Decrease the pbWriteTokenData, now we know the length and
+ // write it out.
+ pbWriteTokenData -= nTempLength;
+ nTempLength = ASNDerWriteMechList( pbWriteTokenData, MechType );
+
+ // Adjust Values and sanity check
+ nTotalBytesWritten += nTempLength;
+ nInternalTokenLength -= nTempLength;
+
+ if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+ {
+ goto xEndWriteNegTokenInit;
+ }
+
+ // The next tokens we're writing out reflect the total number of bytes
+ // we have actually written out.
+
+ // Sequence Token
+ nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
+
+ // Decrease the pbWriteTokenData, now we know the length and
+ // write it out.
+ pbWriteTokenData -= nTempLength;
+ nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
+ NULL, nTotalBytesWritten );
+
+ // Adjust Values and sanity check
+ nTotalBytesWritten += nTempLength;
+ nInternalTokenLength -= nTempLength;
+
+ if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+ {
+ goto xEndWriteNegTokenInit;
+ }
+
+ // Neg Init Token Identifier Token
+ nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
+
+ // Decrease the pbWriteTokenData, now we know the length and
+ // write it out.
+ pbWriteTokenData -= nTempLength;
+ nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER,
+ NULL, nTotalBytesWritten );
+
+ // Adjust Values and sanity check
+ nTotalBytesWritten += nTempLength;
+ nInternalTokenLength -= nTempLength;
+
+ if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+ {
+ goto xEndWriteNegTokenInit;
+ }
+
+ // SPNEGO OID Token
+ nTempLength = g_stcMechOIDList[spnego_mech_oid_Spnego].iLen;
+
+ // Decrease the pbWriteTokenData, now we know the length and
+ // write it out.
+ pbWriteTokenData -= nTempLength;
+ nTempLength = ASNDerWriteOID( pbWriteTokenData, spnego_mech_oid_Spnego );
+
+ // Adjust Values and sanity check
+ nTotalBytesWritten += nTempLength;
+ nInternalTokenLength -= nTempLength;
+
+ if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+ {
+ goto xEndWriteNegTokenInit;
+ }
+
+ // App Constructed Token
+ nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
+
+ // Decrease the pbWriteTokenData, now we know the length and
+ // write it out.
+ pbWriteTokenData -= nTempLength;
+ nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT,
+ NULL, nTotalBytesWritten );
+
+ // Adjust Values and sanity check
+ nTotalBytesWritten += nTempLength;
+
+ // Don't adjust the internal token length here, it doesn't account
+ // the initial bytes written out (we really don't need to keep
+ // a running count here, but for debugging, it helps to be able
+ // to see the total number of bytes written out as well as the
+ // number of bytes left to write).
+
+ if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 &&
+ pbWriteTokenData == pbTokenData )
+ {
+ nReturn = SPNEGO_E_SUCCESS;
+ }
+
+xEndWriteNegTokenInit:
+
+ return nReturn;
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// CalculateMinSpnegoTargTokenSize
+//
+// Parameters:
+// [in] MechType - Supported MechType
+// [in] spnegoNegResult - Neg Result
+// [in] nMechTokenLength - Length of the MechToken Element
+// [in] nMechListMICLength - Length of the MechListMIC Element
+// [out] pnTokenSize - Filled out with total size of token
+// [out] pnInternalTokenLength - Filled out with length minus length
+// for initial token.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Calculates the required length for a SPNEGO NegTokenTarg token based
+// on the supplied variable length values and which elements are present.
+// Note that because the lengths can be represented by an arbitrary
+// number of bytes in DER encodings, we actually calculate the lengths
+// backwards, so we always know how many bytes we will potentially be
+// writing out.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType,
+ SPNEGO_NEGRESULT spnegoNegResult, long nMechTokenLen,
+ long nMechListMICLen, long* pnTokenSize,
+ long* pnInternalTokenLength )
+{
+ int nReturn = SPNEGO_E_INVALID_LENGTH;
+
+ // Start at 0.
+ long nTotalLength = 0;
+ long nTempLength= 0L;
+
+ // We will calculate this by walking the token backwards
+
+ // Start with MIC Element
+ if ( nMechListMICLen > 0L )
+ {
+ nTempLength = ASNDerCalcElementLength( nMechListMICLen, NULL );
+
+ // Check for rollover error
+ if ( nTempLength < nMechListMICLen )
+ {
+ goto xEndTokenTargLength;
+ }
+
+ nTotalLength += nTempLength;
+ }
+
+ // Next is the MechToken
+ if ( nMechTokenLen > 0L )
+ {
+ nTempLength += ASNDerCalcElementLength( nMechTokenLen, NULL );
+
+ // Check for rollover error
+ if ( nTempLength < nTotalLength )
+ {
+ goto xEndTokenTargLength;
+ }
+
+ nTotalLength = nTempLength;
+ }
+
+ // Supported MechType
+ if ( spnego_mech_oid_NotUsed != MechType )
+ {
+ // Supported MechOID element - we use the token function since
+ // we already know the size of the OID token and value
+ nTempLength += ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen,
+ NULL );
+
+ // Check for rollover error
+ if ( nTempLength < nTotalLength )
+ {
+ goto xEndTokenTargLength;
+ }
+
+ nTotalLength = nTempLength;
+
+ } // IF MechType is available
+
+ // NegResult Element
+ if ( spnego_negresult_NotUsed != spnegoNegResult )
+ {
+ nTempLength += ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, NULL );
+
+ // Check for rollover error
+ if ( nTempLength < nTotalLength )
+ {
+ goto xEndTokenTargLength;
+ }
+
+ nTotalLength = nTempLength;
+
+ } // IF negResult is available
+
+ // Following two fields are the basic header tokens
+
+ // Sequence Token
+ nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+ // Check for rollover error
+ if ( nTempLength < nTotalLength )
+ {
+ goto xEndTokenTargLength;
+ }
+
+ nTotalLength = nTempLength;
+
+ // Neg Token Identifier Token
+ nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+ // Check for rollover error
+ if ( nTempLength < nTotalLength )
+ {
+ goto xEndTokenTargLength;
+ }
+
+ // The internal length doesn't include the number of bytes
+ // for the initial token
+ *pnInternalTokenLength = nTotalLength;
+ nTotalLength = nTempLength;
+
+ // We're done
+ *pnTokenSize = nTotalLength;
+ nReturn = SPNEGO_E_SUCCESS;
+
+xEndTokenTargLength:
+
+ return nReturn;
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// CreateSpnegoTargToken
+//
+// Parameters:
+// [in] MechType - Supported MechType
+// [in] eNegResult - NegResult value
+// [in] pbMechToken - Mech Token Binary Data
+// [in] ulMechTokenLen - Length of Mech Token
+// [in] pbMechListMIC - MechListMIC Binary Data
+// [in] ulMechListMICn - Length of MechListMIC
+// [out] pbTokenData - Buffer to write token into.
+// [in] nTokenLength - Length of pbTokenData buffer
+// [in] nInternalTokenLength - Length of full token without leading
+// token bytes.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Uses DER to fill out pbTokenData with a SPNEGO NegTokenTarg Token
+// Note that because the lengths can be represented by an arbitrary
+// number of bytes in DER encodings, we actually calculate the lengths
+// backwards, so we always know how many bytes we will potentially be
+// writing out.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int CreateSpnegoTargToken( SPNEGO_MECH_OID MechType,
+ SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken,
+ unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
+ unsigned long ulMechListMICLen, unsigned char* pbTokenData,
+ long nTokenLength, long nInternalTokenLength )
+{
+ int nReturn = SPNEGO_E_INVALID_LENGTH;
+
+ // Start at 0.
+ long nTempLength= 0L;
+ long nTotalBytesWritten = 0L;
+ long nInternalLength = 0L;
+
+ unsigned char ucTemp = 0;
+
+ // We will write the token out backwards to properly handle the cases
+ // where the length bytes become adjustable, so the write location
+ // is initialized to point *just* past the end of the buffer.
+
+ unsigned char* pbWriteTokenData = pbTokenData + nTokenLength;
+
+
+ // Start with MIC Element
+ if ( ulMechListMICLen > 0L )
+ {
+ nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength );
+
+ // Decrease the pbWriteTokenData, now we know the length and
+ // write it out.
+
+ pbWriteTokenData -= nTempLength;
+ nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC,
+ OCTETSTRING, pbMechListMIC, ulMechListMICLen );
+
+ // Adjust Values and sanity check
+ nTotalBytesWritten += nTempLength;
+ nInternalTokenLength -= nTempLength;
+
+ if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+ {
+ goto xEndWriteNegTokenTarg;
+ }
+
+ } // IF MechListMIC is present
+
+ // Next is the MechToken
+ if ( ulMechTokenLen > 0L )
+ {
+ nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength );
+
+ // Decrease the pbWriteTokenData, now we know the length and
+ // write it out.
+ pbWriteTokenData -= nTempLength;
+ nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN,
+ OCTETSTRING, pbMechToken, ulMechTokenLen );
+ // Adjust Values and sanity check
+ nTotalBytesWritten += nTempLength;
+ nInternalTokenLength -= nTempLength;
+
+ if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+ {
+ goto xEndWriteNegTokenTarg;
+ }
+
+ } // IF MechToken Length is present
+
+ // Supported Mech Type
+ if ( spnego_mech_oid_NotUsed != MechType )
+ {
+
+ nTempLength = ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen,
+ &nInternalLength );
+
+ // Decrease the pbWriteTokenData, now we know the length and
+ // write it out.
+ pbWriteTokenData -= nTempLength;
+ nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH,
+ g_stcMechOIDList[MechType].ucOid,
+ g_stcMechOIDList[MechType].iLen );
+
+ // Adjust Values and sanity check
+ nTotalBytesWritten += nTempLength;
+ nInternalTokenLength -= nTempLength;
+
+ if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+ {
+ goto xEndWriteNegTokenTarg;
+ }
+
+ } // IF MechType is present
+
+ // Neg Result
+ // NegResult Element
+ if ( spnego_negresult_NotUsed != eNegResult )
+ {
+ ucTemp = (unsigned char) eNegResult;
+
+ nTempLength = ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, &nInternalLength );
+
+ // Decrease the pbWriteTokenData, now we know the length and
+ // write it out.
+ pbWriteTokenData -= nTempLength;
+ nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_NEGRESULT,
+ ENUMERATED, &ucTemp, SPNEGO_NEGTARG_MAXLEN_NEGRESULT );
+
+ // Adjust Values and sanity check
+ nTotalBytesWritten += nTempLength;
+ nInternalTokenLength -= nTempLength;
+
+ if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+ {
+ goto xEndWriteNegTokenTarg;
+ }
+
+ } // If eNegResult is available
+
+ // The next tokens we're writing out reflect the total number of bytes
+ // we have actually written out.
+
+ // Sequence Token
+ nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
+
+ // Decrease the pbWriteTokenData, now we know the length and
+ // write it out.
+ pbWriteTokenData -= nTempLength;
+ nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
+ NULL, nTotalBytesWritten );
+
+ // Adjust Values and sanity check
+ nTotalBytesWritten += nTempLength;
+ nInternalTokenLength -= nTempLength;
+
+ if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+ {
+ goto xEndWriteNegTokenTarg;
+ }
+
+ // Neg Targ Token Identifier Token
+ nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
+
+ // Decrease the pbWriteTokenData, now we know the length and
+ // write it out.
+ pbWriteTokenData -= nTempLength;
+ nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER,
+ NULL, nTotalBytesWritten );
+
+ // Adjust Values and sanity check
+ nTotalBytesWritten += nTempLength;
+
+ // Don't adjust the internal token length here, it doesn't account
+ // the initial bytes written out (we really don't need to keep
+ // a running count here, but for debugging, it helps to be able
+ // to see the total number of bytes written out as well as the
+ // number of bytes left to write).
+
+ if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 &&
+ pbWriteTokenData == pbTokenData )
+ {
+ nReturn = SPNEGO_E_SUCCESS;
+ }
+
+
+xEndWriteNegTokenTarg:
+
+ return nReturn;
+
+
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// AllocEmptySpnegoToken
+//
+// Parameters:
+// [in] ucCopyData - Flag to copy data or pointer.
+// [in] ulFlags - Flags for SPNEGO_TOKEN data member.
+// [in] pbTokenData - Binary token data.
+// [in] ulTokenSize - Size of pbTokenData.
+//
+// Returns:
+// SPNEGO_TOKEN* Success - Pointer to initialized SPNEGO_TOKEN struct
+// Failure - NULL
+//
+// Comments :
+// Allocates a SPNEGO_TOKEN data structure and initializes it. Based on
+// the value of ucCopyData, if non-zero, we copy the data into a buffer
+// we allocate in this function, otherwise, we copy the data pointer
+// direcly.
+//
+////////////////////////////////////////////////////////////////////////////
+
+SPNEGO_TOKEN* AllocEmptySpnegoToken( unsigned char ucCopyData, unsigned long ulFlags,
+ unsigned char * pbTokenData, unsigned long ulTokenSize )
+{
+ SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) calloc( 1, sizeof(SPNEGO_TOKEN) );
+
+ if ( NULL != pSpnegoToken )
+ {
+ // Set the token size
+ pSpnegoToken->nStructSize = SPNEGO_TOKEN_SIZE;
+
+ // Initialize the element array
+ InitSpnegoTokenElementArray( pSpnegoToken );
+
+ // Assign the flags value
+ pSpnegoToken->ulFlags = ulFlags;
+
+ //
+ // IF ucCopyData is TRUE, we will allocate a buffer and copy data into it.
+ // Otherwise, we will just copy the pointer and the length. This is so we
+ // can cut out additional allocations for performance reasons
+ //
+
+ if ( SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA == ucCopyData )
+ {
+ // Alloc the internal buffer. Cleanup on failure.
+ pSpnegoToken->pbBinaryData = (unsigned char*) calloc( ulTokenSize, sizeof(unsigned char) );
+
+ if ( NULL != pSpnegoToken->pbBinaryData )
+ {
+ // We must ALWAYS free this buffer
+ pSpnegoToken->ulFlags |= SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA;
+
+ // Copy the data locally
+ memcpy( pSpnegoToken->pbBinaryData, pbTokenData, ulTokenSize );
+ pSpnegoToken->ulBinaryDataLen = ulTokenSize;
+ }
+ else
+ {
+ free( pSpnegoToken );
+ pSpnegoToken = NULL;
+ }
+
+ } // IF ucCopyData
+ else
+ {
+ // Copy the pointer and the length directly - ulFlags will control whether or not
+ // we are allowed to free the value
+
+ pSpnegoToken->pbBinaryData = pbTokenData;
+ pSpnegoToken->ulBinaryDataLen = ulTokenSize;
+ }
+
+ }
+
+ return pSpnegoToken;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// FreeSpnegoToken
+//
+// Parameters:
+// [in] pSpnegoToken - Points to SPNEGO_TOKEN to free.
+//
+// Returns:
+// void
+//
+// Comments :
+// If non-NULL, interprets pSpnegoToken, freeing any internal allocations
+// and finally the actual structure.
+//
+////////////////////////////////////////////////////////////////////////////
+
+void FreeSpnegoToken( SPNEGO_TOKEN* pSpnegoToken )
+{
+ if ( NULL != pSpnegoToken )
+ {
+
+ // Cleanup internal allocation per the flags
+ if ( pSpnegoToken->ulFlags & SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA &&
+ NULL != pSpnegoToken->pbBinaryData )
+ {
+ free( pSpnegoToken->pbBinaryData );
+ pSpnegoToken->pbBinaryData = NULL;
+ }
+
+ free ( pSpnegoToken );
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// InitSpnegoTokenElementArray
+//
+// Parameters:
+// [in] pSpnegoToken - Points to SPNEGO_TOKEN structure.
+//
+// Returns:
+// void
+//
+// Comments :
+// Initializes the element array data member of a SPNEGO_TOKEN data
+// structure.
+//
+////////////////////////////////////////////////////////////////////////////
+
+void InitSpnegoTokenElementArray( SPNEGO_TOKEN* pSpnegoToken )
+{
+ int nCtr;
+
+ // Set the number of elemnts
+ pSpnegoToken->nNumElements = MAX_NUM_TOKEN_ELEMENTS;
+
+ //
+ // Initially, all elements are unavailable
+ //
+
+ for ( nCtr = 0; nCtr < MAX_NUM_TOKEN_ELEMENTS; nCtr++ )
+ {
+ // Set the element size as well
+ pSpnegoToken->aElementArray[ nCtr ].nStructSize = SPNEGO_ELEMENT_SIZE;
+ pSpnegoToken->aElementArray[ nCtr ].iElementPresent = SPNEGO_TOKEN_ELEMENT_UNAVAILABLE;
+ }
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// InitSpnegoTokenType
+//
+// Parameters:
+// [in] pSpnegoToken - Points to SPNEGO_TOKEN structure.
+// [out] pnTokenLength - Filled out with total token length
+// [out] pnRemainingTokenLength - Filled out with remaining length
+// after header is parsed
+// [out] ppbFirstElement - Filled out with pointer to first
+// element after header info.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Walks the underlying binary data for a SPNEGO_TOKEN data structure
+// and determines the type of the underlying token based on token header
+// information.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int InitSpnegoTokenType( SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength,
+ long* pnRemainingTokenLength, unsigned char** ppbFirstElement )
+{
+ int nReturn = SPNEGO_E_INVALID_TOKEN;
+ long nActualTokenLength = 0L;
+ long nBoundaryLength = pSpnegoToken->ulBinaryDataLen;
+ unsigned char* pbTokenData = pSpnegoToken->pbBinaryData;
+
+ //
+ // First byte MUST be either an APP_CONSTRUCT or the NEGTARG_TOKEN_TARG
+ //
+
+ if ( SPNEGO_NEGINIT_APP_CONSTRUCT == *pbTokenData )
+ {
+ // Validate the above token - this will tell us the actual length of the token
+ // per the encoding (minus the actual token bytes)
+ if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT, 0L, nBoundaryLength,
+ pnTokenLength, &nActualTokenLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+ // Initialize the remaining token length value. This will be used
+ // to tell the caller how much token there is left once we've parsed
+ // the header (they could calculate it from the other values, but this
+ // is a bit friendlier)
+ *pnRemainingTokenLength = *pnTokenLength;
+
+ // Make adjustments to next token
+ pbTokenData += nActualTokenLength;
+ nBoundaryLength -= nActualTokenLength;
+
+ // The next token should be an OID
+ if ( ( nReturn = ASNDerCheckOID( pbTokenData, spnego_mech_oid_Spnego, nBoundaryLength,
+ &nActualTokenLength ) ) == SPNEGO_E_SUCCESS )
+ {
+ // Make adjustments to next token
+ pbTokenData += nActualTokenLength;
+ nBoundaryLength -= nActualTokenLength;
+ *pnRemainingTokenLength -= nActualTokenLength;
+
+ // The next token should specify the NegTokenInit
+ if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER,
+ *pnRemainingTokenLength, nBoundaryLength, pnTokenLength,
+ &nActualTokenLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+ // Make adjustments to next token
+ pbTokenData += nActualTokenLength;
+ nBoundaryLength -= nActualTokenLength;
+ *pnRemainingTokenLength -= nActualTokenLength;
+
+ // The next token should specify the start of a sequence
+ if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
+ *pnRemainingTokenLength, nBoundaryLength, pnTokenLength,
+ &nActualTokenLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+ // NegTokenInit header is now checked out!
+
+ // Make adjustments to next token
+ *pnRemainingTokenLength -= nActualTokenLength;
+
+ // Store pointer to first element
+ *ppbFirstElement = pbTokenData + nActualTokenLength;
+ pSpnegoToken->ucTokenType = SPNEGO_TOKEN_INIT;
+ } // IF Check Sequence Token
+
+ } // IF Check NegTokenInit token
+
+
+ } // IF Check for SPNEGO OID
+
+
+ } // IF check app construct token
+
+ }
+ else if ( SPNEGO_NEGTARG_TOKEN_IDENTIFIER == *pbTokenData )
+ {
+
+ // The next token should specify the NegTokenInit
+ if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER,
+ *pnRemainingTokenLength, nBoundaryLength, pnTokenLength,
+ &nActualTokenLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+ // Initialize the remaining token length value. This will be used
+ // to tell the caller how much token there is left once we've parsed
+ // the header (they could calculate it from the other values, but this
+ // is a bit friendlier)
+ *pnRemainingTokenLength = *pnTokenLength;
+
+ // Make adjustments to next token
+ pbTokenData += nActualTokenLength;
+ nBoundaryLength -= nActualTokenLength;
+
+ // The next token should specify the start of a sequence
+ if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
+ *pnRemainingTokenLength, nBoundaryLength, pnTokenLength,
+ &nActualTokenLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+ // NegTokenInit header is now checked out!
+
+ // Make adjustments to next token
+ *pnRemainingTokenLength -= nActualTokenLength;
+
+ // Store pointer to first element
+ *ppbFirstElement = pbTokenData + nActualTokenLength;
+ pSpnegoToken->ucTokenType = SPNEGO_TOKEN_TARG;
+ } // IF Check Sequence Token
+
+ } // IF Check NegTokenInit token
+
+ } // ELSE IF it's a NegTokenTarg
+
+ return nReturn;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// GetSpnegoInitTokenMechList
+//
+// Parameters:
+// [in] pbTokenData - Points to binary MechList element
+// in NegTokenInit.
+// [in] nMechListLength - Length of the MechList
+// [out] pSpnegoElement - Filled out with MechList Element
+// data.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Checks that pbTokenData is pointing at something that at least
+// *looks* like a MechList and then fills out the supplied
+// SPNEGO_ELEMENT structure.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int GetSpnegoInitTokenMechList( unsigned char* pbTokenData, int nMechListLength,
+ SPNEGO_ELEMENT* pSpnegoElement )
+{
+ int nReturn = SPNEGO_E_INVALID_TOKEN;
+ long nLength = 0L;
+ long nActualTokenLength = 0L;
+
+ // Actual MechList is prepended by a Constructed Sequence Token
+ if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
+ nMechListLength, nMechListLength,
+ &nLength, &nActualTokenLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+ // Adjust for this token
+ nMechListLength -= nActualTokenLength;
+ pbTokenData += nActualTokenLength;
+
+ // Perform simple validation of the actual MechList (i.e. ensure that
+ // the OIDs in the MechList are reasonable).
+
+ if ( ( nReturn = ValidateMechList( pbTokenData, nLength ) ) == SPNEGO_E_SUCCESS )
+ {
+ // Initialize the element now
+ pSpnegoElement->eElementType = spnego_init_mechtypes;
+ pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE;
+ pSpnegoElement->type = SPNEGO_MECHLIST_TYPE;
+ pSpnegoElement->nDatalength = nLength;
+ pSpnegoElement->pbData = pbTokenData;
+ }
+
+ } // IF Check Token
+
+ return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// InitSpnegoTokenElementFromBasicType
+//
+// Parameters:
+// [in] pbTokenData - Points to binary element data in
+// a SPNEGO token.
+// [in] nElementLength - Length of the element
+// [in] ucExpectedType - Expected DER type.
+// [in] spnegoElementType - Which element is this?
+// [out] pSpnegoElement - Filled out with element data.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Checks that pbTokenData is pointing at the specified DER type. If so,
+// then we verify that lengths are proper and then fill out the
+// SPNEGO_ELEMENT data structure.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int InitSpnegoTokenElementFromBasicType( unsigned char* pbTokenData, int nElementLength,
+ unsigned char ucExpectedType,
+ SPNEGO_ELEMENT_TYPE spnegoElementType,
+ SPNEGO_ELEMENT* pSpnegoElement )
+{
+ int nReturn = SPNEGO_E_UNEXPECTED_TYPE;
+ long nLength = 0L;
+ long nActualTokenLength = 0L;
+
+ // The type BYTE must match our token data or something is badly wrong
+ if ( *pbTokenData == ucExpectedType )
+ {
+
+ // Check that we are pointing at the specified type
+ if ( ( nReturn = ASNDerCheckToken( pbTokenData, ucExpectedType,
+ nElementLength, nElementLength,
+ &nLength, &nActualTokenLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+ // Adjust for this token
+ nElementLength -= nActualTokenLength;
+ pbTokenData += nActualTokenLength;
+
+ // Initialize the element now
+ pSpnegoElement->eElementType = spnegoElementType;
+ pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE;
+ pSpnegoElement->type = ucExpectedType;
+ pSpnegoElement->nDatalength = nLength;
+ pSpnegoElement->pbData = pbTokenData;
+ }
+
+ } // IF type makes sense
+
+ return nReturn;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// InitSpnegoTokenElementFromOID
+//
+// Parameters:
+// [in] pbTokenData - Points to binary element data in
+// a SPNEGO token.
+// [in] nElementLength - Length of the element
+// [in] spnegoElementType - Which element is this?
+// [out] pSpnegoElement - Filled out with element data.
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Initializes a SpnegoElement from an OID - normally, this would have
+// used the Basic Type function above, but since we do binary compares
+// on the OIDs against the DER information as well as the OID, we need
+// to account for that.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int InitSpnegoTokenElementFromOID( unsigned char* pbTokenData, int nElementLength,
+ SPNEGO_ELEMENT_TYPE spnegoElementType,
+ SPNEGO_ELEMENT* pSpnegoElement )
+{
+ int nReturn = SPNEGO_E_UNEXPECTED_TYPE;
+ long nLength = 0L;
+ long nActualTokenLength = 0L;
+
+ // The type BYTE must match our token data or something is badly wrong
+ if ( *pbTokenData == OID )
+ {
+
+ // Check that we are pointing at an OID type
+ if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID,
+ nElementLength, nElementLength,
+ &nLength, &nActualTokenLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+ // Don't adjust any values for this function
+
+ // Initialize the element now
+ pSpnegoElement->eElementType = spnegoElementType;
+ pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE;
+ pSpnegoElement->type = OID;
+ pSpnegoElement->nDatalength = nElementLength;
+ pSpnegoElement->pbData = pbTokenData;
+ }
+
+ } // IF type makes sense
+
+ return nReturn;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// InitSpnegoTokenElements
+//
+// Parameters:
+// [in] pSpnegoToken - Points to SPNEGO_TOKEN struct
+// [in] pbTokenData - Points to initial binary element
+// data in a SPNEGO token.
+// [in] nRemainingTokenLength - Length remaining past header
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Interprets the data at pbTokenData based on the TokenType in
+// pSpnegoToken. Since some elements are optional (technically all are
+// but the token becomes quite useless if this is so), we check if
+// an element exists before filling out the element in the array.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData,
+ long nRemainingTokenLength )
+{
+ //
+ // The following arrays contain the token identifiers for the elements
+ // comprising the actual token. All values are optional, and there are
+ // no defaults.
+ //
+
+ static unsigned char abNegTokenInitElements[] =
+ { SPNEGO_NEGINIT_ELEMENT_MECHTYPES, SPNEGO_NEGINIT_ELEMENT_REQFLAGS,
+ SPNEGO_NEGINIT_ELEMENT_MECHTOKEN, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC };
+
+ static unsigned char abNegTokenTargElements[] =
+ { SPNEGO_NEGTARG_ELEMENT_NEGRESULT, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH,
+ SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC };
+
+ int nReturn = SPNEGO_E_SUCCESS;
+ int nCtr = 0L;
+ long nElementLength = 0L;
+ long nActualTokenLength = 0L;
+ unsigned char* pbElements = NULL;
+ unsigned char * ptok;
+ long tlen, elen, len;
+
+ // Point to the correct array
+ switch( pSpnegoToken->ucTokenType )
+ {
+ case SPNEGO_TOKEN_INIT:
+ {
+ pbElements = abNegTokenInitElements;
+ }
+ break;
+
+ case SPNEGO_TOKEN_TARG:
+ {
+ pbElements = abNegTokenTargElements;
+ }
+ break;
+
+ } // SWITCH tokentype
+
+ //
+ // Enumerate the element arrays and look for the tokens at our current location
+ //
+
+ for ( nCtr = 0L;
+ SPNEGO_E_SUCCESS == nReturn &&
+ nCtr < MAX_NUM_TOKEN_ELEMENTS &&
+ nRemainingTokenLength > 0L;
+ nCtr++ )
+ {
+
+ // Check if the token exists
+ if ( ( nReturn = ASNDerCheckToken( pbTokenData, pbElements[nCtr],
+ 0L, nRemainingTokenLength,
+ &nElementLength, &nActualTokenLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+
+ // Token data should skip over the sequence token and then
+ // call the appropriate function to initialize the element
+ pbTokenData += nActualTokenLength;
+
+ // Lengths in the elements should NOT go beyond the element
+ // length
+
+ // Different tokens mean different elements
+ if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
+ {
+
+ // Handle each element as appropriate
+ switch( pbElements[nCtr] )
+ {
+
+ case SPNEGO_NEGINIT_ELEMENT_MECHTYPES:
+ {
+ //
+ // This is a Mech List that specifies which OIDs the
+ // originator of the Init Token supports.
+ //
+
+ nReturn = GetSpnegoInitTokenMechList( pbTokenData, nElementLength,
+ &pSpnegoToken->aElementArray[nCtr] );
+
+ }
+ break;
+
+ case SPNEGO_NEGINIT_ELEMENT_REQFLAGS:
+ {
+ //
+ // This is a BITSTRING which specifies the flags that the receiver
+ // pass to the gss_accept_sec_context() function.
+ //
+
+ nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
+ BITSTRING, spnego_init_reqFlags,
+ &pSpnegoToken->aElementArray[nCtr] );
+ }
+ break;
+
+ case SPNEGO_NEGINIT_ELEMENT_MECHTOKEN:
+ {
+ //
+ // This is an OCTETSTRING which contains a GSSAPI token corresponding
+ // to the first OID in the MechList.
+ //
+
+ nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
+ OCTETSTRING, spnego_init_mechToken,
+ &pSpnegoToken->aElementArray[nCtr] );
+ }
+ break;
+
+ case SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC:
+ {
+ //
+ // This is an OCTETSTRING which contains a message integrity BLOB.
+ //
+
+ nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
+ OCTETSTRING, spnego_init_mechListMIC,
+ &pSpnegoToken->aElementArray[nCtr] );
+ /*
+ * don't believe everything you read in RFCs (and MS
+ * sample code)... win2k is sending not an octet string,
+ * but a "general string", wrapped in a sequence.
+ */
+ if (nReturn != SPNEGO_E_UNEXPECTED_TYPE)
+ break;
+ ptok = pbTokenData;
+ elen = nElementLength;
+ if ((nReturn = ASNDerCheckToken(ptok, SPNEGO_CONSTRUCTED_SEQUENCE, elen, elen, &len, &tlen)) != SPNEGO_E_SUCCESS)
+ break;
+ elen -= tlen;
+ ptok += tlen;
+
+ if ((nReturn = ASNDerCheckToken(ptok, SEQ_ELM(0), elen, elen, &len, &tlen)) != SPNEGO_E_SUCCESS)
+ break;
+ elen -= tlen;
+ ptok += tlen;
+ nReturn = InitSpnegoTokenElementFromBasicType(ptok, elen, GENERALSTR, spnego_init_mechListMIC, &pSpnegoToken->aElementArray[nCtr]);
+ }
+ break;
+
+ } // SWITCH Element
+ }
+ else
+ {
+
+ switch( pbElements[nCtr] )
+ {
+
+ case SPNEGO_NEGTARG_ELEMENT_NEGRESULT:
+ {
+ //
+ // This is an ENUMERATION which specifies result of the last GSS
+ // token negotiation call.
+ //
+
+ nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
+ ENUMERATED, spnego_targ_negResult,
+ &pSpnegoToken->aElementArray[nCtr] );
+ }
+ break;
+
+ case SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH:
+ {
+ //
+ // This is an OID which specifies a supported mechanism.
+ //
+
+ nReturn = InitSpnegoTokenElementFromOID( pbTokenData, nElementLength,
+ spnego_targ_mechListMIC,
+ &pSpnegoToken->aElementArray[nCtr] );
+ }
+ break;
+
+ case SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN:
+ {
+ //
+ // This is an OCTETSTRING which specifies results of the last GSS
+ // token negotiation call.
+ //
+
+ nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
+ OCTETSTRING, spnego_targ_responseToken,
+ &pSpnegoToken->aElementArray[nCtr] );
+ }
+ break;
+
+ case SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC:
+ {
+ //
+ // This is an OCTETSTRING which specifies a message integrity BLOB.
+ //
+
+ nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
+ OCTETSTRING, spnego_targ_mechListMIC,
+ &pSpnegoToken->aElementArray[nCtr] );
+ }
+ break;
+
+ } // SWITCH Element
+
+ } // ELSE !NegTokenInit
+
+ // Account for the entire token and following data
+ nRemainingTokenLength -= ( nActualTokenLength + nElementLength );
+
+ // Token data should skip past the element length now
+ pbTokenData += nElementLength;
+
+ } // IF Token found
+ else if ( SPNEGO_E_TOKEN_NOT_FOUND == nReturn )
+ {
+ // For now, this is a benign error (remember, all elements are optional, so
+ // if we don't find one, it's okay).
+
+ nReturn = SPNEGO_E_SUCCESS;
+ }
+
+ } // FOR enum elements
+
+ //
+ // We should always run down to 0 remaining bytes in the token. If not, we've got
+ // a bad token.
+ //
+
+ if ( SPNEGO_E_SUCCESS == nReturn && nRemainingTokenLength != 0L )
+ {
+ nReturn = SPNEGO_E_INVALID_TOKEN;
+ }
+
+ return nReturn;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// FindMechOIDInMechList
+//
+// Parameters:
+// [in] pSpnegoElement - SPNEGO_ELEMENT for MechList
+// [in] MechOID - OID we're looking for.
+// [out] piMechTypeIndex - Index in the list where OID was
+// found
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Walks the MechList for MechOID. When it is found, the index in the
+// list is written to piMechTypeIndex.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID,
+ int * piMechTypeIndex )
+{
+ int nReturn = SPNEGO_E_NOT_FOUND;
+ int nCtr = 0;
+ long nLength = 0L;
+ long nBoundaryLength = pSpnegoElement->nDatalength;
+ unsigned char* pbMechListData = pSpnegoElement->pbData;
+
+ while( SPNEGO_E_SUCCESS != nReturn && nBoundaryLength > 0L )
+ {
+
+ // Use the helper function to check the OID
+ if ( ( nReturn = ASNDerCheckOID( pbMechListData, MechOID, nBoundaryLength, &nLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+ *piMechTypeIndex = nCtr;
+ }
+
+ // Adjust for the current OID
+ pbMechListData += nLength;
+ nBoundaryLength -= nLength;
+ nCtr++;
+
+ } // WHILE enuming OIDs
+
+ return nReturn;
+
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// ValidateMechList
+//
+// Parameters:
+// [in] pbMechListData - Pointer to binary MechList data
+// [in] nBoundaryLength - Length we must not exceed
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Checks the data at pbMechListData to see if it looks like a MechList.
+// As part of this, we walk the list and ensure that none of the OIDs
+// have a length that takes us outside of nBoundaryLength.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength )
+{
+ int nReturn = SPNEGO_E_SUCCESS;
+ long nLength = 0L;
+ long nTokenLength = 0L;
+
+ while( SPNEGO_E_SUCCESS == nReturn && nBoundaryLength > 0L )
+ {
+ // Verify that we have something that at least *looks* like an OID - in other
+ // words it has an OID identifier and specifies a length that doesn't go beyond
+ // the size of the list.
+ nReturn = ASNDerCheckToken( pbMechListData, OID, 0L, nBoundaryLength,
+ &nLength, &nTokenLength );
+
+ // Adjust for the current OID
+ pbMechListData += ( nLength + nTokenLength );
+ nBoundaryLength -= ( nLength + nTokenLength );
+
+ } // WHILE enuming OIDs
+
+ return nReturn;
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// IsValidMechOid
+//
+// Parameters:
+// [in] mechOid - mechOID id enumeration
+//
+// Returns:
+// int Success - 1
+// Failure - 0
+//
+// Comments :
+// Checks for a valid mechOid value.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int IsValidMechOid( SPNEGO_MECH_OID mechOid )
+{
+ return ( mechOid >= spnego_mech_oid_Kerberos_V5_Legacy &&
+ mechOid <= spnego_mech_oid_Spnego );
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// IsValidContextFlags
+//
+// Parameters:
+// [in] ucContextFlags - ContextFlags value
+//
+// Returns:
+// int Success - 1
+// Failure - 0
+//
+// Comments :
+// Checks for a valid ContextFlags value.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int IsValidContextFlags( unsigned char ucContextFlags )
+{
+ // Mask out our valid bits. If there is anything leftover, this
+ // is not a valid value for Context Flags
+ return ( ( ucContextFlags & ~SPNEGO_NEGINIT_CONTEXT_MASK ) == 0 );
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// IsValidNegResult
+//
+// Parameters:
+// [in] negResult - NegResult value
+//
+// Returns:
+// int Success - 1
+// Failure - 0
+//
+// Comments :
+// Checks for a valid NegResult value.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int IsValidNegResult( SPNEGO_NEGRESULT negResult )
+{
+ return ( negResult >= spnego_negresult_success &&
+ negResult <= spnego_negresult_rejected );
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// IsValidSpnegoToken
+//
+// Parameters:
+// [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
+//
+// Returns:
+// int Success - 1
+// Failure - 0
+//
+// Comments :
+// Performs simple heuristic on location pointed to by pSpnegoToken.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int IsValidSpnegoToken( SPNEGO_TOKEN* pSpnegoToken )
+{
+ int nReturn = 0;
+
+ // Parameter should be non-NULL
+ if ( NULL != pSpnegoToken )
+ {
+ // Length should be at least the size defined in the header
+ if ( pSpnegoToken->nStructSize >= SPNEGO_TOKEN_SIZE )
+ {
+ // Number of elements should be >= our maximum - if it's greater, that's
+ // okay, since we'll only be accessing the elements up to MAX_NUM_TOKEN_ELEMENTS
+ if ( pSpnegoToken->nNumElements >= MAX_NUM_TOKEN_ELEMENTS )
+ {
+ // Check for proper token type
+ if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ||
+ SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType )
+ {
+ nReturn = 1;
+ }
+ }
+
+ } // IF struct size makes sense
+
+ } // IF non-NULL spnego Token
+
+ return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// IsValidSpnegoElement
+//
+// Parameters:
+// [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
+// [in] spnegoElement - spnegoElement Type from enumeration
+//
+// Returns:
+// int Success - 1
+// Failure - 0
+//
+// Comments :
+// Checks that spnegoElement has a valid value and is appropriate for
+// the SPNEGO token encapsulated by pSpnegoToken.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int IsValidSpnegoElement( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement )
+{
+ int nReturn = 0;
+
+ // Check boundaries
+ if ( spnegoElement > spnego_element_min &&
+ spnegoElement < spnego_element_max )
+ {
+
+ // Check for appropriateness to token type
+ if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
+ {
+ nReturn = ( spnegoElement >= spnego_init_mechtypes &&
+ spnegoElement <= spnego_init_mechListMIC );
+ }
+ else
+ {
+ nReturn = ( spnegoElement >= spnego_targ_negResult &&
+ spnegoElement <= spnego_targ_mechListMIC );
+ }
+
+ } // IF boundary conditions are met
+
+ return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// CalculateElementArrayIndex
+//
+// Parameters:
+// [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure
+// [in] spnegoElement - spnegoElement Type from enumeration
+//
+// Returns:
+// int index in the SPNEGO_TOKEN element array that the element can
+// can be found
+//
+// Comments :
+// Based on the Token Type, calculates the index in the element array
+// at which the specified element can be found.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int CalculateElementArrayIndex( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement )
+{
+ int nReturn = 0;
+
+ // Offset is difference between value and initial element identifier
+ // (these differ based on ucTokenType)
+
+ if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
+ {
+ nReturn = spnegoElement - spnego_init_mechtypes;
+ }
+ else
+ {
+ nReturn = spnegoElement - spnego_targ_negResult;
+ }
+
+ return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+// InitTokenFromBinary
+//
+// Parameters:
+// [in] ucCopyData - Flag indicating if data should be copied
+// [in] ulFlags - Flags value for structure
+// [in] pnTokenData - Binary Token Data
+// [in] ulLength - Length of the data
+// [out] ppSpnegoToken - Pointer to call allocated SPNEGO Token
+// data structure
+//
+// Returns:
+// int Success - SPNEGO_E_SUCCESS
+// Failure - SPNEGO API Error code
+//
+// Comments :
+// Allocates a SPNEGO_TOKEN data structure and fills it out as
+// appropriate based in the flags passed into the function.
+//
+////////////////////////////////////////////////////////////////////////////
+
+
+// Initializes SPNEGO_TOKEN structure from DER encoded binary data
+int InitTokenFromBinary( unsigned char ucCopyData, unsigned long ulFlags,
+ unsigned char* pbTokenData, unsigned long ulLength,
+ SPNEGO_TOKEN** ppSpnegoToken )
+{
+ int nReturn = SPNEGO_E_INVALID_PARAMETER;
+ SPNEGO_TOKEN* pSpnegoToken = NULL;
+ unsigned char* pbFirstElement = NULL;
+ long nTokenLength = 0L;
+ long nRemainingTokenLength = 0L;
+
+ // Basic Parameter Validation
+
+ if ( NULL != pbTokenData &&
+ NULL != ppSpnegoToken &&
+ 0L != ulLength )
+ {
+
+ //
+ // Allocate the empty token, then initialize the data structure.
+ //
+
+ pSpnegoToken = AllocEmptySpnegoToken( ucCopyData, ulFlags, pbTokenData, ulLength );
+
+ if ( NULL != pSpnegoToken )
+ {
+
+ // Copy the binary data locally
+
+
+ // Initialize the token type
+ if ( ( nReturn = InitSpnegoTokenType( pSpnegoToken, &nTokenLength,
+ &nRemainingTokenLength, &pbFirstElement ) )
+ == SPNEGO_E_SUCCESS )
+ {
+
+ // Initialize the element array
+ if ( ( nReturn = InitSpnegoTokenElements( pSpnegoToken, pbFirstElement,
+ nRemainingTokenLength ) )
+ == SPNEGO_E_SUCCESS )
+ {
+ *ppSpnegoToken = pSpnegoToken;
+ }
+
+ } // IF Init Token Type
+
+ // Cleanup on error condition
+ if ( SPNEGO_E_SUCCESS != nReturn )
+ {
+ spnegoFreeData( pSpnegoToken );
+ }
+
+ }
+ else
+ {
+ nReturn = SPNEGO_E_OUT_OF_MEMORY;
+ }
+
+ } // IF Valid parameters
+
+
+ return nReturn;
+}
diff --git a/usr/src/lib/libsmbfs/smb/spnegoparse.h b/usr/src/lib/libsmbfs/smb/spnegoparse.h
new file mode 100644
index 0000000000..b874dc453d
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/spnegoparse.h
@@ -0,0 +1,170 @@
+// Copyright (C) 2002 Microsoft Corporation
+// All rights reserved.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+// OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Date - 10/08/2002
+// Author - Sanj Surati
+
+/////////////////////////////////////////////////////////////
+//
+// SPNEGOPARSE.H
+//
+// SPNEGO Token Parser Header File
+//
+// Contains the definitions required to properly parse a
+// SPNEGO token using ASN.1 DER helpers.
+//
+/////////////////////////////////////////////////////////////
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifndef __SPNEGOPARSE_H__
+#define __SPNEGOPARSE_H__
+
+// C++ Specific
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+// Indicates if we copy data when creating a SPNEGO_TOKEN structure or not
+#define SPNEGO_TOKEN_INTERNAL_COPYPTR 0
+#define SPNEGO_TOKEN_INTERNAL_COPYDATA 0x1
+
+// Internal flag dictates whether or not we will free the binary data when
+// the SPNEG_TOKEN structure is destroyed
+#define SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA 0x1
+
+ //
+// Each SPNEGO Token Type can be broken down into a
+// maximum of 4 separate elements.
+//
+
+#define MAX_NUM_TOKEN_ELEMENTS 4
+
+//
+// Element offsets in the array
+//
+
+// INIT elements
+#define SPNEGO_INIT_MECHTYPES_ELEMENT 0
+#define SPNEGO_INIT_REQFLAGS_ELEMENT 1
+#define SPNEGO_INIT_MECHTOKEN_ELEMENT 2
+#define SPNEGO_INIT_MECHLISTMIC_ELEMENT 3
+
+// Response elements
+#define SPNEGO_TARG_NEGRESULT_ELEMENT 0
+#define SPNEGO_TARG_SUPPMECH_ELEMENT 1
+#define SPNEGO_TARG_RESPTOKEN_ELEMENT 2
+#define SPNEGO_TARG_MECHLISTMIC_ELEMENT 3
+
+//
+// Defines an individual SPNEGO Token Element.
+//
+
+typedef struct SpnegoElement
+{
+ size_t nStructSize; // Size of the element structure
+ int iElementPresent; // Is the field present? Must be either
+ // SPNEGO_TOKEN_ELEMENT_UNAVAILABLE or
+ // SPNEGO_TOKEN_ELEMENT_AVAILABLE
+
+ SPNEGO_ELEMENT_TYPE eElementType; // The Element Type
+
+ unsigned char type; // Data Type
+
+ unsigned char* pbData; // Points to actual Data
+
+ unsigned long nDatalength; // Actual Data Length
+
+} SPNEGO_ELEMENT;
+
+// Structure size in case we later choose to extend the structure
+#define SPNEGO_ELEMENT_SIZE sizeof(SPNEGO_ELEMENT)
+
+//
+// Packages a SPNEGO Token Encoding. There are two types of
+// encodings: NegTokenInit and NegTokenTarg. Each encoding can
+// contain up to four distinct, optional elements.
+//
+
+typedef struct SpnegoToken
+{
+ size_t nStructSize; // Size of the Token structure
+ unsigned long ulFlags; // Internal Structure Flags - Reserved!
+ int ucTokenType; // Token Type - Must be
+ // SPNEGO_TOKEN_INIT or
+ // SPNEGO_TOKEN_TARG
+
+ unsigned char* pbBinaryData; // Points to binary token data
+
+ unsigned long ulBinaryDataLen; // Length of the actual binary data
+ int nNumElements; // Number of elements
+ SPNEGO_ELEMENT aElementArray [MAX_NUM_TOKEN_ELEMENTS]; // Holds the elements for the token
+} SPNEGO_TOKEN;
+
+// Structure size in case we later choose to extend the structure
+#define SPNEGO_TOKEN_SIZE sizeof(SPNEGO_TOKEN)
+
+//
+// Function definitions
+//
+
+SPNEGO_TOKEN* AllocEmptySpnegoToken( unsigned char ucCopyData, unsigned long ulFlags,
+ unsigned char * pbTokenData, unsigned long ulTokenSize );
+void FreeSpnegoToken( SPNEGO_TOKEN* pSpnegoToken );
+void InitSpnegoTokenElementArray( SPNEGO_TOKEN* pSpnegoToken );
+int InitSpnegoTokenType( SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength,
+ long* pnRemainingTokenLength, unsigned char** ppbFirstElement );
+int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData,
+ long nRemainingTokenLength );
+int GetSpnegoInitTokenMechList( unsigned char* pbTokenData, int nMechListLength,
+ SPNEGO_ELEMENT* pSpnegoElement );
+int InitSpnegoTokenElementFromBasicType( unsigned char* pbTokenData, int nElementLength,
+ unsigned char ucExpectedType,
+ SPNEGO_ELEMENT_TYPE spnegoElementType,
+ SPNEGO_ELEMENT* pSpnegoElement );
+int InitSpnegoTokenElementFromOID( unsigned char* pbTokenData, int nElementLength,
+ SPNEGO_ELEMENT_TYPE spnegoElementType,
+ SPNEGO_ELEMENT* pSpnegoElement );
+int FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID,
+ int * piMechTypeIndex );
+int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength );
+int CalculateMinSpnegoInitTokenSize( long nMechTokenLength, long nMechListMICLength,
+ SPNEGO_MECH_OID mechOid, int nReqFlagsAvailable,
+ long* plTokenSize, long* plInternalLength );
+int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType, SPNEGO_NEGRESULT spnegoNegResult,
+ long nMechTokenLen,
+ long nMechTokenMIC, long* pnTokenSize,
+ long* pnInternalTokenLength );
+int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType,
+ unsigned char ucContextFlags, unsigned char* pbMechToken,
+ unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
+ unsigned long ulMechListMICLen, unsigned char* pbTokenData,
+ long nTokenLength, long nInternalTokenLength );
+int CreateSpnegoTargToken( SPNEGO_MECH_OID MechType,
+ SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken,
+ unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
+ unsigned long ulMechListMICLen, unsigned char* pbTokenData,
+ long nTokenLength, long nInternalTokenLength );
+int IsValidMechOid( SPNEGO_MECH_OID mechOid );
+int IsValidContextFlags( unsigned char ucContextFlags );
+int IsValidNegResult( SPNEGO_NEGRESULT negResult );
+int IsValidSpnegoToken( SPNEGO_TOKEN* pSpnegoToken );
+int IsValidSpnegoElement( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement );
+int CalculateElementArrayIndex( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement );
+int InitTokenFromBinary( unsigned char ucCopyData, unsigned long ulFlags,
+ unsigned char* pbTokenData, unsigned long ulLength,
+ SPNEGO_TOKEN** ppSpnegoToken );
+
+ // C++ Specific
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/usr/src/lib/libsmbfs/smb/subr.c b/usr/src/lib/libsmbfs/smb/subr.c
new file mode 100644
index 0000000000..46842d730f
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/subr.c
@@ -0,0 +1,394 @@
+/*
+ * 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.
+ *
+ * $Id: subr.c,v 1.19 2005/02/09 00:23:45 lindak Exp $
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <sys/debug.h>
+
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sysexits.h>
+#include <libintl.h>
+
+#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;
+
+static int smblib_initialized;
+
+struct rcfile *smb_rc;
+
+int
+smb_lib_init(void)
+{
+ int error;
+
+ if (smblib_initialized)
+ return (0);
+ if ((error = nls_setlocale("")) != 0) {
+ fprintf(stdout, dgettext(TEXT_DOMAIN,
+ "%s: can't initialise locale\n"), __progname);
+ return (error);
+ }
+ smblib_initialized++;
+ return (0);
+}
+
+/*
+ * Private version of strerror(3C) that
+ * knows our special error codes.
+ */
+char *
+smb_strerror(int err)
+{
+ char *msg;
+
+ switch (err) {
+ case EBADRPC:
+ msg = dgettext(TEXT_DOMAIN,
+ "remote call failed");
+ break;
+ case EAUTH:
+ msg = dgettext(TEXT_DOMAIN,
+ "authentication failed");
+ break;
+ default:
+ msg = strerror(err);
+ break;
+ }
+
+ return (msg);
+}
+
+/*
+ * Print a (descriptive) error message
+ * error values:
+ * 0 - no specific error code available;
+ * 1..32767 - system error
+ */
+void
+smb_error(const char *fmt, int error, ...) {
+ va_list ap;
+ const char *cp;
+ int errtype;
+
+ fprintf(stderr, "%s: ", __progname);
+ va_start(ap, error);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ if (error == -1) {
+ error = errno;
+ errtype = SMB_SYS_ERROR;
+ } else {
+ errtype = error & SMB_ERRTYPE_MASK;
+ error &= ~SMB_ERRTYPE_MASK;
+ }
+ switch (errtype) {
+ case SMB_SYS_ERROR:
+ if (error)
+ fprintf(stderr, ": syserr = %s\n", smb_strerror(error));
+ else
+ fprintf(stderr, "\n");
+ break;
+ case SMB_RAP_ERROR:
+ fprintf(stderr, ": raperr = %d (0x%04x)\n", error, error);
+ break;
+ case SMB_NB_ERROR:
+ cp = nb_strerror(error);
+ if (cp == NULL)
+ fprintf(stderr, ": nberr = unknown (0x%04x)\n", error);
+ else
+ fprintf(stderr, ": nberr = %s\n", cp);
+ break;
+ default:
+ fprintf(stderr, "\n");
+ }
+}
+
+char *
+smb_printb(char *dest, int flags, const struct smb_bitname *bnp) {
+ int first = 1;
+
+ strcpy(dest, "<");
+ for (; bnp->bn_bit; bnp++) {
+ if (flags & bnp->bn_bit) {
+ strcat(dest, bnp->bn_name);
+ first = 0;
+ }
+ if (!first && (flags & bnp[1].bn_bit))
+ strcat(dest, "|");
+ }
+ strcat(dest, ">");
+ 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
+ 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
+ dump_props("after reading user settings");
+#endif
+ if (smb_rc == NULL) {
+ return (ENOENT);
+ }
+ return (0);
+}
+
+void
+smb_simplecrypt(char *dst, const char *src)
+{
+ int ch, pos;
+
+ *dst++ = '$';
+ *dst++ = '$';
+ *dst++ = '1';
+ pos = 27;
+ while (*src) {
+ ch = *src++;
+ if (isascii(ch))
+ ch = (isupper(ch) ? ('A' + (ch - 'A' + 13) % 26) :
+ islower(ch) ? ('a' + (ch - 'a' + 13) % 26) : ch);
+ ch ^= pos;
+ pos += 13;
+ sprintf(dst, "%02x", ch);
+ dst += 2;
+ }
+ *dst = 0;
+}
+
+int
+smb_simpledecrypt(char *dst, const char *src)
+{
+ char *ep, hexval[3];
+ int len, ch, pos;
+
+ if (strncmp(src, "$$1", 3) != 0)
+ return (EINVAL);
+ src += 3;
+ len = strlen(src);
+ if (len & 1)
+ return (EINVAL);
+ len /= 2;
+ hexval[2] = 0;
+ pos = 27;
+ while (len--) {
+ hexval[0] = *src++;
+ hexval[1] = *src++;
+ ch = strtoul(hexval, &ep, 16);
+ if (*ep != 0)
+ return (EINVAL);
+ ch ^= pos;
+ pos += 13;
+ if (isascii(ch))
+ ch = (isupper(ch) ? ('A' + (ch - 'A' + 13) % 26) :
+ islower(ch) ? ('a' + (ch - 'a' + 13) % 26) : ch);
+ *dst++ = ch;
+ }
+ *dst = 0;
+ return (0);
+}
+
+
+static int
+safe_execv(char *args[])
+{
+ int pid;
+ int status;
+
+ pid = fork();
+ if (pid == 0) {
+ (void) execv(args[0], args);
+ /* Changed from errx() to fprintf(stderr) -Pavan */
+ fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "%s: execv %s failed, %s\n"), __progname,
+ args[0], smb_strerror(errno));
+ }
+ if (pid == -1) {
+ fprintf(stderr, dgettext(TEXT_DOMAIN, "%s: fork failed, %s\n"),
+ __progname, smb_strerror(errno));
+ return (1);
+ }
+ if (wait4(pid, &status, 0, NULL) != pid) {
+ fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "%s: BUG executing %s command\n"), __progname, args[0]);
+ return (1);
+ } else if (!WIFEXITED(status)) {
+ fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "%s: %s command aborted by signal %d\n"),
+ __progname, args[0], WTERMSIG(status));
+ return (1);
+ } else if (WEXITSTATUS(status)) {
+ fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "%s: %s command failed, exit status %d: %s\n"),
+ __progname, args[0], WEXITSTATUS(status),
+ smb_strerror(WEXITSTATUS(status)));
+ return (1);
+ }
+ return (0);
+}
+
+
+void
+dropsuid()
+{
+ /* drop setuid root privs asap */
+ eff_uid = geteuid();
+ real_uid = getuid();
+ seteuid(real_uid);
+}
+
+
+#define KEXTLOAD_COMMAND "/sbin/kextload"
+#define FS_KEXT_DIR "/System/Library/Extensions/smbfs.kext"
+#define FULL_KEXTNAME "com.apple.filesystems.smbfs"
+
+
+int
+loadsmbvfs()
+{
+ char *kextargs[] = {KEXTLOAD_COMMAND, FS_KEXT_DIR, NULL};
+ int error = 0;
+
+ /*
+ * temporarily revert to root (required for kextload)
+ */
+ seteuid(eff_uid);
+ error = safe_execv(kextargs);
+ seteuid(real_uid); /* and back to real user */
+ return (error);
+}
+
+#undef __progname
+
+char *__progname = NULL;
+
+char *
+smb_getprogname()
+{
+ char *p;
+
+ if (__progname == NULL) {
+ __progname = (char *)getexecname();
+ if ((p = strrchr(__progname, '/')) != 0)
+ __progname = p + 1;
+ }
+ return (__progname);
+}
diff --git a/usr/src/lib/libsmbfs/smb/ui-sun.c b/usr/src/lib/libsmbfs/smb/ui-sun.c
new file mode 100644
index 0000000000..7512d2c964
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/ui-sun.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @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.)
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <ctype.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/smb_keychain.h>
+
+#define MAXLINE 127
+#define MAXPASSWD 256 /* from libc:getpass */
+
+static void
+smb_tty_prompt(char *prmpt,
+ char *buf, size_t buflen)
+{
+ char temp[MAXLINE+1];
+ char *cp;
+ int ch;
+
+ memset(temp, 0, sizeof (temp));
+
+ fprintf(stderr, "%s", prmpt);
+ cp = temp;
+ while ((ch = getc(stdin)) != EOF) {
+ if (ch == '\n' || ch == '\r')
+ break;
+ if (isspace(ch) || iscntrl(ch))
+ continue;
+ *cp++ = ch;
+ if (cp == &temp[MAXLINE])
+ break;
+ }
+
+ /* If input empty, accept default. */
+ if (cp == temp)
+ return;
+
+ /* Use input as new value. */
+ strncpy(buf, temp, buflen);
+}
+
+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)
+{
+ char *npw;
+ int error, i, kcask, kcerr;
+
+ if (ctx->ct_flags & SMBCF_KCFOUND || ctx->ct_flags & SMBCF_KCBAD) {
+ ctx->ct_flags &= ~SMBCF_KCFOUND;
+ } else {
+ ctx->ct_flags &= ~(SMBCF_KCFOUND | SMBCF_KCDOMAIN);
+
+ /*
+ * 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);
+ }
+
+ /*
+ * 2nd: try lookup using domain name
+ */
+ 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);
+ }
+
+ /*
+ * XXX: Ask the user for help, possibly via
+ * GNOME dbus or some such... (todo).
+ */
+ smb_error(dgettext(TEXT_DOMAIN,
+ "Cannot prompt for a password when input is redirected."), 0);
+
+ return (ENOTTY);
+}
+
+int
+smb_browse(struct smb_ctx *ctx, int anon)
+{
+ /*
+ * Let user pick a share.
+ * Not supported.
+ */
+ return (EINTR);
+}
diff --git a/usr/src/lib/libsmbfs/sparc/Makefile b/usr/src/lib/libsmbfs/sparc/Makefile
new file mode 100644
index 0000000000..23b74c3928
--- /dev/null
+++ b/usr/src/lib/libsmbfs/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libsmbfs/sparcv9/Makefile b/usr/src/lib/libsmbfs/sparcv9/Makefile
new file mode 100644
index 0000000000..7443ee1806
--- /dev/null
+++ b/usr/src/lib/libsmbfs/sparcv9/Makefile
@@ -0,0 +1,31 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)