summaryrefslogtreecommitdiffstats
path: root/contrib/smbfs/lib/smb
diff options
context:
space:
mode:
authorsheldonh <sheldonh@FreeBSD.org>2001-12-14 11:06:03 +0000
committersheldonh <sheldonh@FreeBSD.org>2001-12-14 11:06:03 +0000
commit4e260b134ff188548ec2c8a16a37570a4abf1257 (patch)
tree672d7786f89ed3b67f221098cb86cf0bc53ad5e3 /contrib/smbfs/lib/smb
downloadFreeBSD-src-4e260b134ff188548ec2c8a16a37570a4abf1257.zip
FreeBSD-src-4e260b134ff188548ec2c8a16a37570a4abf1257.tar.gz
Import smbfs-1.4.1.
This is Boris Popov's SMB/CIFS file system implementation for FreeBSD. Obtained from: Boris Popov via ftp://ftp.butya.kz/pub/smbfs/
Diffstat (limited to 'contrib/smbfs/lib/smb')
-rw-r--r--contrib/smbfs/lib/smb/Makefile50
-rw-r--r--contrib/smbfs/lib/smb/cfopt.c123
-rw-r--r--contrib/smbfs/lib/smb/ctx.c773
-rw-r--r--contrib/smbfs/lib/smb/file.c80
-rw-r--r--contrib/smbfs/lib/smb/kiconv.c61
-rw-r--r--contrib/smbfs/lib/smb/mbuf.c467
-rw-r--r--contrib/smbfs/lib/smb/nb.c191
-rw-r--r--contrib/smbfs/lib/smb/nb_name.c198
-rw-r--r--contrib/smbfs/lib/smb/nb_net.c201
-rw-r--r--contrib/smbfs/lib/smb/nbns_rq.c380
-rw-r--r--contrib/smbfs/lib/smb/nls.c214
-rw-r--r--contrib/smbfs/lib/smb/print.c97
-rw-r--r--contrib/smbfs/lib/smb/rap.c404
-rw-r--r--contrib/smbfs/lib/smb/rcfile.c499
-rw-r--r--contrib/smbfs/lib/smb/rcfile_priv.h20
-rw-r--r--contrib/smbfs/lib/smb/rq.c179
-rw-r--r--contrib/smbfs/lib/smb/subr.c243
17 files changed, 4180 insertions, 0 deletions
diff --git a/contrib/smbfs/lib/smb/Makefile b/contrib/smbfs/lib/smb/Makefile
new file mode 100644
index 0000000..9b76203
--- /dev/null
+++ b/contrib/smbfs/lib/smb/Makefile
@@ -0,0 +1,50 @@
+# $Id: Makefile,v 1.12 2001/04/16 14:27:35 bp Exp $
+
+LIB= smb
+
+NOPROFILE= yes
+
+#SHLIB_MAJOR= 1
+#SHLIB_MINOR= 0
+
+NOMAN=
+
+SRCS= rcfile.c ctx.c cfopt.c subr.c nls.c rap.c mbuf.c rq.c file.c \
+ print.c \
+ kiconv.c \
+ nb.c nb_name.c nb_net.c nbns_rq.c
+
+.ifmake !clean && !cleandepend
+.if !defined(PREFIX)
+.include "../../config.int"
+.endif
+.endif
+
+DESTDIR=${PREFIX}/
+LIBDIR=lib
+
+.if !defined(USE_SHAREDLIBS)
+NOPIC= yes
+.endif
+
+install-src: install-lib
+
+deinstall-src: deinstall-lib
+
+.include <bsd.lib.mk>
+
+install-lib: afterinstall _SUBDIR
+.if !defined(NOMAN)
+afterinstall: realinstall maninstall
+.else
+afterinstall: realinstall
+.endif
+
+deinstall-lib:
+ rm -f ${DESTDIR}/${LIBDIR}/lib${LIB}.a
+.if defined(SHLIB_NAME)
+ rm -f ${DESTDIR}/${SHLIBDIR}/${SHLIB_NAME}
+.endif
+.if defined(SHLIB_LINK)
+ rm -f ${DESTDIR}/${SHLIBDIR}/${SHLIB_LINK}
+.endif
diff --git a/contrib/smbfs/lib/smb/cfopt.c b/contrib/smbfs/lib/smb/cfopt.c
new file mode 100644
index 0000000..5328b2f
--- /dev/null
+++ b/contrib/smbfs/lib/smb/cfopt.c
@@ -0,0 +1,123 @@
+/*
+ * 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.3 2000/07/11 01:51:49 bp Exp $
+ */
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <cflib.h>
+
+extern char *__progname;
+
+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,
+ "%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,
+ "%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/contrib/smbfs/lib/smb/ctx.c b/contrib/smbfs/lib/smb/ctx.c
new file mode 100644
index 0000000..6ecb190
--- /dev/null
+++ b/contrib/smbfs/lib/smb/ctx.c
@@ -0,0 +1,773 @@
+/*
+ * 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.21 2001/04/06 15:47:14 bp Exp $
+ */
+#include <sys/param.h>
+#include <sys/sysctl.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 <sys/iconv.h>
+
+#define NB_NEEDRESOLVER
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_conn.h>
+#include <cflib.h>
+
+/*
+ * Prescan command line for [-U user] argument
+ * and fill context with defaults
+ */
+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;
+
+ bzero(ctx,sizeof(*ctx));
+ 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;
+ 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, "");
+ smb_ctx_setuser(ctx, getpwuid(geteuid())->pw_name);
+ endpwent();
+ if (argv == NULL)
+ return 0;
+ for (opt = 1; opt < argc; opt++) {
+ cp = argv[opt];
+ if (strncmp(cp, "//", 2) != 0)
+ continue;
+ error = smb_ctx_parseunc(ctx, cp, sharetype, (const char**)&cp);
+ if (error)
+ return error;
+ ctx->ct_uncnext = cp;
+ break;
+ }
+ while (error == 0 && (opt = cf_getopt(argc, argv, ":E:L:U:")) != -1) {
+ arg = cf_optarg;
+ switch (opt) {
+ case 'E':
+ error = smb_ctx_setcharset(ctx, arg);
+ if (error)
+ return error;
+ break;
+ case 'L':
+ error = nls_setlocale(optarg);
+ if (error)
+ break;
+ break;
+ case 'U':
+ error = smb_ctx_setuser(ctx, arg);
+ break;
+ }
+ }
+ cf_optind = cf_optreset = 1;
+ return error;
+}
+
+void
+smb_ctx_done(struct smb_ctx *ctx)
+{
+ 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);
+ if (ctx->ct_srvaddr)
+ free(ctx->ct_srvaddr);
+ if (ctx->ct_nb)
+ nb_ctx_done(ctx->ct_nb);
+}
+
+static int
+getsubstring(const char *p, u_char 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;
+}
+
+/*
+ * Here we expect something like "[proto:]//[user@]host[/share][/path]"
+ */
+int
+smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
+ const char **next)
+{
+ const char *p = unc;
+ char *p1;
+ char tmp[1024];
+ int error ;
+
+ ctx->ct_parsedlevel = SMBL_NONE;
+ if (*p++ != '/' || *p++ != '/') {
+ smb_error("UNC should start with '//'", 0);
+ return EINVAL;
+ }
+ p1 = tmp;
+ error = getsubstring(p, '@', p1, sizeof(tmp), &p);
+ if (!error) {
+ if (ctx->ct_maxlevel < SMBL_VC) {
+ smb_error("no user name required", 0);
+ return EINVAL;
+ }
+ if (*p1 == 0) {
+ smb_error("empty user name", 0);
+ return EINVAL;
+ }
+ error = smb_ctx_setuser(ctx, tmp);
+ 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("no server name found", 0);
+ return error;
+ }
+ }
+ if (*p1 == 0) {
+ smb_error("empty server name", 0);
+ return EINVAL;
+ }
+ error = smb_ctx_setserver(ctx, tmp);
+ if (error)
+ return error;
+ if (sharetype == SMB_ST_NONE) {
+ *next = p;
+ return 0;
+ }
+ if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
+ smb_error("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("unexpected end of line", 0);
+ return error;
+ }
+ }
+ if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE) {
+ smb_error("empty share name", 0);
+ return EINVAL;
+ }
+ *next = p;
+ if (*p1 == 0)
+ return 0;
+ error = smb_ctx_setshare(ctx, 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("invalid local charset specification (%s)", 0, arg);
+ return EINVAL;
+ }
+ scslen = (size_t)strlen(++cp);
+ if (scslen == 0 || scslen >= cslen) {
+ smb_error("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("can't initialize iconv support (%s:%s)",
+ error, localcs, servercs);
+ localcs[0] = 0;
+ servercs[0] = 0;
+ return error;
+}
+
+int
+smb_ctx_setserver(struct smb_ctx *ctx, const char *name)
+{
+ if (strlen(name) >= SMB_MAXSRVNAMELEN) {
+ smb_error("server name '%s' too long", 0, name);
+ return ENAMETOOLONG;
+ }
+ nls_str_upper(ctx->ct_ssn.ioc_srvname, name);
+ return 0;
+}
+
+int
+smb_ctx_setuser(struct smb_ctx *ctx, const char *name)
+{
+ if (strlen(name) >= SMB_MAXUSERNAMELEN) {
+ smb_error("user name '%s' too long", 0, name);
+ return ENAMETOOLONG;
+ }
+ nls_str_upper(ctx->ct_ssn.ioc_user, name);
+ return 0;
+}
+
+int
+smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name)
+{
+ if (strlen(name) >= SMB_MAXUSERNAMELEN) {
+ smb_error("workgroup name '%s' too long", 0, name);
+ return ENAMETOOLONG;
+ }
+ nls_str_upper(ctx->ct_ssn.ioc_workgroup, name);
+ return 0;
+}
+
+int
+smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd)
+{
+ if (passwd == NULL)
+ return EINVAL;
+ if (strlen(passwd) >= SMB_MAXPASSWORDLEN) {
+ smb_error("password too long", 0);
+ return ENAMETOOLONG;
+ }
+ 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);
+ return 0;
+}
+
+int
+smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
+{
+ if (strlen(share) >= SMB_MAXSHARENAMELEN) {
+ smb_error("share name '%s' too long", 0, share);
+ return ENAMETOOLONG;
+ }
+ 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 *cp;
+
+ cp = strchr(pair, ':');
+ if (cp) {
+ *cp++ = '\0';
+ if (*cp) {
+ gr = getgrnam(cp);
+ if (gr) {
+ *gid = gr->gr_gid;
+ } else
+ smb_error("Invalid group name %s, ignored",
+ 0, cp);
+ }
+ }
+ if (*pair) {
+ pw = getpwnam(pair);
+ if (pw) {
+ *uid = pw->pw_uid;
+ } else
+ smb_error("Invalid user name %s, ignored", 0, pair);
+ }
+ endpwent();
+ return 0;
+}
+
+int
+smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
+{
+ int error = 0;
+ char *p, *cp;
+
+ switch(opt) {
+ case 'U':
+ 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':
+ error = smb_ctx_setworkgroup(ctx, arg);
+ break;
+ }
+ return error;
+}
+
+#if 0
+static void
+smb_hexdump(const u_char *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 u_char *tbl)
+{
+ int error;
+
+ error = kiconv_add_xlat_table(to, from, tbl);
+ if (error && error != EEXIST) {
+ smb_error("can not setup kernel iconv table (%s:%s)", error,
+ from, to);
+ return error;
+ }
+ 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;
+ u_char cstbl[256];
+ u_int i;
+ int error = 0;
+
+ ctx->ct_flags &= ~SMBCF_RESOLVED;
+ if (ssn->ioc_srvname[0] == 0) {
+ smb_error("no server name specified", 0);
+ return EINVAL;
+ }
+ if (ssn->ioc_user[0] == 0) {
+ smb_error("no user name specified for server %s",
+ 0, ssn->ioc_srvname);
+ return EINVAL;
+ }
+ if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0) {
+ smb_error("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 (ctx->ct_srvaddr) {
+ error = nb_resolvehost_in(ctx->ct_srvaddr, &sap);
+ } else {
+ error = nbns_resolvename(ssn->ioc_srvname, ctx->ct_nb, &sap);
+ }
+ if (error) {
+ smb_error("can't get server address", error);
+ return error;
+ }
+ nn.nn_scope = ctx->ct_nb->nb_scope;
+ nn.nn_type = NBT_SERVER;
+ strcpy(nn.nn_name, ssn->ioc_srvname);
+ error = nb_sockaddr(sap, &nn, &saserver);
+ nb_snbfree(sap);
+ if (error) {
+ smb_error("can't allocate server address", error);
+ return error;
+ }
+ ssn->ioc_server = (struct sockaddr*)saserver;
+ if (ctx->ct_locname[0] == 0) {
+ error = nb_getlocalname(ctx->ct_locname);
+ if (error) {
+ smb_error("can't get local name", error);
+ return error;
+ }
+ nls_str_upper(ctx->ct_locname, ctx->ct_locname);
+ }
+ strcpy(nn.nn_name, ctx->ct_locname);
+ 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("can't allocate local address", error);
+ return error;
+ }
+ ssn->ioc_local = (struct sockaddr*)salocal;
+ ssn->ioc_lolen = salocal->snb_len;
+ ssn->ioc_svlen = saserver->snb_len;
+ if (ssn->ioc_password[0] == 0 && (ctx->ct_flags & SMBCF_NOPWD) == 0) {
+ cp = getpass("Password:");
+ error = smb_ctx_setpassword(ctx, cp);
+ if (error)
+ return error;
+ }
+ ctx->ct_flags |= SMBCF_RESOLVED;
+ return 0;
+}
+
+static int
+smb_ctx_gethandle(struct smb_ctx *ctx)
+{
+ int fd, i;
+ char buf[20];
+
+ /*
+ * First try to open as clone
+ */
+ fd = open("/dev/"NSMB_NAME, O_RDWR);
+ if (fd >= 0) {
+ ctx->ct_fd = fd;
+ return 0;
+ }
+ /*
+ * 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) {
+ ctx->ct_fd = fd;
+ return 0;
+ }
+ }
+ /*
+ * This is a compatibility with old /dev/net/nsmb device
+ */
+ for (i = 0; i < 1024; i++) {
+ snprintf(buf, sizeof(buf), "/dev/net/%s%d", NSMB_NAME, i);
+ fd = open(buf, O_RDWR);
+ if (fd >= 0) {
+ ctx->ct_fd = fd;
+ return 0;
+ }
+ if (errno == ENOENT)
+ return ENOENT;
+ }
+ return ENOENT;
+}
+
+int
+smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags)
+{
+ struct smbioc_lookup rq;
+ int error;
+
+ if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
+ smb_error("smb_ctx_lookup() data is not resolved", 0);
+ return EINVAL;
+ }
+ if (ctx->ct_fd != -1) {
+ close(ctx->ct_fd);
+ ctx->ct_fd = -1;
+ }
+ error = smb_ctx_gethandle(ctx);
+ if (error) {
+ smb_error("can't get handle to requester (no /dev/net/nsmb* device)", 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));
+ rq.ioc_flags = flags;
+ rq.ioc_level = level;
+ if (ioctl(ctx->ct_fd, SMBIOC_LOOKUP, &rq) == -1) {
+ error = errno;
+ if (flags & SMBLK_CREATE)
+ smb_error("unable to open connection", error);
+ return error;
+ }
+ return 0;
+}
+
+int
+smb_ctx_login(struct smb_ctx *ctx)
+{
+ struct smbioc_ossn *ssn = &ctx->ct_ssn;
+ struct smbioc_oshare *sh = &ctx->ct_sh;
+ int error;
+
+ if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
+ smb_error("smb_ctx_resolve() should be called first", 0);
+ return EINVAL;
+ }
+ if (ctx->ct_fd != -1) {
+ close(ctx->ct_fd);
+ ctx->ct_fd = -1;
+ }
+ error = smb_ctx_gethandle(ctx);
+ if (error) {
+ smb_error("can't get handle to requester", 0);
+ return EINVAL;
+ }
+ if (ioctl(ctx->ct_fd, SMBIOC_OPENSESSION, ssn) == -1) {
+ error = errno;
+ smb_error("can't open session to server %s", error, ssn->ioc_srvname);
+ return error;
+ }
+ if (sh->ioc_share[0] == 0)
+ return 0;
+ if (ioctl(ctx->ct_fd, SMBIOC_OPENSHARE, sh) == -1) {
+ error = errno;
+ smb_error("can't connect to share //%s/%s", error,
+ ssn->ioc_srvname, sh->ioc_share);
+ return error;
+ }
+ return 0;
+}
+
+int
+smb_ctx_setflags(struct smb_ctx *ctx, int level, int mask, int flags)
+{
+ struct smbioc_flags fl;
+
+ if (ctx->ct_fd == -1)
+ return EINVAL;
+ fl.ioc_level = level;
+ fl.ioc_mask = mask;
+ fl.ioc_flags = flags;
+ if (ioctl(ctx->ct_fd, SMBIOC_SETFLAGS, &fl) == -1)
+ return errno;
+ return 0;
+}
+
+/*
+ * 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;
+
+ if (level > 0) {
+ rc_getstringptr(smb_rc, sname, "charsets", &p);
+ if (p) {
+ error = smb_ctx_setcharset(ctx, p);
+ if (error)
+ smb_error("charset specification in the section '%s' ignored", error, sname);
+ }
+ }
+ if (level <= 1) {
+ rc_getint(smb_rc, sname, "timeout", &ctx->ct_ssn.ioc_timeout);
+ rc_getint(smb_rc, sname, "retry_count", &ctx->ct_ssn.ioc_retrycount);
+ }
+ if (level == 1) {
+ rc_getstringptr(smb_rc, sname, "addr", &p);
+ if (p) {
+ error = smb_ctx_setsrvaddr(ctx, p);
+ if (error) {
+ smb_error("invalid address specified in the section %s", 0, sname);
+ return error;
+ }
+ }
+ }
+ if (level >= 2) {
+ rc_getstringptr(smb_rc, sname, "password", &p);
+ if (p)
+ smb_ctx_setpassword(ctx, p);
+ }
+ rc_getstringptr(smb_rc, sname, "workgroup", &p);
+ if (p)
+ smb_ctx_setworkgroup(ctx, p);
+ return 0;
+}
+
+/*
+ * read rc file as follows:
+ * 1. read [default] section
+ * 2. override with [server] section
+ * 3. override with [server:user:share] section
+ * Since abcence 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];
+/* char *p;*/
+
+ if (smb_open_rcfile() != 0)
+ return 0;
+
+ if (ctx->ct_ssn.ioc_user[0] == 0 || ctx->ct_ssn.ioc_srvname[0] == 0)
+ return 0;
+
+ smb_ctx_readrcsection(ctx, "default", 0);
+ nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
+ smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1);
+ nb_ctx_readrcsection(smb_rc, ctx->ct_nb, ctx->ct_ssn.ioc_srvname, 1);
+ /*
+ * 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 (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);
+ }
+ return 0;
+}
+
diff --git a/contrib/smbfs/lib/smb/file.c b/contrib/smbfs/lib/smb/file.c
new file mode 100644
index 0000000..9408576
--- /dev/null
+++ b/contrib/smbfs/lib/smb/file.c
@@ -0,0 +1,80 @@
+/*
+ * 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.2 2001/04/16 04:33:01 bp Exp $
+ */
+#include <sys/param.h>
+#include <sys/sysctl.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 <netsmb/smb_conn.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;
+
+ rwrq.ioc_fh = fh;
+ rwrq.ioc_base = dst;
+ rwrq.ioc_cnt = count;
+ rwrq.ioc_offset = offset;
+ if (ioctl(ctx->ct_fd, SMBIOC_READ, &rwrq) == -1)
+ return -1;
+ 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;
+
+ rwrq.ioc_fh = fh;
+ (const char*)rwrq.ioc_base = src;
+ rwrq.ioc_cnt = count;
+ rwrq.ioc_offset = offset;
+ if (ioctl(ctx->ct_fd, SMBIOC_WRITE, &rwrq) == -1)
+ return -1;
+ return rwrq.ioc_cnt;
+}
diff --git a/contrib/smbfs/lib/smb/kiconv.c b/contrib/smbfs/lib/smb/kiconv.c
new file mode 100644
index 0000000..ce69c84
--- /dev/null
+++ b/contrib/smbfs/lib/smb/kiconv.c
@@ -0,0 +1,61 @@
+/*
+ * 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: kiconv.c,v 1.2 2001/04/16 04:33:01 bp Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/iconv.h>
+#include <sys/sysctl.h>
+#include <ctype.h>
+#include <errno.h>
+
+int
+kiconv_add_xlat_table(const char *to, const char *from, const u_char *table)
+{
+ struct iconv_add_in din;
+ struct iconv_add_out dout;
+ int olen;
+
+ if (strlen(from) > ICONV_CSNMAXLEN || strlen(to) > ICONV_CSNMAXLEN)
+ return EINVAL;
+ din.ia_version = ICONV_ADD_VER;
+ strcpy(din.ia_converter, "xlat");
+ strcpy(din.ia_from, from);
+ strcpy(din.ia_to, to);
+ din.ia_data = table;
+ din.ia_datalen = 256;
+ olen = sizeof(dout);
+ if (sysctlbyname("kern.iconv.add", &dout, &olen, &din, sizeof(din)) == -1)
+ return errno;
+ return 0;
+}
+
diff --git a/contrib/smbfs/lib/smb/mbuf.c b/contrib/smbfs/lib/smb/mbuf.c
new file mode 100644
index 0000000..fa31486
--- /dev/null
+++ b/contrib/smbfs/lib/smb/mbuf.c
@@ -0,0 +1,467 @@
+/*
+ * 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.6 2001/02/24 15:56:04 bp Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/mchain.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netsmb/smb_lib.h>
+
+#define MBERROR(format, args...) printf("%s(%d): "format, __FUNCTION__ , \
+ __LINE__ ,## args)
+
+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
+mb_fixhdr(struct mbdata *mbp)
+{
+ struct mbuf *m = mbp->mb_top;
+ int len = 0;
+
+ while (m) {
+ len += m->m_len;
+ m = m->m_next;
+ }
+ mbp->mb_top->m_pkthdr.len = len;
+ return len;
+}
+*/
+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, u_int8_t x)
+{
+ MB_PUT(u_int8_t);
+ *p = x;
+ return 0;
+}
+
+int
+mb_put_uint16be(struct mbdata *mbp, u_int16_t x)
+{
+ MB_PUT(u_int16_t);
+ setwbe(p, 0, x);
+ return 0;
+}
+
+int
+mb_put_uint16le(struct mbdata *mbp, u_int16_t x)
+{
+ MB_PUT(u_int16_t);
+ setwle(p, 0, x);
+ return 0;
+}
+
+int
+mb_put_uint32be(struct mbdata *mbp, u_int32_t x)
+{
+ MB_PUT(u_int32_t);
+ setdbe(p, 0, x);
+ return 0;
+}
+
+int
+mb_put_uint32le(struct mbdata *mbp, u_int32_t x)
+{
+ MB_PUT(u_int32_t);
+ setdle(p, 0, x);
+ return 0;
+}
+
+int
+mb_put_int64be(struct mbdata *mbp, int64_t x)
+{
+ MB_PUT(int64_t);
+ *p = htobeq(x);
+ return 0;
+}
+
+int
+mb_put_int64le(struct mbdata *mbp, int64_t x)
+{
+ MB_PUT(int64_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, u_int8_t *x)
+{
+ return mb_get_mem(mbp, x, 1);
+}
+
+int
+mb_get_uint16(struct mbdata *mbp, u_int16_t *x)
+{
+ return mb_get_mem(mbp, (char *)x, 2);
+}
+
+int
+mb_get_uint16le(struct mbdata *mbp, u_int16_t *x)
+{
+ u_int16_t v;
+ int error = mb_get_uint16(mbp, &v);
+
+ *x = letohs(v);
+ return error;
+}
+
+int
+mb_get_uint16be(struct mbdata *mbp, u_int16_t *x) {
+ u_int16_t v;
+ int error = mb_get_uint16(mbp, &v);
+
+ *x = betohs(v);
+ return error;
+}
+
+int
+mb_get_uint32(struct mbdata *mbp, u_int32_t *x)
+{
+ return mb_get_mem(mbp, (char *)x, 4);
+}
+
+int
+mb_get_uint32be(struct mbdata *mbp, u_int32_t *x)
+{
+ u_int32_t v;
+ int error;
+
+ error = mb_get_uint32(mbp, &v);
+ *x = betohl(v);
+ return error;
+}
+
+int
+mb_get_uint32le(struct mbdata *mbp, u_int32_t *x)
+{
+ u_int32_t v;
+ int error;
+
+ error = mb_get_uint32(mbp, &v);
+ *x = letohl(v);
+ return error;
+}
+
+int
+mb_get_int64(struct mbdata *mbp, int64_t *x)
+{
+ return mb_get_mem(mbp, (char *)x, 8);
+}
+
+int
+mb_get_int64be(struct mbdata *mbp, int64_t *x)
+{
+ int64_t v;
+ int error;
+
+ error = mb_get_int64(mbp, &v);
+ *x = betohq(v);
+ return error;
+}
+
+int
+mb_get_int64le(struct mbdata *mbp, int64_t *x)
+{
+ int64_t v;
+ int error;
+
+ error = mb_get_int64(mbp, &v);
+ *x = letohq(v);
+ return error;
+}
+
+int
+mb_get_mem(struct mbdata *mbp, char * target, size_t size)
+{
+ struct mbuf *m = mbp->mb_cur;
+ u_int count;
+
+ while (size > 0) {
+ if (m == NULL) {
+ MBERROR("incomplete copy\n");
+ 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/contrib/smbfs/lib/smb/nb.c b/contrib/smbfs/lib/smb/nb.c
new file mode 100644
index 0000000..2be9ab0
--- /dev/null
+++ b/contrib/smbfs/lib/smb/nb.c
@@ -0,0 +1,191 @@
+/*
+ * 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.4 2001/04/16 04:33:01 bp Exp $
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <cflib.h>
+
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.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));
+ *ctxpp = ctx;
+ return 0;
+}
+
+void
+nb_ctx_done(struct nb_ctx *ctx)
+{
+ if (ctx == NULL)
+ return;
+ if (ctx->nb_scope)
+ free(ctx->nb_scope);
+}
+
+int
+nb_ctx_setns(struct nb_ctx *ctx, const char *addr)
+{
+ if (addr == NULL || addr[0] == 0)
+ return EINVAL;
+ if (ctx->nb_nsname)
+ free(ctx->nb_nsname);
+ if ((ctx->nb_nsname = strdup(addr)) == NULL)
+ return ENOMEM;
+ return 0;
+}
+
+int
+nb_ctx_setscope(struct nb_ctx *ctx, const char *scope)
+{
+ size_t slen = strlen(scope);
+
+ if (slen >= 128) {
+ smb_error("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;
+}
+
+int
+nb_ctx_resolve(struct nb_ctx *ctx)
+{
+ struct sockaddr *sap;
+ int error;
+
+ ctx->nb_flags &= ~NBCF_RESOLVED;
+
+ if (ctx->nb_nsname == NULL) {
+ ctx->nb_ns.sin_addr.s_addr = htonl(INADDR_BROADCAST);
+ } else {
+ error = nb_resolvehost_in(ctx->nb_nsname, &sap);
+ if (error) {
+ smb_error("can't resolve %s", error, ctx->nb_nsname);
+ return error;
+ }
+ if (sap->sa_family != AF_INET) {
+ smb_error("unsupported address family %d", 0, sap->sa_family);
+ return EINVAL;
+ }
+ bcopy(sap, &ctx->nb_ns, sizeof(ctx->nb_ns));
+ free(sap);
+ }
+ ctx->nb_ns.sin_port = htons(137);
+ ctx->nb_ns.sin_family = AF_INET;
+ ctx->nb_ns.sin_len = sizeof(ctx->nb_ns);
+ ctx->nb_flags |= NBCF_RESOLVED;
+ return 0;
+}
+
+/*
+ * used level values:
+ * 0 - default
+ * 1 - server
+ */
+int
+nb_ctx_readrcsection(struct rcfile *rcfile, struct nb_ctx *ctx,
+ const char *sname, int level)
+{
+ char *p;
+ int error;
+
+ if (level > 1)
+ return EINVAL;
+ rc_getint(rcfile, sname, "nbtimeout", &ctx->nb_timo);
+ rc_getstringptr(rcfile, sname, "nbns", &p);
+ if (p) {
+ error = nb_ctx_setns(ctx, p);
+ if (error) {
+ smb_error("invalid address specified in the section %s", 0, sname);
+ return error;
+ }
+ }
+ rc_getstringptr(rcfile, sname, "nbscope", &p);
+ if (p)
+ nb_ctx_setscope(ctx, p);
+ return 0;
+}
+
+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"
+};
+
+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/contrib/smbfs/lib/smb/nb_name.c b/contrib/smbfs/lib/smb/nb_name.c
new file mode 100644
index 0000000..24b1a80
--- /dev/null
+++ b/contrib/smbfs/lib/smb/nb_name.c
@@ -0,0 +1,198 @@
+/*
+ * 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.1 2000/07/16 01:52:07 bp Exp $
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+
+int
+nb_snballoc(int namelen, struct sockaddr_nb **dst)
+{
+ struct sockaddr_nb *snb;
+ int slen;
+
+ slen = namelen + sizeof(*snb) - sizeof(snb->snb_name);
+ snb = malloc(slen);
+ if (snb == NULL)
+ return ENOMEM;
+ bzero(snb, slen);
+ snb->snb_family = AF_NETBIOS;
+ snb->snb_len = slen;
+ *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;
+ int nmlen, error;
+
+ if (peer && (peer->sa_family != AF_INET && peer->sa_family != AF_IPX))
+ return EPROTONOSUPPORT;
+ nmlen = nb_name_len(np);
+ if (nmlen < NB_ENCNAMELEN)
+ return EINVAL;
+ error = nb_snballoc(nmlen, &snb);
+ if (error)
+ return error;
+ if (nmlen != nb_name_encode(np, snb->snb_name))
+ printf("a bug somewhere in the nb_name* code\n");
+ if (peer)
+ memcpy(&snb->snb_tran, peer, peer->sa_len);
+ *dst = snb;
+ return 0;
+}
+
+int
+nb_name_len(struct nb_name *np)
+{
+ u_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 char *str)
+{
+ const u_char *cp = (const u_char *)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;
+}
+
+#define NBENCODE(c) ((u_short)(((u_char)(c) >> 4) | \
+ (((u_char)(c) & 0xf) << 8)) + 0x4141)
+
+static void
+memsetw(char *dst, int n, u_short word)
+{
+ while (n--) {
+ *(u_short*)dst = word;
+ dst += 2;
+ }
+}
+
+int
+nb_name_encode(struct nb_name *np, u_char *dst)
+{
+ u_char *name, *plen;
+ u_char *cp = dst;
+ int i, lblen;
+
+ *cp++ = NB_ENCNAMELEN;
+ name = np->nn_name;
+ if (name[0] == '*' && name[1] == 0) {
+ *(u_short*)cp = NBENCODE('*');
+ memsetw(cp + 2, NB_NAMELEN - 1, NBENCODE(' '));
+ cp += NB_ENCNAMELEN;
+ } else {
+ for (i = 0; *name && i < NB_NAMELEN; i++, cp += 2, name++)
+ *(u_short*)cp = NBENCODE(toupper(*name));
+ i = NB_NAMELEN - i - 1;
+ if (i > 0) {
+ memsetw(cp, i, NBENCODE(' '));
+ cp += i * 2;
+ }
+ *(u_short*)cp = NBENCODE(np->nn_type);
+ cp += 2;
+ }
+ *cp = 0;
+ if (np->nn_scope == NULL)
+ return nb_encname_len(dst);
+ plen = cp++;
+ lblen = 0;
+ for (name = np->nn_scope; ; name++) {
+ if (*name == '.' || *name == 0) {
+ *plen = lblen;
+ plen = cp++;
+ *plen = 0;
+ if (*name == 0)
+ break;
+ } else {
+ if (lblen < NB_MAXLABLEN) {
+ *cp++ = *name;
+ lblen++;
+ }
+ }
+ }
+ return nb_encname_len(dst);
+}
+
diff --git a/contrib/smbfs/lib/smb/nb_net.c b/contrib/smbfs/lib/smb/nb_net.c
new file mode 100644
index 0000000..c0a2060
--- /dev/null
+++ b/contrib/smbfs/lib/smb/nb_net.c
@@ -0,0 +1,201 @@
+/*
+ * 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.4 2001/02/16 02:46:12 bp Exp $
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+
+int
+nb_getlocalname(char *name)
+{
+ char buf[1024], *cp;
+
+ if (gethostname(buf, sizeof(buf)) != 0)
+ return errno;
+ cp = strchr(buf, '.');
+ if (cp)
+ *cp = 0;
+ strcpy(name, buf);
+ return 0;
+}
+
+int
+nb_resolvehost_in(const char *name, struct sockaddr **dest)
+{
+ struct hostent* h;
+ struct sockaddr_in *sinp;
+ int len;
+
+ h = gethostbyname(name);
+ if (!h) {
+ warnx("can't get server address `%s': ", name);
+ herror(NULL);
+ return ENETDOWN;
+ }
+ if (h->h_addrtype != AF_INET) {
+ warnx("address for `%s' is not in the AF_INET family", name);
+ return EAFNOSUPPORT;
+ }
+ if (h->h_length != 4) {
+ warnx("address for `%s' has invalid length", name);
+ return EAFNOSUPPORT;
+ }
+ len = sizeof(struct sockaddr_in);
+ sinp = malloc(len);
+ if (sinp == NULL)
+ return ENOMEM;
+ bzero(sinp, len);
+ sinp->sin_len = len;
+ sinp->sin_family = h->h_addrtype;
+ memcpy(&sinp->sin_addr.s_addr, h->h_addr, 4);
+ sinp->sin_port = htons(SMB_TCP_PORT);
+ *dest = (struct sockaddr*)sinp;
+ return 0;
+}
+
+int
+nb_enum_if(struct nb_ifdesc **iflist, int maxif)
+{
+ struct ifconf ifc;
+ struct ifreq *ifrqp;
+ struct nb_ifdesc *ifd;
+ struct in_addr iaddr, imask;
+ char *ifrdata, *iname;
+ int s, rdlen, ifcnt, error, iflags, i;
+
+ *iflist = NULL;
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s == -1)
+ return errno;
+
+ rdlen = maxif * sizeof(struct ifreq);
+ ifrdata = malloc(rdlen);
+ if (ifrdata == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ ifc.ifc_len = rdlen;
+ ifc.ifc_buf = ifrdata;
+ if (ioctl(s, SIOCGIFCONF, &ifc) != 0) {
+ error = errno;
+ goto bad;
+ }
+ ifrqp = ifc.ifc_req;
+ ifcnt = ifc.ifc_len / sizeof(struct ifreq);
+ error = 0;
+ for (i = 0; i < ifcnt; i++, ifrqp++) {
+ if (ioctl(s, SIOCGIFFLAGS, ifrqp) != 0)
+ continue;
+ iflags = ifrqp->ifr_flags;
+ if ((iflags & IFF_UP) == 0 || (iflags & IFF_BROADCAST) == 0)
+ continue;
+
+ if (ioctl(s, SIOCGIFADDR, ifrqp) != 0 ||
+ ifrqp->ifr_addr.sa_family != AF_INET)
+ continue;
+ iname = ifrqp->ifr_name;
+ if (strlen(iname) >= sizeof(ifd->id_name))
+ continue;
+ iaddr = (*(struct sockaddr_in *)&ifrqp->ifr_addr).sin_addr;
+
+ if (ioctl(s, SIOCGIFNETMASK, ifrqp) != 0)
+ continue;
+ imask = ((struct sockaddr_in *)&ifrqp->ifr_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;
+}
+*/ \ No newline at end of file
diff --git a/contrib/smbfs/lib/smb/nbns_rq.c b/contrib/smbfs/lib/smb/nbns_rq.c
new file mode 100644
index 0000000..5ea22f1
--- /dev/null
+++ b/contrib/smbfs/lib/smb/nbns_rq.c
@@ -0,0 +1,380 @@
+/*
+ * 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.5 2001/02/17 03:07:24 bp Exp $
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define NB_NEEDRESOLVER
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.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;
+
+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;
+ bzero(&nn, sizeof(nn));
+ strcpy(nn.nn_name, name);
+ nn.nn_scope = ctx->nb_scope;
+ nn.nn_type = NBT_SERVER;
+ 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;
+ dest = &rqp->nr_dest;
+ *dest = ctx->nb_ns;
+ dest->sin_family = AF_INET;
+ dest->sin_len = sizeof(*dest);
+ if (dest->sin_port == 0)
+ dest->sin_port = htons(137);
+ if (dest->sin_addr.s_addr == INADDR_ANY)
+ dest->sin_addr.s_addr = htonl(INADDR_BROADCAST);
+ if (dest->sin_addr.s_addr == INADDR_BROADCAST)
+ rqp->nr_flags |= NBRQF_BROADCAST;
+ 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) {
+ 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, &dest->sin_addr, 4);
+ rqp->nr_flags &= ~NBRQF_BROADCAST;
+ 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);
+ 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;
+}
+
+int
+nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp)
+{
+ struct nbns_rq *rqp;
+ static u_int16_t trnid;
+ int error;
+
+ 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);
+ 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;
+ u_char *cp;
+ int error, len;
+
+ bzero(rrp, sizeof(*rrp));
+ cp = 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 = 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;
+ u_int8_t nmflags;
+ u_char *cp;
+ int len, error;
+
+ error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE);
+ if (error)
+ return error;
+ if (rqp->nr_dest.sin_addr.s_addr == INADDR_BROADCAST) {
+ rqp->nr_nmflags |= NBNS_NMFLAG_BCAST;
+ if (nb_iflist == NULL) {
+ error = nb_enum_if(&nb_iflist, 100);
+ if (error)
+ return error;
+ }
+ } else
+ rqp->nr_nmflags &= ~NBNS_NMFLAG_BCAST;
+ mb_put_uint16be(mbp, rqp->nr_trnid);
+ nmflags = ((rqp->nr_opcode & 0x1F) << 3) | ((rqp->nr_nmflags & 0x70) >> 4);
+ mb_put_uint8(mbp, nmflags);
+ mb_put_uint8(mbp, (rqp->nr_nmflags & 0x0f) << 4 /* rcode */);
+ 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, s;
+
+ s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return errno;
+ if (rqp->nr_flags & NBRQF_BROADCAST) {
+ opt = 1;
+ if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) < 0)
+ return errno;
+ if (rqp->nr_if == NULL)
+ return NBERROR(NBERR_NOBCASTIFS);
+ bzero(&locaddr, sizeof(locaddr));
+ locaddr.sin_family = AF_INET;
+ locaddr.sin_len = sizeof(locaddr);
+ locaddr.sin_addr = rqp->nr_if->id_addr;
+ rqp->nr_dest.sin_addr.s_addr = rqp->nr_if->id_addr.s_addr | ~rqp->nr_if->id_mask.s_addr;
+ if (bind(s, (struct sockaddr*)&locaddr, sizeof(locaddr)) < 0)
+ return errno;
+ }
+ return 0;
+}
+
+static int
+nbns_rq_send(struct nbns_rq *rqp)
+{
+ struct mbdata *mbp = &rqp->nr_rq;
+ int s = rqp->nr_fd;
+
+ if (sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0,
+ (struct sockaddr*)&rqp->nr_dest, sizeof(rqp->nr_dest)) < 0)
+ return errno;
+ return 0;
+}
+
+int
+nbns_rq(struct nbns_rq *rqp)
+{
+ struct mbdata *mbp = &rqp->nr_rq;
+ u_int16_t rpid;
+ u_int8_t nmflags;
+ int error, retrycount;
+
+ rqp->nr_if = nb_iflist;
+again:
+ error = nbns_rq_opensocket(rqp);
+ if (error)
+ return error;
+ retrycount = 3; /* XXX - configurable */
+ for (;;) {
+ error = nbns_rq_send(rqp);
+ if (error)
+ return error;
+ error = nbns_rq_recv(rqp);
+ if (error) {
+ if (error != ETIMEDOUT || retrycount == 0) {
+ if ((rqp->nr_nmflags & NBNS_NMFLAG_BCAST) &&
+ rqp->nr_if != NULL &&
+ rqp->nr_if->id_next != NULL) {
+ rqp->nr_if = rqp->nr_if->id_next;
+ close(rqp->nr_fd);
+ goto again;
+ } else
+ return error;
+ }
+ retrycount--;
+ continue;
+ }
+ 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_uint8(mbp, &nmflags);
+ rqp->nr_rpnmflags = (nmflags & 7) << 4;
+ mb_get_uint8(mbp, &nmflags);
+ rqp->nr_rpnmflags |= (nmflags & 0xf0) >> 4;
+ rqp->nr_rprcode = nmflags & 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/contrib/smbfs/lib/smb/nls.c b/contrib/smbfs/lib/smb/nls.c
new file mode 100644
index 0000000..7517c6e
--- /dev/null
+++ b/contrib/smbfs/lib/smb/nls.c
@@ -0,0 +1,214 @@
+/*
+ * 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.8 2001/04/16 12:46:46 bp Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/iconv.h>
+#include <sys/sysctl.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <err.h>
+#include <netsmb/smb_lib.h>
+
+/*
+ * prototype iconv* functions
+ */
+typedef void *iconv_t;
+
+static iconv_t (*my_iconv_open)(const char *, const char *);
+static size_t(*my_iconv)(iconv_t, const char **, size_t *, char **, size_t *);
+static int(*my_iconv_close)(iconv_t);
+
+u_char nls_lower[256];
+u_char nls_upper[256];
+
+static iconv_t nls_toext, nls_toloc;
+static int iconv_loaded;
+static void *iconv_lib;
+
+int
+nls_setlocale(const char *name)
+{
+ int i;
+
+ if (setlocale(LC_CTYPE, name) == NULL) {
+ warnx("can't set locale '%s'\n", name);
+ return EINVAL;
+ }
+ 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)
+{
+ iconv_t icd;
+
+ if (iconv_loaded == 2)
+ return ENOENT;
+ else if (iconv_loaded == 0) {
+ iconv_loaded++;
+ iconv_lib = dlopen("libiconv.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (iconv_lib == NULL) {
+ warn("Unable to load iconv library: %s\n", dlerror());
+ iconv_loaded++;
+ return ENOENT;
+ }
+ my_iconv_open = dlsym(iconv_lib, "iconv_open");
+ my_iconv = dlsym(iconv_lib, "iconv");
+ my_iconv_close = dlsym(iconv_lib, "iconv_close");
+ }
+ if (nls_toext)
+ my_iconv_close(nls_toext);
+ if (nls_toloc)
+ my_iconv_close(nls_toloc);
+ nls_toext = nls_toloc = (iconv_t)0;
+ icd = my_iconv_open(external, local);
+ if (icd == (iconv_t)-1)
+ return errno;
+ nls_toext = icd;
+ icd = my_iconv_open(local, external);
+ if (icd == (iconv_t)-1) {
+ my_iconv_close(nls_toext);
+ nls_toext = (iconv_t)0;
+ return errno;
+ }
+ nls_toloc = icd;
+ return 0;
+}
+
+char *
+nls_str_toloc(char *dst, const char *src)
+{
+ char *p = dst;
+ int 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;
+ int 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;
+ int 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;
+ int 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/contrib/smbfs/lib/smb/print.c b/contrib/smbfs/lib/smb/print.c
new file mode 100644
index 0000000..243ad5b
--- /dev/null
+++ b/contrib/smbfs/lib/smb/print.c
@@ -0,0 +1,97 @@
+/*
+ * 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.4 2001/04/16 04:33:01 bp Exp $
+ */
+#include <sys/param.h>
+#include <sys/sysctl.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 <netnb/netbios.h>*/
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/smb_conn.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/contrib/smbfs/lib/smb/rap.c b/contrib/smbfs/lib/smb/rap.c
new file mode 100644
index 0000000..952f666
--- /dev/null
+++ b/contrib/smbfs/lib/smb/rap.c
@@ -0,0 +1,404 @@
+/*
+ * 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.8 2001/02/24 15:56:05 bp Exp $
+ *
+ * This is very simple implementation of RAP protocol.
+ */
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <sysexits.h>
+
+#include <sys/mchain.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_rap.h>
+
+/*#include <sys/ioctl.h>*/
+
+static int
+smb_rap_parserqparam(const char *s, char **next, int *rlen)
+{
+ char *np;
+ int len, m;
+
+ m = 1;
+ 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, m;
+
+ m = 1;
+ 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, m;
+
+ m = 1;
+ 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;
+}
+
+static int
+smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, long value)
+{
+ char *p = rap->r_npbuf;
+ int len;
+
+ switch (ptype) {
+ case 'L':
+ case 'W':
+ setwle(p, 0, value);
+ len = 2;
+ break;
+ case 'D':
+ setdle(p, 0, value);
+ len = 4;
+ break;
+ case 'b':
+ memset(p, value, 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, len;
+
+ rap = malloc(sizeof(*rap));
+ if (rap == NULL)
+ return NULL;
+ 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);
+ free(rap);
+}
+
+int
+smb_rap_setNparam(struct smb_rap *rap, long 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;
+
+ error = smb_rap_parserpparam(p, &p, &plen);
+ if (error)
+ return error;
+ switch (ptype) {
+ case 'h':
+ *value = letohs(*(u_int16_t*)rap->r_npbuf);
+ 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)
+{
+ u_int16_t *rp, conv;
+ u_int32_t *p32;
+ char *dp, *p = rap->r_nparam;
+ char ptype;
+ int error, rdatacnt, rparamcnt, entries, done, dlen;
+
+ rdatacnt = rap->r_rcvbuflen;
+ rparamcnt = rap->r_plen;
+ error = smb_t2_request(ctx, 0, 0, "\\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 */
+ );
+ if (error)
+ return error;
+ rp = (u_int16_t*)rap->r_pbuf;
+ rap->r_result = letohs(*rp++);
+ conv = letohs(*rp++);
+ rap->r_npbuf = (char*)rp;
+ rap->r_entries = entries = 0;
+ done = 0;
+ while (!done && *p) {
+ ptype = *p;
+ switch (ptype) {
+ case 'e':
+ rap->r_entries = entries = letohs(*(u_int16_t*)rap->r_npbuf);
+ rap->r_npbuf += 2;
+ p++;
+ break;
+ default:
+ done = 1;
+ }
+/* error = smb_rap_parserpparam(p, &p, &plen);
+ if (error) {
+ smb_error("reply parameter mismath %s", 0, p);
+ return EBADRPC;
+ }*/
+ }
+ rap->r_nparam = p;
+ /*
+ * In general, unpacking entries we may need to relocate
+ * entries for proper alingning. 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("reply data mismath %s", 0, p);
+ return EBADRPC;
+ }
+ switch (ptype) {
+ case 'z':
+ p32 = (u_int32_t*)dp;
+ *p32 = (*p32 & 0xffff) - conv;
+ break;
+ }
+ dp += 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;
+}
+
+int
+smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer,
+ int cbBuffer, int *pcEntriesRead, int *pcTotalAvail)
+{
+ struct smb_rap *rap;
+ long lval;
+ int error;
+
+ 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;
+ }
+ error = smb_rap_error(rap, error);
+ smb_rap_done(rap);
+ return error;
+}
diff --git a/contrib/smbfs/lib/smb/rcfile.c b/contrib/smbfs/lib/smb/rcfile.c
new file mode 100644
index 0000000..79f6bd7
--- /dev/null
+++ b/contrib/smbfs/lib/smb/rcfile.c
@@ -0,0 +1,499 @@
+/*
+ * 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.5 2001/04/16 12:46:46 bp Exp $
+ */
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <err.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);
+static struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname);
+static struct rcsection *rc_addsect(struct rcfile *rcp, const char *sectname);
+static int rc_freesect(struct rcfile *rcp, struct rcsection *rsp);
+static 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);
+
+
+/*
+ * 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;
+
+ rcp = rc_cachelookup(filename);
+ if (rcp) {
+ *rcfile = rcp;
+ return 0;
+ }
+ f = fopen(filename, mode);
+ if (f == NULL)
+ return errno;
+ 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;
+
+ 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_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 (strcmp(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) {
+ free(p->rk_value);
+ } else {
+ 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);
+ return;
+}
+#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};
+
+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;
+ }
+ }
+ if (state == stSkipToEOL || next == last) {/* ignore long lines */
+ 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) {
+ if (c == ' ' || c == '\t')/* side effect: 'key name='*/
+ continue; /* become 'keyname=' */
+ if (c == '\n') { /* silently ignore ... */
+ state = stNewLine;
+ continue;
+ }
+ if (c != '=') {
+ *next++ = c;
+ continue;
+ }
+ *next = 0;
+ if (rsp == NULL) {
+ fprintf(stderr, "Key '%s' defined before section\n", buf);
+ state = stSkipToEOL;
+ continue;
+ }
+ rkp = rc_sect_addkey(rsp, buf, NULL);
+ next = buf;
+ state = stGetValue;
+ continue;
+ }
+ /* only stGetValue left */
+ if (state != stGetValue) {
+ fprintf(stderr, "Well, I can't parse file '%s'\n",rcp->rf_name);
+ state = stSkipToEOL;
+ }
+ if (c != '\n') {
+ *next++ = c;
+ continue;
+ }
+ *next = 0;
+ rkp->rk_value = strdup(buf);
+ state = stNewLine;
+ rkp = NULL;
+ } /* while */
+ if (c == EOF && state == stGetValue) {
+ *next = 0;
+ rkp->rk_value = strdup(buf);
+ }
+ return;
+}
+
+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) {
+ warnx("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) {
+ warnx("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, "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) {
+ warnx("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)) {
+ warnx("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) {
+ warnx("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) {
+ warnx("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))) {
+ warnx("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/contrib/smbfs/lib/smb/rcfile_priv.h b/contrib/smbfs/lib/smb/rcfile_priv.h
new file mode 100644
index 0000000..5909d0c
--- /dev/null
+++ b/contrib/smbfs/lib/smb/rcfile_priv.h
@@ -0,0 +1,20 @@
+
+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/contrib/smbfs/lib/smb/rq.c b/contrib/smbfs/lib/smb/rq.c
new file mode 100644
index 0000000..c410753
--- /dev/null
+++ b/contrib/smbfs/lib/smb/rq.c
@@ -0,0 +1,179 @@
+/*
+ * 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.7 2001/04/16 04:33:01 bp Exp $
+ */
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <sysexits.h>
+
+#include <sys/mchain.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_rap.h>
+
+
+int
+smb_rq_init(struct smb_ctx *ctx, u_char 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("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;
+
+ 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 *);
+ if (ioctl(rqp->rq_ctx->ct_fd, SMBIOC_REQUEST, &krq) == -1)
+ return errno;
+ mbp->mb_top->m_len = krq.ioc_rwc * 2 + krq.ioc_rbc;
+ rqp->rq_wcount = krq.ioc_rwc;
+ rqp->rq_bcount = krq.ioc_rbc;
+ return 0;
+}
+
+int
+smb_t2_request(struct smb_ctx *ctx, int setup, int setupcount,
+ const char *name,
+ int tparamcnt, void *tparam,
+ int tdatacnt, void *tdata,
+ int *rparamcnt, void *rparam,
+ int *rdatacnt, void *rdata)
+{
+ struct smbioc_t2rq krq;
+
+ bzero(&krq, sizeof(krq));
+ krq.ioc_setup[0] = setup;
+ krq.ioc_setupcnt = setupcount;
+ (const char*)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_rparam = rparam;
+ krq.ioc_rdatacnt = *rdatacnt;
+ krq.ioc_rdata = rdata;
+ if (ioctl(ctx->ct_fd, SMBIOC_T2RQ, &krq) == -1)
+ return errno;
+ *rparamcnt = krq.ioc_rparamcnt;
+ *rdatacnt = krq.ioc_rdatacnt;
+ return 0;
+}
diff --git a/contrib/smbfs/lib/smb/subr.c b/contrib/smbfs/lib/smb/subr.c
new file mode 100644
index 0000000..9541b62
--- /dev/null
+++ b/contrib/smbfs/lib/smb/subr.c
@@ -0,0 +1,243 @@
+/*
+ * 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.11 2001/04/16 04:33:01 bp Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/sysctl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <err.h>
+
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+#include <cflib.h>
+
+extern char *__progname;
+
+static int smblib_initialized;
+
+struct rcfile *smb_rc;
+
+int
+smb_lib_init(void)
+{
+ int error;
+ int kv;
+ size_t kvlen = sizeof(kv);
+
+ if (smblib_initialized)
+ return 0;
+#if __FreeBSD_version > 400000
+ error = sysctlbyname("net.smb.version", &kv, &kvlen, NULL, 0);
+ if (error) {
+ warnx("%s: can't find kernel module\n", __FUNCTION__);
+ return error;
+ }
+ if (NSMB_VERSION != kv) {
+ warnx("%s: kernel module version(%d) don't match library(%d).\n", __FUNCTION__, kv, NSMB_VERSION);
+ return EINVAL;
+ }
+#endif
+ if ((error = nls_setlocale("")) != 0) {
+ warnx("%s: can't initialise locale\n", __FUNCTION__);
+ return error;
+ }
+ smblib_initialized++;
+ return 0;
+}
+
+/*
+ * 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 = error & SMB_ERRTYPE_MASK;
+
+ fprintf(stderr, "%s: ", __progname);
+ va_start(ap, error);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ if (error == -1)
+ error = errno;
+ else
+ error &= ~SMB_ERRTYPE_MASK;
+ switch (errtype) {
+ case SMB_SYS_ERROR:
+ if (error)
+ fprintf(stderr, ": syserr = %s\n", 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;
+}
+
+/*
+ * first read ~/.smbrc, next try to merge SMB_CFG_FILE
+ */
+int
+smb_open_rcfile(void)
+{
+ char *home, *fn;
+ int error;
+
+ home = getenv("HOME");
+ if (home) {
+ fn = malloc(strlen(home) + 20);
+ sprintf(fn, "%s/.nsmbrc", home);
+ error = rc_open(fn, "r", &smb_rc);
+ free(fn);
+ }
+ error = rc_merge(SMB_CFG_FILE, &smb_rc);
+ if (smb_rc == NULL) {
+ printf("Warning: no cfg file(s) found.\n");
+ return ENOENT;
+ }
+ return 0;
+}
+
+void *
+smb_dumptree(void)
+{
+ size_t len;
+ void *p;
+ int error;
+
+ error = sysctlbyname("net.smb.treedump", NULL, &len, NULL, 0);
+ if (error)
+ return NULL;
+ p = malloc(len);
+ if (p == NULL)
+ return NULL;
+ error = sysctlbyname("net.smb.treedump", p, &len, NULL, 0);
+ if (error) {
+ free(p);
+ return NULL;
+ }
+ return p;
+}
+
+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;
+}
OpenPOWER on IntegriCloud