Mercurial > illumos > illumos-gate
changeset 6007:d57e38e8fdd1
PSARC 2005/695 CIFS Client on Solaris
PSARC 2007/303 pam_smb_login
PSARC 2008/073 CIFS Client on Solaris - Updates
6651904 CIFS Client - PSARC 2005/695
line wrap: on
line diff
--- a/usr/src/cmd/Makefile.cmd Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/cmd/Makefile.cmd Wed Feb 13 19:51:22 2008 -0800 @@ -243,6 +243,7 @@ ROOTSVCNETWORKNIS= $(ROOTSVCNETWORK)/nis ROOTSVCNETWORKROUTING= $(ROOTSVCNETWORK)/routing ROOTSVCNETWORKRPC= $(ROOTSVCNETWORK)/rpc +ROOTSVCNETWORKSMB= $(ROOTSVCNETWORK)/smb ROOTSVCNETWORKSECURITY= $(ROOTSVCNETWORK)/security ROOTSVCNETWORKSSL= $(ROOTSVCNETWORK)/ssl ROOTSVCNETWORKIPSEC= $(ROOTSVCNETWORK)/ipsec @@ -422,6 +423,9 @@ $(ROOTSVCNETWORKSHARES)/%: % $(INS.file) +$(ROOTSVCNETWORKSMB)/%: % + $(INS.file) + $(ROOTSVCAPPLICATION)/%: % $(INS.file)
--- a/usr/src/cmd/devfsadm/misc_link.c Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/cmd/devfsadm/misc_link.c Wed Feb 13 19:51:22 2008 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -175,6 +175,9 @@ { "pseudo", "ddi_pseudo", "dm2s", TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name, }, + { "pseudo", "ddi_pseudo", "nsmb", + TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name, + }, }; DEVFSADM_CREATE_INIT_V0(misc_cbt);
--- a/usr/src/cmd/dfs.cmds/sharectl/Makefile.com Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/cmd/dfs.cmds/sharectl/Makefile.com Wed Feb 13 19:51:22 2008 -0800 @@ -21,7 +21,7 @@ # # ident "%Z%%M% %I% %E% SMI" # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. #
--- a/usr/src/cmd/dfs.cmds/sharectl/sharectl.c Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/cmd/dfs.cmds/sharectl/sharectl.c Wed Feb 13 19:51:22 2008 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -109,6 +109,9 @@ case USAGE_CTL_STATUS: ret = gettext("status [-h | proto ...]"); break; + case USAGE_CTL_DELSECT: + ret = gettext("delsect [-h] section proto"); + break; } return (ret); } @@ -121,6 +124,10 @@ struct options *optlist = NULL; int ret = SA_OK; int c; + sa_protocol_properties_t propset, propsect; + sa_property_t prop; + char *section, *value, *name; + int first = 1; while ((c = getopt(argc, argv, "?hp:")) != EOF) { switch (c) { @@ -153,73 +160,96 @@ } proto = argv[optind]; - if (sa_valid_protocol(proto)) { - sa_protocol_properties_t propset; - propset = sa_proto_get_properties(proto); - if (propset != NULL) { - sa_property_t prop; - char *value; - char *name; - - if (optlist == NULL) { - /* - * Display all known properties for - * this protocol. - */ - for (prop = sa_get_protocol_property(propset, - NULL); - prop != NULL; - prop = sa_get_next_protocol_property( - prop)) { + if (!sa_valid_protocol(proto)) { + (void) printf(gettext("Invalid protocol specified: %s\n"), + proto); + return (SA_INVALID_PROTOCOL); + } + propset = sa_proto_get_properties(proto); + if (propset == NULL) + return (ret); - /* - * Get and display the - * property and value. - */ - name = sa_get_property_attr(prop, - "type"); - if (name != NULL) { - value = sa_get_property_attr( - prop, "value"); - (void) printf(gettext( - "%s=%s\n"), name, - value != NULL ? value : ""); - } - if (value != NULL) - sa_free_attr_string(value); - if (name != NULL) - sa_free_attr_string(name); + if (optlist == NULL) { + /* Display all known properties for this protocol */ + for (propsect = sa_get_protocol_section(propset, NULL); + propsect != NULL; + propsect = sa_get_next_protocol_section(propsect, NULL)) { + section = sa_get_property_attr(propsect, + "name"); + /* + * If properties are organized into sections, as + * in the SMB client, print the section name. + */ + if (sa_proto_get_featureset(proto) & + SA_FEATURE_HAS_SECTIONS) { + if (!first) + (void) printf("\n"); + first = 0; + (void) printf("[%s]\n", section); + } + /* Display properties for this section */ + for (prop = sa_get_protocol_property(propsect, NULL); + prop != NULL; + prop = sa_get_next_protocol_property(prop, NULL)) { + + /* get and display the property and value */ + name = sa_get_property_attr(prop, "type"); + if (name != NULL) { + value = sa_get_property_attr(prop, + "value"); + (void) printf(gettext("%s=%s\n"), name, + value != NULL ? value : ""); } - } else { - struct options *opt; - /* list the specified option(s) */ - for (opt = optlist; - opt != NULL; - opt = opt->next) { - prop = sa_get_protocol_property( - propset, opt->optname); - if (prop != NULL) { - value = sa_get_property_attr( - prop, "value"); - (void) printf(gettext( - "%s=%s\n"), - opt->optname, - value != NULL ? - value : ""); - sa_free_attr_string(value); - } else { - (void) printf(gettext( - "%s: not defined\n"), - opt->optname); - ret = SA_NO_SUCH_PROP; - } - } + if (value != NULL) + sa_free_attr_string(value); + if (name != NULL) + sa_free_attr_string(name); } } } else { - (void) printf(gettext("Invalid protocol specified: %s\n"), - proto); - ret = SA_INVALID_PROTOCOL; + struct options *opt; + + /* list the specified option(s) */ + for (opt = optlist; opt != NULL; opt = opt->next) { + int printed = 0; + + for (propsect = sa_get_protocol_section(propset, NULL); + propsect != NULL; + propsect = sa_get_next_protocol_section(propsect, + NULL)) { + + section = sa_get_property_attr(propsect, + "name"); + for (prop = sa_get_protocol_property(propsect, + opt->optname); + prop != NULL; + prop = sa_get_next_protocol_property( + propsect, opt->optname)) { + value = sa_get_property_attr(prop, + "value"); + if (sa_proto_get_featureset(proto) & + SA_FEATURE_HAS_SECTIONS) { + (void) printf( + gettext("[%s] %s=%s\n"), + section, opt->optname, + value != NULL ? value : ""); + sa_free_attr_string(section); + } else { + (void) printf( + gettext("%s=%s\n"), + opt->optname, + value != NULL ? value : ""); + } + sa_free_attr_string(value); + printed = 1; + } + } + if (!printed) { + (void) printf(gettext("%s: not defined\n"), + opt->optname); + ret = SA_NO_SUCH_PROP; + } + } } return (ret); } @@ -230,9 +260,12 @@ { char *proto = NULL; struct options *optlist = NULL; + sa_protocol_properties_t propsect; int ret = SA_OK; int c; + int err; sa_protocol_properties_t propset; + sa_property_t prop; while ((c = getopt(argc, argv, "?hp:")) != EOF) { switch (c) { @@ -271,53 +304,71 @@ return (SA_INVALID_PROTOCOL); } propset = sa_proto_get_properties(proto); - if (propset != NULL) { - sa_property_t prop; - int err; - if (optlist == NULL) { - (void) printf(gettext("usage: %s\n"), - sc_get_usage(USAGE_CTL_SET)); - (void) printf(gettext( - "\tat least one property and value " - "must be specified\n")); - } else { - struct options *opt; - /* list the specified option(s) */ - for (opt = optlist; - opt != NULL; - opt = opt->next) { - prop = sa_get_protocol_property( - propset, opt->optname); - if (prop != NULL) { - /* - * "err" is used in order to - * prevent setting ret to - * SA_OK if there has been a - * real error. We want to be - * able to return an error - * status on exit in that - * case. Error messages are - * printed for each error, so - * we only care on exit that - * there was an error and not - * the specific error value. - */ - err = sa_set_protocol_property( - prop, opt->optvalue); - if (err != SA_OK) { - (void) printf(gettext( - "Could not set property" - " %s: %s\n"), - opt->optname, - sa_errorstr(err)); - ret = err; - } - } else { + if (propset == NULL) + return (ret); + + if (optlist == NULL) { + (void) printf(gettext("usage: %s\n"), + sc_get_usage(USAGE_CTL_SET)); + (void) printf(gettext( + "\tat least one property and value " + "must be specified\n")); + } else { + struct options *opt; + char *section = NULL; + /* fetch and change the specified option(s) */ + for (opt = optlist; opt != NULL; opt = opt->next) { + if (strncmp("section", opt->optname, 7) == 0) { + if (section != NULL) + free(section); + section = strdup(opt->optvalue); + continue; + } + if (sa_proto_get_featureset(proto) & + SA_FEATURE_HAS_SECTIONS) { + propsect = sa_get_protocol_section(propset, + section); + prop = sa_get_protocol_property(propsect, + opt->optname); + } else { + prop = sa_get_protocol_property(propset, + opt->optname); + } + if (prop == NULL && sa_proto_get_featureset(proto) & + SA_FEATURE_ADD_PROPERTIES) { + sa_property_t sect; + sect = sa_create_section(section, NULL); + sa_set_section_attr(sect, "type", proto); + (void) sa_add_protocol_property(propset, sect); + prop = sa_create_property( + opt->optname, opt->optvalue); + (void) sa_add_protocol_property(sect, prop); + } + if (prop != NULL) { + /* + * "err" is used in order to prevent + * setting ret to SA_OK if there has + * been a real error. We want to be + * able to return an error status on + * exit in that case. Error messages + * are printed for each error, so we + * only care on exit that there was an + * error and not the specific error + * value. + */ + err = sa_set_protocol_property(prop, section, + opt->optvalue); + if (err != SA_OK) { (void) printf(gettext( - "%s: not defined\n"), - opt->optname); - ret = SA_NO_SUCH_PROP; + "Could not set property" + " %s: %s\n"), + opt->optname, sa_errorstr(err)); + ret = err; } + } else { + (void) printf(gettext("%s: not defined\n"), + opt->optname); + ret = SA_NO_SUCH_PROP; } } } @@ -395,10 +446,78 @@ return (ret); } +/*ARGSUSED*/ +static int +sc_delsect(sa_handle_t handle, int flags, int argc, char *argv[]) +{ + char *proto = NULL; + char *section = NULL; + sa_protocol_properties_t propset; + sa_protocol_properties_t propsect; + int ret = SA_OK; + int c; + + while ((c = getopt(argc, argv, "?h")) != EOF) { + switch (c) { + default: + ret = SA_SYNTAX_ERR; + /*FALLTHROUGH*/ + case '?': + case 'h': + (void) printf(gettext("usage: %s\n"), + sc_get_usage(USAGE_CTL_DELSECT)); + return (ret); + } + /*NOTREACHED*/ + } + + section = argv[optind++]; + + if (optind >= argc) { + (void) printf(gettext("usage: %s\n"), + sc_get_usage(USAGE_CTL_DELSECT)); + (void) printf(gettext( + "\tsection and protocol must be specified.\n")); + return (SA_INVALID_PROTOCOL); + } + + proto = argv[optind]; + if (!sa_valid_protocol(proto)) { + (void) printf(gettext("Invalid protocol specified: %s\n"), + proto); + return (SA_INVALID_PROTOCOL); + } + + if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { + (void) printf(gettext("Protocol %s does not have sections\n"), + section, proto); + return (SA_NOT_SUPPORTED); + } + + propset = sa_proto_get_properties(proto); + if (propset == NULL) { + (void) printf(gettext("Cannot get properties for %s\n"), + proto); + return (SA_NO_PROPERTIES); + } + + propsect = sa_get_protocol_section(propset, section); + if (propsect == NULL) { + (void) printf(gettext("Cannot find section %s for proto %s\n"), + section, proto); + return (SA_NO_SUCH_SECTION); + } + + ret = sa_proto_delete_section(proto, section); + + return (ret); +} + static sa_command_t commands[] = { {"get", 0, sc_get, USAGE_CTL_GET}, {"set", 0, sc_set, USAGE_CTL_SET}, {"status", 0, sc_status, USAGE_CTL_STATUS}, + {"delsect", 0, sc_delsect, USAGE_CTL_DELSECT}, {NULL, 0, NULL, 0}, };
--- a/usr/src/cmd/dfs.cmds/sharemgr/sharemgr.h Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/cmd/dfs.cmds/sharemgr/sharemgr.h Wed Feb 13 19:51:22 2008 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -63,7 +63,8 @@ typedef enum { USAGE_CTL_GET, USAGE_CTL_SET, - USAGE_CTL_STATUS + USAGE_CTL_STATUS, + USAGE_CTL_DELSECT } sc_usage_t; typedef struct sa_command {
--- a/usr/src/cmd/fs.d/Makefile Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/cmd/fs.d/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -46,7 +46,7 @@ SUBDIR1= lofs zfs SUBDIR2= dev fd pcfs nfs hsfs proc ctfs udfs ufs tmpfs cachefs \ - autofs mntfs objfs sharefs + autofs mntfs objfs sharefs smbclnt SUBDIRS= $(SUBDIR1) $(SUBDIR2) I18NDIRS= $(SUBDIR2)
--- a/usr/src/cmd/fs.d/autofs/autod_parse.c Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/cmd/fs.d/autofs/autod_parse.c Wed Feb 13 19:51:22 2008 -0800 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -22,7 +21,7 @@ /* * autod_parse.c * - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -160,7 +159,7 @@ trace_mapents("do_mapent_hosts:(return)", mapents); if (hierarchical_sort(mapents, &rootnode, key, mapname) - != PARSE_OK) + != PARSE_OK) goto parse_error; } else { /* @@ -250,13 +249,13 @@ if (macro_expand(key, lp, lq, LINESZ)) { syslog(LOG_ERR, "mapline_to_mapent: map %s: line too long (max %d chars)", - mapname, LINESZ - 1); + mapname, LINESZ - 1); return (PARSE_ERROR); } if (trace > 3 && (strcmp(ml->linebuf, lp) != 0)) trace_prt(1, - " mapline_to_mapent: (expanded) mapline (%s,%s)\n", - ml->linebuf, ml->lineqbuf); + " mapline_to_mapent: (expanded) mapline (%s,%s)\n", + ml->linebuf, ml->lineqbuf); /* init the head of mapentry list to null */ *mapents = NULL; @@ -277,7 +276,11 @@ } else strcpy(defaultopts, mapopts); - implied = *w != '/'; /* implied is 1 only if '/' is implicit */ + /* + * implied is true if there is no '/' (the usual NFS case) + * or if there are two slashes (the smbfs case) + */ + implied = ((*w != '/') || (*(w+1) == '/')); while (*w == '/' || implied) { mp = me; if ((me = (struct mapent *)malloc(sizeof (*me))) == NULL) @@ -340,7 +343,7 @@ if (w[0] == '\0' || w[0] == '-') { syslog(LOG_ERR, "mapline_to_mapent: bad location=%s map=%s key=%s", - w, mapname, key); + w, mapname, key); return (PARSE_ERROR); } @@ -474,8 +477,8 @@ * Add a new one */ if ((rc = alloc_hiernode - (&newnode, dirname)) - != PARSE_OK) + (&newnode, dirname)) + != PARSE_OK) return (rc); prevnode->leveldir = newnode; prevnode = newnode; @@ -503,7 +506,7 @@ /* duplicate mntpoint found */ syslog(LOG_ERR, "hierarchical_sort: duplicate mntpnt map=%s key=%s", - mapname, key); + mapname, key); return (PARSE_ERROR); } @@ -542,17 +545,17 @@ if (me != NULL) { /* not all nodes point to a mapentry */ me->map_err = err; if ((rc = set_mapent_opts(me, me->map_mntopts, - defaultopts, mapopts)) != PARSE_OK) + defaultopts, mapopts)) != PARSE_OK) return (rc); } /* push the options to subdirs */ if (node->subdir != NULL) { if (node->mapent && strcmp(node->mapent->map_fstype, - MNTTYPE_AUTOFS) == 0) + MNTTYPE_AUTOFS) == 0) err = MAPENT_UATFS; if ((rc = push_options(node->subdir, defaultopts, - mapopts, err)) != PARSE_OK) + mapopts, err)) != PARSE_OK) return (rc); } node = node->leveldir; @@ -623,7 +626,7 @@ p += strlen(BACKFSTYPE_EQ); if (strncmp(p, MNTTYPE_NFS, len) == 0 && - (p[len] == '\0' || p[len] == ',')) { + (p[len] == '\0' || p[len] == ',')) { /* * Cached nfs mount */ @@ -638,7 +641,7 @@ * more option pushing work. */ if (fstype_opt == TRUE && - (strcmp(me->map_mntopts, NO_OPTS) == 0)) { + (strcmp(me->map_mntopts, NO_OPTS) == 0)) { free(me->map_mntopts); if ((rc = fstype_opts(me, opts, defaultopts, mapopts)) != PARSE_OK) @@ -647,7 +650,7 @@ done: if (((me->map_fstype = strdup(fstype)) == NULL) || - ((me->map_mounter = strdup(mounter)) == NULL)) { + ((me->map_mounter = strdup(mounter)) == NULL)) { if (me->map_fstype != NULL) free(me->map_fstype); syslog(LOG_ERR, "set_mapent_opts: No memory"); @@ -773,7 +776,7 @@ * at one level below the rootnode given by subdir. */ if ((rc = set_and_fake_mapent_mntlevel(rootnode, subdir, key, mapname, - &faked_mapents, isdirect, mapopts, mount_access)) != PARSE_OK) + &faked_mapents, isdirect, mapopts, mount_access)) != PARSE_OK) return (rc); /* @@ -791,7 +794,7 @@ me = *mapents; while (me != NULL) { if ((me->map_mntlevel == -1) || (me->map_err) || - (mount_access == FALSE && me->map_mntlevel == 0)) { + (mount_access == FALSE && me->map_mntlevel == 0)) { /* * syslog any errors and free entry */ @@ -827,8 +830,8 @@ * to autonodes */ if (me->map_mntlevel == 1 && - (strcmp(me->map_fstype, MNTTYPE_AUTOFS) != 0) && - (me->map_faked != TRUE)) { + (strcmp(me->map_fstype, MNTTYPE_AUTOFS) != 0) && + (me->map_faked != TRUE)) { if ((rc = convert_mapent_to_automount(me, mapname, mapopts)) != PARSE_OK) return (rc); @@ -877,7 +880,7 @@ * contains no '/' at the end. Took some mucking to get that right. */ if ((rc = get_dir_from_path(dirname, &subdir_child, sizeof (dirname))) - != PARSE_OK) + != PARSE_OK) return (rc); if (dirname[0] != '\0') @@ -897,7 +900,7 @@ return (rc); if (dirname[0] != '\0') sprintf(traversed_path, "%s/%s", - traversed_path, dirname); + traversed_path, dirname); } else { /* try next leveldir */ @@ -922,14 +925,14 @@ if (prevnode->mapent != NULL && mount_access == TRUE) { if (trace > 3) trace_prt(1, " node mountpoint %s\t travpath=%s\n", - prevnode->mapent->map_mntpnt, traversed_path); + prevnode->mapent->map_mntpnt, traversed_path); /* * Copy traversed path map_mntpnt to get rid of any extra * '/' the map entry may contain. */ if (strlen(prevnode->mapent->map_mntpnt) < - strlen(traversed_path)) { /* sanity check */ + strlen(traversed_path)) { /* sanity check */ if (verbose) syslog(LOG_ERR, "set_and_fake_mapent_mntlevel: path=%s error", @@ -948,7 +951,7 @@ } else if (currnode != NULL) { if (trace > 3) trace_prt(1, " No rootnode, travpath=%s\n", - traversed_path); + traversed_path); if ((rc = mark_and_fake_level1_noroot(currnode, traversed_path, key, mapname, faked_mapents, isdirect, mapopts)) != PARSE_OK) @@ -988,7 +991,7 @@ sprintf(w, "%s/%s", traversed_path, node->dirname); if (mark_level1_root(node->subdir, w) - == PARSE_ERROR) + == PARSE_ERROR) return (PARSE_ERROR); } else { if (verbose) { @@ -1079,7 +1082,7 @@ (void) memset((char *)me, 0, sizeof (*me)); if ((me->map_fs = (struct mapfs *) - malloc(sizeof (struct mapfs))) == NULL) + malloc(sizeof (struct mapfs))) == NULL) return (ENOMEM); (void) memset(me->map_fs, 0, sizeof (struct mapfs)); @@ -1092,14 +1095,14 @@ me->map_root = strdup(w1); sprintf(faked_map_mntpnt, "%s/%s", traversed_path, - node->dirname); + node->dirname); me->map_mntpnt = strdup(faked_map_mntpnt); me->map_fstype = strdup(MNTTYPE_AUTOFS); me->map_mounter = strdup(MNTTYPE_AUTOFS); /* set options */ if ((rc = automount_opts(&me->map_mntopts, mapopts)) - != PARSE_OK) + != PARSE_OK) return (rc); me->map_fs->mfs_dir = strdup(mapname); me->map_mntlevel = 1; @@ -1190,7 +1193,7 @@ alloc_failed: syslog(LOG_ERR, - "convert_mapent_to_automount: Memory allocation failed"); + "convert_mapent_to_automount: Memory allocation failed"); return (ENOMEM); } @@ -1215,7 +1218,7 @@ if (len > AUTOFS_MAXOPTSLEN) { syslog(LOG_ERR, "option string %s too long (max=%d)", mapopts, - AUTOFS_MAXOPTSLEN-8); + AUTOFS_MAXOPTSLEN-8); return (PARSE_ERROR); } @@ -1277,10 +1280,10 @@ bufq = ""; if (strcmp(me->map_fstype, MNTTYPE_NFS) == 0) { err = parse_nfs(mapname, me, me->map_fsw, - me->map_fswq, &bufp, &bufq, wordsz); + me->map_fswq, &bufp, &bufq, wordsz); } else { err = parse_special(me, me->map_fsw, me->map_fswq, - &bufp, &bufq, wordsz); + &bufp, &bufq, wordsz); } if (err != PARSE_OK || *me->map_fsw != '\0' || @@ -1738,24 +1741,24 @@ trace_prt(1, "\n\t%s\n", s); for (me = mapents; me; me = me->map_next) { trace_prt(1, " (%s,%s)\t %s%s -%s\n", - me->map_fstype ? me->map_fstype : "", - me->map_mounter ? me->map_mounter : "", - me->map_root ? me->map_root : "", - me->map_mntpnt ? me->map_mntpnt : "", - me->map_mntopts ? me->map_mntopts : ""); + me->map_fstype ? me->map_fstype : "", + me->map_mounter ? me->map_mounter : "", + me->map_root ? me->map_root : "", + me->map_mntpnt ? me->map_mntpnt : "", + me->map_mntopts ? me->map_mntopts : ""); for (mfs = me->map_fs; mfs; mfs = mfs->mfs_next) trace_prt(0, "\t\t%s:%s\n", - mfs->mfs_host ? mfs->mfs_host: "", - mfs->mfs_dir ? mfs->mfs_dir : ""); + mfs->mfs_host ? mfs->mfs_host: "", + mfs->mfs_dir ? mfs->mfs_dir : ""); trace_prt(1, "\tme->map_fsw=%s\n", - me->map_fsw ? me->map_fsw:"", - me->map_fswq ? me->map_fsw:""); + me->map_fsw ? me->map_fsw:"", + me->map_fswq ? me->map_fsw:""); trace_prt(1, "\t mntlevel=%d\t%s\t%s err=%d\n", - me->map_mntlevel, - me->map_modified ? "modify=TRUE":"modify=FALSE", - me->map_faked ? "faked=TRUE":"faked=FALSE", - me->map_err); + me->map_mntlevel, + me->map_modified ? "modify=TRUE":"modify=FALSE", + me->map_faked ? "faked=TRUE":"faked=FALSE", + me->map_err); } } @@ -1778,12 +1781,12 @@ for (i = 0; i < nodelevel; i++) trace_prt(0, "\t"); trace_prt(0, "\t(%s, ", - currnode->dirname ? currnode->dirname :""); + currnode->dirname ? currnode->dirname :""); if (currnode->mapent) { trace_prt(0, "%d, %s)\n", - currnode->mapent->map_mntlevel, - currnode->mapent->map_mntopts ? - currnode->mapent->map_mntopts:""); + currnode->mapent->map_mntlevel, + currnode->mapent->map_mntopts ? + currnode->mapent->map_mntopts:""); } else trace_prt(0, " ,)\n"); @@ -1793,12 +1796,12 @@ for (i = 0; i < nodelevel; i++) trace_prt(0, "\t"); trace_prt(0, "\t(%s, ", - currnode->dirname ? currnode->dirname :""); + currnode->dirname ? currnode->dirname :""); if (currnode->mapent) { trace_prt(0, "%d, %s)\n", - currnode->mapent->map_mntlevel, - currnode->mapent->map_mntopts ? - currnode->mapent->map_mntopts:""); + currnode->mapent->map_mntlevel, + currnode->mapent->map_mntopts ? + currnode->mapent->map_mntopts:""); } else trace_prt(0, ", )\n");
--- a/usr/src/cmd/fs.d/mount.c Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/cmd/fs.d/mount.c Wed Feb 13 19:51:22 2008 -0800 @@ -23,7 +23,7 @@ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -220,11 +220,11 @@ int main(int argc, char *argv[]) { - char *special, /* argument of special/resource */ - *mountp, /* argument of mount directory */ - *fstype, /* wherein the fstype name is filled */ - *newargv[ARGV_MAX], /* arg list for specific command */ - *farg = NULL, *Farg = NULL; + char *special, /* argument of special/resource */ + *mountp, /* argument of mount directory */ + *fstype, /* wherein the fstype name is filled */ + *newargv[ARGV_MAX], /* arg list for specific command */ + *farg = NULL, *Farg = NULL; int ii, ret, cc, fscnt; struct stat64 stbuf; struct vfstab vget, vref; @@ -317,8 +317,8 @@ /* pv mututally exclusive */ if (pflg + vflg + aflg > 1) { fprintf(stderr, gettext - ("%s: -a, -p, and -v are mutually exclusive\n"), - myname); + ("%s: -a, -p, and -v are mutually exclusive\n"), + myname); usage(); } @@ -328,14 +328,14 @@ */ if (aflg && Oflg) { fprintf(stderr, gettext - ("%s: -a and -O are mutually exclusive\n"), myname); + ("%s: -a and -O are mutually exclusive\n"), myname); usage(); } /* dfF mutually exclusive */ if (fflg + Fflg > 1) { fprintf(stderr, gettext - ("%s: More than one FSType specified\n"), myname); + ("%s: More than one FSType specified\n"), myname); usage(); } @@ -425,10 +425,10 @@ mountp == NULL) { if ((fd = fopen(vfstab, "r")) == NULL) { if (fstype == NULL || special == NULL || - mountp == NULL) { + mountp == NULL) { fprintf(stderr, gettext( - "%s: Cannot open %s\n"), - myname, vfstab); + "%s: Cannot open %s\n"), + myname, vfstab); exit(1); } else { /* @@ -455,7 +455,8 @@ special = vref.vfs_special = mountp; mountp = vref.vfs_mountp = NULL; /* skip erroneous lines; they were reported above */ - while ((ret = getvfsany(fd, &vget, &vref)) > 0); + while ((ret = getvfsany(fd, &vget, &vref)) > 0) + ; } fclose(fd); @@ -474,20 +475,20 @@ } else if (special == NULL) { if (stat64(mountp, &stbuf) == -1) { fprintf(stderr, gettext("%s: cannot stat %s\n"), - myname, mountp); + myname, mountp); exit(2); } if (((mode = (stbuf.st_mode & S_IFMT)) == S_IFBLK) || - (mode == S_IFCHR)) { + (mode == S_IFCHR)) { fprintf(stderr, gettext("%s: mount point cannot be determined\n"), - myname); + myname); exit(1); } else { fprintf(stderr, gettext("%s: special cannot be determined\n"), - myname); + myname); exit(1); } } else if (fstype == NULL) @@ -544,18 +545,18 @@ { fprintf(stderr, gettext("Usage:\n%s [-v | -p]\n"), myname); fprintf(stderr, gettext( - "%s [-F FSType] [-V] [current_options] [-o specific_options]"), - myname); + "%s [-F FSType] [-V] [current_options] [-o specific_options]"), + myname); fprintf(stderr, gettext("\n\t{special | mount_point}\n")); fprintf(stderr, gettext( - "%s [-F FSType] [-V] [current_options] [-o specific_options]"), - myname); + "%s [-F FSType] [-V] [current_options] [-o specific_options]"), + myname); fprintf(stderr, gettext("\n\tspecial mount_point\n")); fprintf(stderr, gettext( "%s -a [-F FSType ] [-V] [current_options] [-o specific_options]\n"), - myname); + myname); fprintf(stderr, gettext("\t[mount_point ...]\n")); exit(1); @@ -605,7 +606,7 @@ } rfp = fopen(REMOTE, "r"); while ((ret = getextmntent(fd, &mget, sizeof (struct extmnttab))) - == 0) { + == 0) { if (ignore(mget.mnt_mntopts)) continue; if (mget.mnt_special && mget.mnt_mountp && @@ -615,26 +616,26 @@ if (pflg) { elide_dev(mget.mnt_mntopts); printf("%s - %s %s - no %s\n", - mget.mnt_special, - mget.mnt_mountp, - mget.mnt_fstype, - mget.mnt_mntopts != NULL ? - mget.mnt_mntopts : "-"); + mget.mnt_special, + mget.mnt_mountp, + mget.mnt_fstype, + mget.mnt_mntopts != NULL ? + mget.mnt_mntopts : "-"); } else if (vflg) { printf("%s on %s type %s %s%s on %s", - mget.mnt_special, - mget.mnt_mountp, - mget.mnt_fstype, - remote(mget.mnt_fstype, rfp), - flags(mget.mnt_mntopts, NEW), - time_buf); + mget.mnt_special, + mget.mnt_mountp, + mget.mnt_fstype, + remote(mget.mnt_fstype, rfp), + flags(mget.mnt_mntopts, NEW), + time_buf); } else printf("%s on %s %s%s on %s", - mget.mnt_mountp, - mget.mnt_special, - remote(mget.mnt_fstype, rfp), - flags(mget.mnt_mntopts, OLD), - time_buf); + mget.mnt_mountp, + mget.mnt_special, + remote(mget.mnt_fstype, rfp), + flags(mget.mnt_mntopts, OLD), + time_buf); } } if (ret > 0) @@ -731,7 +732,7 @@ extern char *strtok(); if (rfp == NULL || fstype == NULL || - strlen(fstype) > (size_t)FSTYPE_MAX) + strlen(fstype) > (size_t)FSTYPE_MAX) return (""); /* not a remote */ rewind(rfp); while (fgets(buf, sizeof (buf), rfp) != NULL) { @@ -752,22 +753,22 @@ case VFS_TOOLONG: fprintf(stderr, gettext("%s: Warning: Line in vfstab for \"%s\" exceeds %d characters\n"), - myname, special, VFS_LINE_MAX-1); + myname, special, VFS_LINE_MAX-1); break; case VFS_TOOFEW: fprintf(stderr, gettext("%s: Warning: Line for \"%s\" in vfstab has too few entries\n"), - myname, special); + myname, special); break; case VFS_TOOMANY: fprintf(stderr, gettext("%s: Warning: Line for \"%s\" in vfstab has too many entries\n"), - myname, special); + myname, special); break; default: fprintf(stderr, gettext( - "%s: Warning: Error in line for \"%s\" in vfstab\n"), - myname, special); + "%s: Warning: Error in line for \"%s\" in vfstab\n"), + myname, special); } } @@ -777,18 +778,18 @@ switch (flag) { case MNT_TOOLONG: fprintf(stderr, - gettext("%s: Line in mnttab exceeds %d characters\n"), - myname, MNT_LINE_MAX-2); + gettext("%s: Line in mnttab exceeds %d characters\n"), + myname, MNT_LINE_MAX-2); break; case MNT_TOOFEW: fprintf(stderr, - gettext("%s: Line in mnttab has too few entries\n"), - myname); + gettext("%s: Line in mnttab has too few entries\n"), + myname); break; case MNT_TOOMANY: fprintf(stderr, - gettext("%s: Line in mnttab has too many entries\n"), - myname); + gettext("%s: Line in mnttab has too many entries\n"), + myname); break; } exit(1); @@ -802,6 +803,13 @@ char *vfs_path = VFS_PATH; char *alt_path = ALT_PATH; int i; + int smbfs; + + /* + * Special case smbfs file system. + * Execute command in profile if possible. + */ + smbfs = strcmp(fstype, "smbfs") == 0; /* build the full pathname of the fstype dependent command. */ sprintf(full_path, "%s/%s/%s", vfs_path, fstype, myname); @@ -824,11 +832,23 @@ * '..mount: not found' message when '/usr' is mounted */ if (access(full_path, 0) == 0) { + if (smbfs) { + /* + * Run mount_smbfs(1m) with pfexec so that we can + * add sys_mount privilege, (via exec_attr, etc.) + * allowing normal users to mount on any directory + * they own. + */ + newargv[0] = "pfexec"; + newargv[1] = full_path; + execv("/usr/bin/pfexec", &newargv[0]); + newargv[1] = myname; + } execv(full_path, &newargv[1]); if (errno == EACCES) { fprintf(stderr, gettext("%s: Cannot execute %s - permission denied\n"), - myname, full_path); + myname, full_path); } if (errno == ENOEXEC) { newargv[0] = "sh"; @@ -836,11 +856,17 @@ execv("/sbin/sh", &newargv[0]); } } + if (smbfs) { + newargv[0] = "pfexec"; + newargv[1] = alter_path; + execv("/usr/bin/pfexec", &newargv[0]); + newargv[1] = myname; + } execv(alter_path, &newargv[1]); if (errno == EACCES) { fprintf(stderr, gettext( - "%s: Cannot execute %s - permission denied\n"), - myname, alter_path); + "%s: Cannot execute %s - permission denied\n"), + myname, alter_path); exit(1); } if (errno == ENOEXEC) { @@ -849,8 +875,8 @@ execv("/sbin/sh", &newargv[0]); } fprintf(stderr, - gettext("%s: Operation not applicable to FSType %s\n"), - myname, fstype); + gettext("%s: Operation not applicable to FSType %s\n"), + myname, fstype); exit(1); } @@ -954,7 +980,7 @@ return (0); fprintf(stderr, gettext("%s: No valid entries found in %s\n"), - myname, vfstab); + myname, vfstab); return (1); } @@ -966,7 +992,7 @@ */ if (!lofscnt) qsort((void *)vfsarray, vfsarraysize, sizeof (vfsent_t *), - mlevelcmp); + mlevelcmp); /* * Shrink the vfsll linked list down to the new list. This will @@ -1003,7 +1029,7 @@ if ((fp = fopen(vfstab, "r")) == NULL) { fprintf(stderr, gettext("%s: Cannot open %s\n"), - myname, vfstab); + myname, vfstab); exit(1); } @@ -1156,8 +1182,8 @@ if (!found) { fprintf(stderr, gettext( - "%s: Warning: %s not found in %s\n"), - myname, *mntlist, vfstab); + "%s: Warning: %s not found in %s\n"), + myname, *mntlist, vfstab); exitcode = 1; } } @@ -1243,15 +1269,15 @@ */ if (lofscnt == 0) { qsort((void *)vl, cnt, sizeof (vfsent_t *), - mlevelcmp); + mlevelcmp); vp = *vl; } } if (vp->flag & VRPFAILED) { fprintf(stderr, gettext( - "%s: Nonexistent mount point: %s\n"), - myname, vp->v.vfs_mountp); + "%s: Nonexistent mount point: %s\n"), + myname, vp->v.vfs_mountp); vp->flag |= VNOTMOUNTED; exitcode = 1; continue; @@ -1444,7 +1470,7 @@ * This should never happen. */ fprintf(stderr, gettext( - "%s: Unknown child %d\n"), myname, pid); + "%s: Unknown child %d\n"), myname, pid); exitcode = 1; return (ret); } @@ -1494,7 +1520,7 @@ if ((new->v.vfs_mntopts = strdup(specific_opts)) == NULL) nomem(); } else if (vin->vfs_mntopts && - (new->v.vfs_mntopts = strdup(vin->vfs_mntopts)) == NULL) + (new->v.vfs_mntopts = strdup(vin->vfs_mntopts)) == NULL) nomem(); new->order = order; @@ -1576,21 +1602,21 @@ if (strlen(fstype) > (size_t)FSTYPE_MAX) { fprintf(stderr, - gettext("%s: FSType %s exceeds %d characters\n"), - myname, fstype, FSTYPE_MAX); + gettext("%s: FSType %s exceeds %d characters\n"), + myname, fstype, FSTYPE_MAX); return (1); } if (mountp == NULL) { fprintf(stderr, - gettext("%s: Mount point cannot be determined\n"), - myname); + gettext("%s: Mount point cannot be determined\n"), + myname); return (1); } if (*mountp != '/') { fprintf(stderr, gettext( - "%s: Mount point %s is not an absolute pathname.\n"), - myname, mountp); + "%s: Mount point %s is not an absolute pathname.\n"), + myname, mountp); return (1); } /* @@ -1601,12 +1627,12 @@ if (!aflg && stat64(mountp, &stbuf) < 0) { if (errno == ENOENT || errno == ENOTDIR) fprintf(stderr, - gettext("%s: Mount point %s does not exist.\n"), - myname, mountp); + gettext("%s: Mount point %s does not exist.\n"), + myname, mountp); else { fprintf(stderr, - gettext("%s: Cannot stat mount point %s.\n"), - myname, mountp); + gettext("%s: Cannot stat mount point %s.\n"), + myname, mountp); perror(myname); } return (1);
--- a/usr/src/cmd/fs.d/nfs/share/fstypes Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/cmd/fs.d/nfs/share/fstypes Wed Feb 13 19:51:22 2008 -0800 @@ -1,3 +1,4 @@ nfs NFS Utilities autofs AUTOFS Utilities cachefs CACHEFS Utilities +smbfs CIFS Utilities
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/COPYRIGHT Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,31 @@ +#ident "%Z%%M% %I% %E% SMI" + + 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.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/CREDITS Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,11 @@ +#ident "%Z%%M% %I% %E% SMI" + + In the development process next sources were used: + +Various documents from the Microsoft ftp site. +HTML docs published by Thursby Software. + +Special thanks to the Samba team for permission to use their source +code as reference. + +Author - Boris Popov <bp@butya.kz>, <bp@freebsd.org>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,62 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# cmd/fs.d/smbclnt/Makefile +# +# cmd/fs.d/smbclnt contains the CIFS client commands +# + +include $(SRC)/Makefile.master + +SUBDIRS_CATALOG= smbutil mount umount +SUBDIRS= $(SUBDIRS_CATALOG) svc + +# for messaging catalog files +# +POFILES= smbutil/smbutil_all.po mount/mount.po umount/umount.po +POFILE= smbclnt.po + +all:= TARGET= all +install:= TARGET= install +clean:= TARGET= clean +clobber:= TARGET= clobber +lint:= TARGET= lint +catalog:= TARGET= catalog + +.KEEP_STATE: + +.PARALLEL: $(SUBDIRS) + +install clean clobber: $(SUBDIRS) + +all lint catalog: $(SUBDIRS_CATALOG) + $(RM) $(POFILE) + cat $(POFILES) > $(POFILE) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/mount/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,62 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# cmd/fs.d/smbclnt/mount/Makefile +# + +FSTYPE= smbfs +LIBPROG= mount +ROOTFS_PROG= $(LIBPROG) + +include ../../Makefile.fstype + +OBJS= $(LIBPROG).o +SRCS= $(LIBPROG).c $(FSLIBSRC) +POFILE= $(LIBPROG).po + +LDLIBS += -lsmbfs -lscf + +CFLAGS += $(CCVERBOSE) +C99MODE= $(C99_ENABLE) +CPPFLAGS += -I$(SRC)/lib/libsmbfs \ + -I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common + +CLOBBERFILES += $(LIBPROG) + +.KEEP_STATE: + +all: $(ROOTFS_PROG) + +POFILE= mount.po + +catalog: $(POFILE) + +install: $(ROOTLIBFSTYPEPROG) + +lint: lint_SRCS + +clean: + $(RM) $(OBJS) $(POFILE)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/mount/mntopts.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)mntopts.h 8.7 (Berkeley) 3/29/95 + * $Id: mntopts.h,v 1.4 2004/03/19 01:49:47 lindak Exp $ + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _CIFS_MNTOPTS_H +#define _CIFS_MNTOPTS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/vfs.h> +#ifdef UNPORTED +/* In solaris this is defined in proto/root_i386/usr/include/sys/vfs.h */ +struct mntopt { + const char *m_option; /* option name */ + int m_inverse; /* if a negative option, e.g. "dev" */ + int m_flag; /* bit to set, e.g. MNT_RDONLY */ + int m_altloc; /* 1 => set bit in altflags */ +}; +#endif /* UNPORTED */ + +/* User-visible MNT_ flags. */ +#define MOPT_ASYNC { "async", 0, MNT_ASYNC, 0 } +#define MOPT_NODEV { "dev", 1, MNT_NODEV, 0 } +#define MOPT_NOEXEC { "exec", 1, MNT_NOEXEC, 0 } +#define MOPT_NOSUID { "suid", 1, MNT_NOSUID, 0 } +#define MOPT_RDONLY { "rdonly", 0, MNT_RDONLY, 0 } +#define MOPT_SYNC { "sync", 0, MNT_SYNCHRONOUS, 0 } +#define MOPT_UNION { "union", 0, MNT_UNION, 0 } +#define MOPT_USERQUOTA { "userquota", 0, 0, 0 } +#define MOPT_GROUPQUOTA { "groupquota", 0, 0, 0 } +#define MOPT_BROWSE { "browse", 1, MNT_DONTBROWSE, 0 } +#define MOPT_AUTOMOUNTED { "automounted", 0, MNT_AUTOMOUNTED, 0 } + +/* Control flags. */ +#define MOPT_FORCE { "force", 0, MNT_FORCE, 0 } +#define MOPT_UPDATE { "update", 0, MNT_UPDATE, 0 } +#define MOPT_RO { "ro", 0, MNT_RDONLY, 0 } +#define MOPT_RW { "rw", 1, MNT_RDONLY, 0 } + +/* This is parsed by mount(1m), but is ignored by specific mount_*(1m)s. */ +#define MOPT_AUTO { "auto", 0, 0, 0 } + +#define MOPT_FSTAB_COMPAT \ + MOPT_RO, \ + MOPT_RW, \ + MOPT_AUTO + +/* Standard options which all mounts can understand. */ +#define MOPT_STDOPTS \ + MOPT_USERQUOTA, \ + MOPT_GROUPQUOTA, \ + MOPT_FSTAB_COMPAT, \ + MOPT_NODEV, \ + MOPT_NOEXEC, \ + MOPT_NOSUID, \ + MOPT_RDONLY, \ + MOPT_UNION, \ + MOPT_BROWSE, \ + MOPT_AUTOMOUNTED + +void getmntopts(const char *, const mntopt_t *, int *, int *); + +extern int getmnt_silent; + +#ifdef __cplusplus +} +#endif + +#endif /* _CIFS_MNTOPTS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/mount/mount.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,512 @@ +/* + * 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: mount_smbfs.c,v 1.28.44.2 2005/06/02 00:55:41 lindak Exp $ + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/errno.h> +#include <sys/mount.h> + +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <pwd.h> +#include <grp.h> +#include <unistd.h> +#include <ctype.h> +#include <stdlib.h> +#include <errno.h> +#include <err.h> +#include <sysexits.h> +#include <libintl.h> +#include <locale.h> +#include <libscf.h> + +#include <sys/mntent.h> +#include <sys/mnttab.h> + +#include <cflib.h> + +#include <netsmb/smb.h> +#include <netsmb/smb_lib.h> + +#include <sys/fs/smbfs_mount.h> + +#include "mntopts.h" + +static char mount_point[MAXPATHLEN + 1]; +static void usage(void); +static int setsubopt(int, char *, struct smbfs_args *); + +/* smbfs options */ +#define MNTOPT_RETRY "retry" +#define MNTOPT_TIMEOUT "timeout" +#define MNTOPT_DIRPERMS "dirperms" +#define MNTOPT_FILEPERMS "fileperms" +#define MNTOPT_GID "gid" +#define MNTOPT_UID "uid" +#define MNTOPT_NOPROMPT "noprompt" + +#define OPT_RETRY 1 +#define OPT_TIMEOUT 2 +#define OPT_DIRPERMS 3 +#define OPT_FILEPERMS 4 +#define OPT_GID 5 +#define OPT_UID 6 +#define OPT_NOPROMPT 7 + +/* generic VFS options */ +#define OPT_RO 10 +#define OPT_RW 11 +#define OPT_SUID 12 +#define OPT_NOSUID 13 +#define OPT_DEVICES 14 +#define OPT_NODEVICES 15 +#define OPT_SETUID 16 +#define OPT_NOSETUID 17 +#define OPT_EXEC 18 +#define OPT_NOEXEC 19 + +struct smbfsopts { + char *name; + int index; +}; + +struct smbfsopts opts[] = { + {MNTOPT_RETRY, OPT_RETRY}, + {MNTOPT_TIMEOUT, OPT_TIMEOUT}, + {MNTOPT_DIRPERMS, OPT_DIRPERMS}, + {MNTOPT_FILEPERMS, OPT_FILEPERMS}, + {MNTOPT_GID, OPT_GID}, + {MNTOPT_UID, OPT_UID}, + {MNTOPT_NOPROMPT, OPT_NOPROMPT}, + {MNTOPT_RO, OPT_RO}, + {MNTOPT_RW, OPT_RW}, + {MNTOPT_SUID, OPT_SUID}, + {MNTOPT_NOSUID, OPT_NOSUID}, + {MNTOPT_DEVICES, OPT_DEVICES}, + {MNTOPT_NODEVICES, OPT_NODEVICES}, + {MNTOPT_SETUID, OPT_SETUID}, + {MNTOPT_NOSETUID, OPT_NOSETUID}, + {MNTOPT_EXEC, OPT_EXEC}, + {MNTOPT_NOEXEC, OPT_NOEXEC}, + {NULL, 0} +}; + +static int Oflg = 0; /* Overlay mounts */ +static int qflg = 0; /* quiet - don't print warnings on bad options */ +static int ro = 0; /* read-only mount */ +static int noprompt = 0; /* don't prompt for password */ +static int retry = -1; +static int timeout = -1; + +#define RET_ERR 33 +#define SERVICE "svc:/network/smb/client:default" + +int +main(int argc, char *argv[]) +{ + struct smb_ctx sctx, *ctx = &sctx; + struct smbfs_args mdata; + struct stat st; + extern void dropsuid(); + int opt, error, mntflags; + struct mnttab mnt; + struct mnttab *mntp = &mnt; + char optbuf[MAX_MNTOPT_STR]; + static char *fstype = MNTTYPE_SMBFS; + char *env, *state; + + (void) setlocale(LC_ALL, ""); +#if !defined(TEXT_DOMAIN) +#define TEXT_DOMAIN "SYS_TEST" +#endif + (void) textdomain(TEXT_DOMAIN); + dropsuid(); + if (argc == 2) { + if (strcmp(argv[1], "-h") == 0) { + usage(); + } else if (strcmp(argv[1], "-v") == 0) { + errx(EX_OK, gettext("version %d.%d.%d"), + SMBFS_VERSION / 100000, + (SMBFS_VERSION % 10000) / 1000, + (SMBFS_VERSION % 1000) / 100); + } + } + if (argc < 3) + usage(); + + state = smf_get_state(SERVICE); + if (state == NULL || strcmp(state, SCF_STATE_STRING_ONLINE) != 0) { + fprintf(stderr, + gettext("mount_smbfs: service \"%s\" not enabled.\n"), + SERVICE); + exit(1); + } + + /* Debugging support. */ + if ((env = getenv("SMBFS_DEBUG")) != NULL) { + smb_debug = atoi(env); + if (smb_debug < 1) + smb_debug = 1; + } + + error = smb_lib_init(); + if (error) + exit(error); + + mnt.mnt_mntopts = optbuf; + mntflags = MS_DATA; + bzero(&mdata, sizeof (mdata)); + mdata.uid = (uid_t)-1; + mdata.gid = (gid_t)-1; + mdata.caseopt = SMB_CS_NONE; + + error = smb_ctx_init(ctx, argc, argv, SMBL_SHARE, SMBL_SHARE, + SMB_ST_DISK); + if (error) + exit(error); + error = smb_ctx_readrc(ctx); + if (error) + exit(error); + + while ((opt = getopt(argc, argv, "ro:Oq")) != -1) { + switch (opt) { + case 'O': + Oflg++; + break; + + case 'q': + qflg++; + break; + + case 'r': + ro++; + break; + + case 'o': { + char *nextopt, *comma, *equals, *sopt, *soptval; + int i, ret; + + if (strlen(optarg) >= MAX_MNTOPT_STR) { + if (!qflg) + warnx(gettext( + "option string too long")); + exit(RET_ERR); + } + for (sopt = optarg; sopt != NULL; sopt = nextopt) { + comma = strchr(sopt, ','); + if (comma) { + nextopt = comma + 1; + *comma = '\0'; + } else + nextopt = NULL; + equals = strchr(sopt, '='); + if (equals) { + soptval = equals + 1; + *equals = '\0'; + } else + soptval = NULL; + for (i = 0; opts[i].name != NULL; i++) { + if (strcmp(sopt, opts[i].name) == 0) + break; + } + if (opts[i].name == NULL) { + if (equals) + *equals = '='; + if (!qflg) + errx(RET_ERR, gettext( + "Bad option '%s'"), sopt); + if (comma) + *comma = ','; + continue; + } + ret = setsubopt(opts[i].index, soptval, &mdata); + if (ret != 0) + exit(RET_ERR); + if (equals) + *equals = '='; + (void) strcat(mnt.mnt_mntopts, sopt); + if (comma) + *comma = ','; + } + break; + } + + case '?': + default: + usage(); + } + } + + if (Oflg) + mntflags |= MS_OVERLAY; + + if (ro) { + char *p; + + mntflags |= MS_RDONLY; + /* convert "rw"->"ro" */ + if (p = strstr(mntp->mnt_mntopts, "rw")) { + if (*(p+2) == ',' || *(p+2) == '\0') + *(p+1) = 'o'; + } + } + + mnt.mnt_special = argv[optind]; + mnt.mnt_mountp = argv[optind+1]; + + mdata.version = SMBFS_VERSION; /* smbfs mount version */ + + if (optind == argc - 2) + optind++; + + if (optind != argc - 1) + usage(); + realpath(unpercent(argv[optind]), mount_point); + + if (stat(mount_point, &st) == -1) + err(EX_OSERR, gettext("could not find mount point %s"), + mount_point); + if (!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + err(EX_OSERR, gettext("can't mount on %s"), mount_point); + } + + /* + * Darwin takes defaults from the + * mounted-on directory. + * We want the real uid/gid. + * XXX: Is this correct? + */ +#ifdef __sun + if (mdata.uid == (uid_t)-1) + mdata.uid = getuid(); + if (mdata.gid == (gid_t)-1) + mdata.gid = getgid(); +#else + if (mdata.uid == (uid_t)-1) + mdata.uid = st.st_uid; + if (mdata.gid == (gid_t)-1) + mdata.gid = st.st_gid; +#endif + + if (mdata.file_mode == 0) + mdata.file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + if (mdata.dir_mode == 0) { + mdata.dir_mode = mdata.file_mode; + if (mdata.dir_mode & S_IRUSR) + mdata.dir_mode |= S_IXUSR; + if (mdata.dir_mode & S_IRGRP) + mdata.dir_mode |= S_IXGRP; + if (mdata.dir_mode & S_IROTH) + mdata.dir_mode |= S_IXOTH; + } + + /* + * XXX: The driver can fill these in more reliably, + * so why do we set them here? (Just set both = -1) + */ + ctx->ct_ssn.ioc_owner = ctx->ct_sh.ioc_owner = getuid(); + ctx->ct_ssn.ioc_group = ctx->ct_sh.ioc_group = getgid(); + opt = 0; + if (mdata.dir_mode & S_IXGRP) + opt |= SMBM_EXECGRP; + if (mdata.dir_mode & S_IXOTH) + opt |= SMBM_EXECOTH; + ctx->ct_ssn.ioc_rights |= opt; + ctx->ct_sh.ioc_rights |= opt; + if (noprompt) + ctx->ct_flags |= SMBCF_NOPWD; + if (retry != -1) + ctx->ct_ssn.ioc_retrycount = retry; + if (timeout != -1) + ctx->ct_ssn.ioc_timeout = timeout; + + /* + * If we got our password from the keychain and get an + * authorization error, we come back here to obtain a new + * password from user input. + */ +reauth: + error = smb_ctx_resolve(ctx); + if (error) + exit(error); + + mdata.devfd = ctx->ct_fd; /* file descriptor */ + +again: + error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE); + if (error == ENOENT && ctx->ct_origshare) { + strcpy(ctx->ct_sh.ioc_share, ctx->ct_origshare); + free(ctx->ct_origshare); + ctx->ct_origshare = NULL; + goto again; /* try again using share name as given */ + } + if (ctx->ct_flags & SMBCF_KCFOUND && smb_autherr(error)) { + ctx->ct_ssn.ioc_password[0] = '\0'; + smb_error(gettext("main(lookup): bad keychain entry"), 0); + ctx->ct_flags |= SMBCF_KCBAD; + goto reauth; + } + if (error) + exit(error); + + mdata.version = SMBFS_VERSION; + mdata.devfd = ctx->ct_fd; + + if (mount(mntp->mnt_special, mntp->mnt_mountp, + mntflags, fstype, &mdata, sizeof (mdata), + mntp->mnt_mntopts, MAX_MNTOPT_STR) < 0) { + if (errno != ENOENT) { + err(EX_OSERR, gettext("mount_smbfs: %s"), + mntp->mnt_mountp); + } else { + struct stat sb; + if (stat(mntp->mnt_mountp, &sb) < 0 && + errno == ENOENT) + err(EX_OSERR, gettext("mount_smbfs: %s"), + mntp->mnt_mountp); + else + err(EX_OSERR, gettext("mount_smbfs: %s"), + mntp->mnt_special); + + error = smb_ctx_tdis(ctx); + if (error) /* unable to clean up?! */ + exit(error); + } + } + + smb_ctx_done(ctx); + if (error) { + smb_error(gettext("mount error: %s"), error, mount_point); + exit(errno); + } + return (0); +} + +int +setsubopt(int index, char *optarg, struct smbfs_args *mdatap) +{ + struct passwd *pwd; + struct group *grp; + long l; + int err = 0; + char *next; + + switch (index) { + case OPT_RO: + case OPT_RW: + case OPT_SUID: + case OPT_NOSUID: + case OPT_DEVICES: + case OPT_NODEVICES: + case OPT_SETUID: + case OPT_NOSETUID: + case OPT_EXEC: + case OPT_NOEXEC: + /* We don't have to handle generic options here */ + return (0); + case OPT_UID: + pwd = isdigit(optarg[0]) ? + getpwuid(atoi(optarg)) : getpwnam(optarg); + if (pwd == NULL) { + if (!qflg) + warnx(gettext("unknown user '%s'"), optarg); + err = -1; + } else { + mdatap->uid = pwd->pw_uid; + } + break; + case OPT_GID: + grp = isdigit(optarg[0]) ? + getgrgid(atoi(optarg)) : getgrnam(optarg); + if (grp == NULL) { + if (!qflg) + warnx(gettext("unknown group '%s'"), optarg); + err = -1; + } else { + mdatap->gid = grp->gr_gid; + } + break; + case OPT_DIRPERMS: + errno = 0; + l = strtol(optarg, &next, 8); + if (errno || *next != 0) { + if (!qflg) + warnx(gettext( + "invalid value for directory mode")); + err = -1; + } else { + mdatap->dir_mode = l; + } + break; + case OPT_FILEPERMS: + errno = 0; + l = strtol(optarg, &next, 8); + if (errno || *next != 0) { + if (!qflg) + warnx(gettext("invalid value for file mode")); + err = -1; + } else { + mdatap->file_mode = l; + } + break; + case OPT_RETRY: + retry = atoi(optarg); + break; + case OPT_TIMEOUT: + timeout = atoi(optarg); + break; + case OPT_NOPROMPT: + noprompt++; + } + return (err); +} + +static void +usage(void) +{ + fprintf(stderr, "%s\n", + gettext("usage: mount -F smbfs [-Orq] [-o option[,option]]" + " //[workgroup;][user[:password]@]server[/share] path")); + + exit(EX_USAGE); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,65 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# cmd/fs.d/smbclnt/smbutil/Makefile +# + +PROG= smbutil + +include $(SRC)/cmd/Makefile.cmd + +OBJS= smbutil.o login.o lookup.o print.o status.o view.o +SRCS= $(OBJS:%.o=%.c) +POFILE= smbutil_all.po +POFILES= $(OBJS:%.o=%.po) + +C99MODE= $(C99_ENABLE) +CPPFLAGS += -I$(SRC)/lib/libsmbfs \ + -I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common +LDLIBS += -lsmbfs -lnsl + +all: $(PROG) + +$(PROG): $(OBJS) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) + $(POST_PROCESS) + +install: all $(ROOTPROG) + +$(ROOTPROG): $(PROG) + $(INS.file) $(PROG) + +catalog: $(POFILE) + +$(POFILE): $(POFILES) + $(RM) $@ + $(CAT) $(POFILES) > $@ + +clean : + $(RM) $(OBJS) + +clobber: clean + $(RM) $(PROG) $(POFILES)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/smbutil/common.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,39 @@ +#ifndef _SMBUTIL_COMMON_H +#define _SMBUTIL_COMMON_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +#include <stdlib.h> + +int cmd_crypt(int argc, char *argv[]); +int cmd_help(int argc, char *argv[]); +int cmd_login(int argc, char *argv[]); +int cmd_logout(int argc, char *argv[]); +int cmd_logoutall(int argc, char *argv[]); +int cmd_lookup(int argc, char *argv[]); +int cmd_print(int argc, char *argv[]); +int cmd_status(int argc, char *argv[]); +int cmd_view(int argc, char *argv[]); + +/* No crypt_usage? */ +void help_usage(void); +void login_usage(void); +void logout_usage(void); +void logoutall_usage(void); +void lookup_usage(void); +void print_usage(void); +void status_usage(void); +void view_usage(void); + +extern int loadsmbvfs(); + +#ifdef __cplusplus +} +#endif + +#endif /* _SMBUTIL_COMMON_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/smbutil/login.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,274 @@ +/* + * 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: login.c,v 1.8 2004/03/19 01:49:48 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/stat.h> + +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <unistd.h> +#include <err.h> +#include <libintl.h> + +#include <netsmb/smb_lib.h> +#include <netsmb/smb_keychain.h> + +#include "common.h" + +/* defaults */ +static char def_dom[256]; +static char def_usr[256]; +static char tmp_arg[256]; + + +/* + * Parse the string: domuser, which may be any of: + * "user@domain" or "domain/user" or "domain\\user" + * and return pointers to the domain and user parts. + * Modifies the string domuser in-place. Returned + * string pointers are within the string domusr. + */ +int +smbfs_parse_domuser(char *domuser, char **dom, char **usr) +{ + const char sep[] = "@/\\"; + char sc, *p, *s1, *s2; + + p = strpbrk(domuser, sep); + if (p == NULL) { + /* No separators - whole string is the user. */ + *dom = NULL; + *usr = domuser; + return (0); + } + + /* Have two strings. */ + s1 = domuser; + sc = *p; /* Save the sep. char */ + *p++ = '\0'; /* zap it */ + s2 = p; + + /* Enforce just one separator */ + p = strpbrk(s2, sep); + if (p) + return (-1); + + /* + * Now, which order are they? + * "user@domain" or "domain/user" + */ + if (sc == '@') { + *usr = s1; + *dom = s2; + } else { + *dom = s1; + *usr = s2; + } + + return (0); +} + +void +login_usage(void) +{ + printf(gettext("usage: smbutil login [-c] [[domain/]user]\n")); + printf(gettext(" smbutil login [-c] [user[@domain]]\n")); + exit(1); +} + +int +cmd_login(int argc, char *argv[]) +{ + static char prompt[64]; + char *dom, *usr, *pass; + int err, opt; + int check = 0; + + while ((opt = getopt(argc, argv, "c")) != EOF) { + switch (opt) { + + case 'c': /* smbutil login -c ... */ + check = 1; + break; + + default: + login_usage(); + break; + } + } + + dom = usr = NULL; + if (optind < argc) { + strcpy(tmp_arg, argv[optind]); + err = smbfs_parse_domuser(tmp_arg, &dom, &usr); + if (err) + errx(1, gettext("failed to parse %s"), argv[optind]); + optind++; + } + if (optind != argc) + login_usage(); + + if (dom == NULL || usr == NULL) { + err = smbfs_default_dom_usr(NULL, NULL, + def_dom, sizeof (def_dom), + def_usr, sizeof (def_usr)); + if (err) + errx(1, gettext("failed to get defaults")); + } + if (dom == NULL) + dom = def_dom; + else + nls_str_upper(dom, dom); + if (usr == NULL) + usr = def_usr; + + if (check) { + err = smbfs_keychain_chk(dom, usr); + if (!err) + printf(gettext("Keychain entry exists.\n")); + else + printf(gettext("Keychain entry not found.\n")); + return (0); + } + + snprintf(prompt, sizeof (prompt), + gettext("Password for %s/%s:"), dom, usr); + pass = getpassphrase(prompt); + + err = smbfs_keychain_add((uid_t)-1, dom, usr, pass); + if (err) + errx(1, gettext("failed to add keychain entry")); + + return (0); +} + + +void +logout_usage(void) +{ + printf(gettext("usage: smbutil logout [[domain/]user]\n")); + printf(gettext(" smbutil logout [user[@domain]]\n")); + printf(gettext(" smbutil logout -a\n")); + exit(1); +} + +int +cmd_logout(int argc, char *argv[]) +{ + char *dom, *usr; + int err, opt; + + while ((opt = getopt(argc, argv, "a")) != EOF) { + switch (opt) { + + case 'a': /* smbutil logout -a */ + if (optind != argc) + logout_usage(); + err = smbfs_keychain_del_owner(); + if (err) + errx(1, +gettext("failed to delete keychain entries")); + return (0); + + default: + logout_usage(); + break; + } + } + + /* This part is like login. */ + dom = usr = NULL; + if (optind < argc) { + strcpy(tmp_arg, argv[optind]); + err = smbfs_parse_domuser(tmp_arg, &dom, &usr); + if (err) + errx(1, gettext("failed to parse %s"), argv[optind]); + optind++; + } + if (optind != argc) + logout_usage(); + + if (dom == NULL || usr == NULL) { + err = smbfs_default_dom_usr(NULL, NULL, + def_dom, sizeof (def_dom), + def_usr, sizeof (def_usr)); + if (err) + errx(1, gettext("failed to get defaults")); + } + if (dom == NULL) + dom = def_dom; + else + nls_str_upper(dom, dom); + if (usr == NULL) + usr = def_usr; + + err = smbfs_keychain_del((uid_t)-1, dom, usr); + if (err) + errx(1, gettext("failed to delete keychain entry")); + + return (0); +} + + +void +logoutall_usage(void) +{ + printf(gettext("usage: smbutil logoutall\n")); + exit(1); +} + +int +cmd_logoutall(int argc, char *argv[]) +{ + int err; + + if (optind != argc) + logoutall_usage(); + + err = smbfs_keychain_del_everyone(); + if (err == EPERM) { + errx(1, +gettext("You must have super-user privileges to use this sub-command\n")); + } + if (err) { + errx(1, gettext("Failed to delete all keychain entries: %s\n"), + smb_strerror(err)); + } + + return (0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/smbutil/lookup.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,119 @@ +/* + * 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: lookup.c,v 1.1.1.1 2001/06/09 00:28:13 zarzycki Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <stdio.h> +#include <err.h> +#include <unistd.h> +#include <strings.h> +#include <stdlib.h> +#include <sysexits.h> +#include <libintl.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <cflib.h> + +#include <netsmb/netbios.h> +#include <netsmb/smb_lib.h> +#include <netsmb/nb_lib.h> + +#include "common.h" + + +int +cmd_lookup(int argc, char *argv[]) +{ + struct nb_ctx *ctx; + struct sockaddr *sap; + char *hostname; + int error, opt; + + if (argc < 2) + lookup_usage(); + error = nb_ctx_create(&ctx); + if (error) { + smb_error(gettext("unable to create nbcontext"), error); + exit(1); + } + if (smb_open_rcfile(NULL) == 0) { + if (nb_ctx_readrcsection(smb_rc, ctx, "default", 0) != 0) + exit(1); + rc_close(smb_rc); + } + if ((ctx->nb_flags & NBCF_NS_ENABLE) == 0) { + fprintf(stderr, + gettext("nbns_enable=false, cannot do lookup\n")); + exit(1); + } + while ((opt = getopt(argc, argv, "w:")) != EOF) { + switch (opt) { + case 'w': + nb_ctx_setns(ctx, optarg); + break; + default: + lookup_usage(); + /*NOTREACHED*/ + } + } + if (optind >= argc) + lookup_usage(); + if (nb_ctx_resolve(ctx) != 0) + exit(1); + hostname = argv[argc - 1]; + error = nbns_resolvename(hostname, ctx, &sap); + if (error) { + smb_error(gettext("unable to resolve %s"), error, hostname); + exit(1); + } + printf(gettext("Got response from %s\n"), + inet_ntoa(ctx->nb_lastns.sin_addr)); + printf(gettext("IP address of %s: %s\n"), hostname, + inet_ntoa(((struct sockaddr_in *)sap)->sin_addr)); + return (0); +} + + +void +lookup_usage(void) +{ + printf(gettext("usage: smbutil lookup [-w host] name\n")); + exit(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/smbutil/print.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,64 @@ +/* + * 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.7 2004/03/19 01:49:48 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <err.h> +#include <unistd.h> +#include <strings.h> +#include <stdlib.h> +#include <sysexits.h> +#include <libintl.h> + +#include <cflib.h> + +#include <netsmb/smb_lib.h> + +#include "common.h" + + + +void +print_usage(void) +{ + printf(gettext("usage: smbutil print [connection options] //" + "[workgroup;][user[:password]@]" + "server/share\n")); + exit(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/smbutil/smbutil.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,169 @@ +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/time.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <err.h> +#include <sysexits.h> +#include <locale.h> +#include <libintl.h> + +#include <netsmb/smb_lib.h> + +#include "common.h" + +#ifndef EX_DATAERR +#define EX_DATAERR 1 +#endif + +static void help(void); + + +typedef int cmd_fn_t (int argc, char *argv[]); +typedef void cmd_usage_t (void); + +#define CMDFL_NO_KMOD 0x0001 + +static struct commands { + const char *name; + cmd_fn_t *fn; + cmd_usage_t *usage; + int flags; +} commands[] = { + {"crypt", cmd_crypt, NULL, CMDFL_NO_KMOD}, + {"help", cmd_help, help_usage, CMDFL_NO_KMOD}, + {"login", cmd_login, login_usage, 0}, + {"logout", cmd_logout, logout_usage, 0}, + {"logoutall", cmd_logoutall, logoutall_usage, 0}, + {"lookup", cmd_lookup, lookup_usage, CMDFL_NO_KMOD}, + {"status", cmd_status, status_usage, 0}, + {"view", cmd_view, view_usage, 0}, + {NULL, NULL, NULL, 0} +}; + +static struct commands * +lookupcmd(const char *name) +{ + struct commands *cmd; + + for (cmd = commands; cmd->name; cmd++) { + if (strcmp(cmd->name, name) == 0) + return (cmd); + } + return (NULL); +} + +int +cmd_crypt(int argc, char *argv[]) +{ + char *cp, *psw; + + if (argc < 2) + psw = getpassphrase(gettext("Password:")); + else + psw = argv[1]; + /* XXX Better to embed malloc/free in smb_simplecrypt? */ + cp = malloc(4 + 2 * strlen(psw)); + if (cp == NULL) + errx(EX_DATAERR, gettext("out of memory")); + smb_simplecrypt(cp, psw); + printf("%s\n", cp); + free(cp); + return (0); +} + +int +cmd_help(int argc, char *argv[]) +{ + struct commands *cmd; + char *cp; + + if (argc < 2) + help_usage(); + cp = argv[1]; + cmd = lookupcmd(cp); + if (cmd == NULL) + errx(EX_DATAERR, gettext("unknown command %s"), cp); + if (cmd->usage == NULL) + errx(EX_DATAERR, + gettext("no specific help for command %s"), cp); + cmd->usage(); + return (0); +} + +int +main(int argc, char *argv[]) +{ + struct commands *cmd; + char *cp; + int opt; + extern void dropsuid(); + + (void) setlocale(LC_ALL, ""); + (void) textdomain(TEXT_DOMAIN); + + dropsuid(); + + if (argc < 2) + help(); + + while ((opt = getopt(argc, argv, "dhv")) != EOF) { + switch (opt) { + case 'd': + smb_debug++; + break; + case 'h': + help(); + /* NOTREACHED */ + case 'v': + smb_verbose++; + break; + default: + help(); + /* NOTREACHED */ + } + } + if (optind >= argc) + help(); + + cp = argv[optind]; + cmd = lookupcmd(cp); + if (cmd == NULL) + errx(EX_DATAERR, gettext("unknown command %s"), cp); + + if ((cmd->flags & CMDFL_NO_KMOD) == 0 && smb_lib_init() != 0) + exit(1); + + argc -= optind; + argv += optind; + optind = 1; + return (cmd->fn(argc, argv)); +} + +static void +help(void) { + printf("\n"); + printf(gettext("usage: %s [-hv] subcommand [args]\n"), __progname); + printf(gettext("where subcommands are:\n" + " crypt slightly obscure password\n" + " help display help on specified subcommand\n" + /* " lc display active connections\n" */ + " login login to specified host\n" + " logout logout from specified host\n" + " logoutall logout all users (requires privilege)\n" + " lookup resolve NetBIOS name to IP address\n" + /* " print print file to the specified remote printer\n" */ + " status resolve IP address or DNS name to NetBIOS names\n" + " view list resources on specified host\n" + "\n")); + exit(1); +} + +void +help_usage(void) { + printf(gettext("usage: smbutil help command\n")); + exit(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/smbutil/status.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2001, Apple Computer, Inc. + * 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: status.c,v 1.2 2001/08/18 05:44:50 conrad Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <stdio.h> +#include <err.h> +#include <unistd.h> +#include <strings.h> +#include <stdlib.h> +#include <sysexits.h> +#include <libintl.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <cflib.h> + +#include <netsmb/netbios.h> +#include <netsmb/smb_lib.h> +#include <netsmb/nb_lib.h> + +#include "common.h" + + +int +cmd_status(int argc, char *argv[]) +{ + struct nb_ctx *ctx; + struct sockaddr *sap; + char *hostname; + char servername[SMB_MAXSRVNAMELEN + 1]; + char workgroupname[SMB_MAXUSERNAMELEN + 1]; + int error, opt; + + if (argc < 2) + status_usage(); + error = nb_ctx_create(&ctx); + if (error) { + smb_error(gettext("unable to create nbcontext"), error); + exit(1); + } + if (smb_open_rcfile(NULL) == 0) { + if (nb_ctx_readrcsection(smb_rc, ctx, "default", 0) != 0) + exit(1); + rc_close(smb_rc); + } + while ((opt = getopt(argc, argv, "")) != EOF) { + switch (opt) { + default: + status_usage(); + /*NOTREACHED*/ + } + } + if (optind >= argc) + status_usage(); + + hostname = argv[argc - 1]; + error = nb_resolvehost_in(hostname, &sap); + if (error) { + smb_error(gettext( + "unable to resolve DNS hostname %s"), error, hostname); + exit(1); + } + if ((ctx->nb_flags & NBCF_NS_ENABLE) == 0) { + fprintf(stderr, + gettext("nbns_enable=false, cannot get status\n")); + exit(1); + } + servername[0] = (char)0; + workgroupname[0] = (char)0; + error = nbns_getnodestatus(sap, ctx, servername, workgroupname); + if (error) { + smb_error( + gettext("unable to get status from %s"), error, hostname); + exit(1); + } + + if (workgroupname[0]) { + printf(gettext("Workgroup: %s\n"), workgroupname); + } + if (servername[0]) { + printf(gettext("Server: %s\n"), servername); + } + + return (0); +} + + +void +status_usage(void) +{ + printf(gettext("usage: smbutil status hostname\n")); + exit(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/smbutil/view.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,153 @@ +/* + * 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: view.c,v 1.9 2004/12/13 00:25:39 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/stat.h> +#include <stdio.h> +#include <err.h> +#include <unistd.h> +#include <strings.h> +#include <stdlib.h> +#include <sysexits.h> +#include <libintl.h> + +#include <cflib.h> +#include <netsmb/smb_lib.h> +#include <netsmb/smb_netshareenum.h> + +#include "common.h" + +#ifdef I18N /* not defined, put here so xgettext(1) can find strings */ +static char *shtype[] = { + gettext("disk"), + gettext("printer"), + gettext("device"), /* Communications device */ + gettext("IPC"), /* Inter process communication */ + gettext("unknown") +}; +#else +static char *shtype[] = { + "disk", + "printer", + "device", /* Communications device */ + "IPC", /* IPC Inter process communication */ + "unknown" +}; +#endif + +int +cmd_view(int argc, char *argv[]) +{ + struct smb_ctx sctx, *ctx = &sctx; + struct share_info *share_info, *ep; + int error, opt, i, entries, total; + + if (argc < 2) + view_usage(); + error = smb_ctx_init(ctx, argc, argv, SMBL_VC, SMBL_VC, SMB_ST_ANY); + if (error) + exit(error); + error = smb_ctx_readrc(ctx); + if (error) + exit(error); + if (smb_rc) + rc_close(smb_rc); + while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) { + switch (opt) { + case STDPARAM_ARGS: + error = smb_ctx_opt(ctx, opt, optarg); + if (error) + exit(error); + break; + default: + view_usage(); + /*NOTREACHED*/ + } + } +#ifdef APPLE + if (loadsmbvfs()) + fprintf(stderr, gettext("SMB filesystem is not available")); +#endif +reauth: + smb_ctx_setshare(ctx, "IPC$", SMB_ST_ANY); + error = smb_ctx_resolve(ctx); + if (error) + exit(error); + error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE); + if (ctx->ct_flags & SMBCF_KCFOUND && smb_autherr(error)) { + ctx->ct_ssn.ioc_password[0] = '\0'; + goto reauth; + } + if (error) { + smb_error(gettext("could not login to server %s"), + error, ctx->ct_ssn.ioc_srvname); + exit(error); + } + printf(gettext("Share Type Comment\n")); + printf("-------------------------------\n"); + error = smb_netshareenum(ctx, &entries, &total, &share_info); + if (error) { + smb_error(gettext("unable to list resources"), error); + exit(error); + } + for (ep = share_info, i = 0; i < entries; i++, ep++) { + int sti = ep->type & STYPE_MASK; + if (sti > STYPE_UNKNOWN) + sti = STYPE_UNKNOWN; + printf("%-12s %-10s %s\n", ep->netname, + gettext(shtype[sti]), + ep->remark ? ep->remark : ""); + free(ep->netname); + } + printf(gettext("\n%d shares listed from %d available\n"), + entries, total); + free(share_info); + smb_ctx_done(ctx); +#ifdef APPLE + smb_save2keychain(ctx); +#endif + return (0); +} + + +void +view_usage(void) +{ + printf(gettext("usage: smbutil view [connection options] //" + "[workgroup;][user[:password]@]server\n")); + exit(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/svc/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,45 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +MANIFEST= client.xml +SVCMETHOD= smb-client + +include $(SRC)/cmd/Makefile.cmd + +ROOTMANIFESTDIR= $(ROOTSVCNETWORKSMB) + +all lint: + +install: $(ROOTMANIFEST) $(ROOTSVCMETHOD) + +clean: + +clobber: + +check: $(CHKMANIFEST) + +include $(SRC)/cmd/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/svc/client.xml Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,117 @@ +<?xml version="1.0"?> +<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> +<!-- + Copyright 2008 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + + ident "%Z%%M% %I% %E% SMI" + + NOTE: This service manifest is not editable; its contents will + be overwritten by package or patch operations, including + operating system upgrade. Make customizations in a different + file. +--> + +<service_bundle type='manifest' name='SUNWsmbfsr:smb-client'> + +<service + name='network/smb/client' + type='service' + version='1'> + + <create_default_instance enabled='false' /> + + <single_instance /> + + <dependency name='network' + grouping='require_any' + restart_on='error' + type='service'> + <service_fmri value='svc:/milestone/network' /> + </dependency> + + <dependency name='gss' + grouping='optional_all' + restart_on='none' + type='service'> + <service_fmri value='svc:/network/rpc/gss' /> + </dependency> + + <dependency name='name-services' + grouping='require_all' + restart_on='refresh' + type='service'> + <service_fmri value='svc:/milestone/name-services' /> + </dependency> + + <dependent + name='smb-client_multi-user' + grouping='optional_all' + restart_on='none'> + <service_fmri value='svc:/milestone/multi-user' /> + </dependent> + + <!-- + Err on the side of caution for the mountalls in the smb-client + startup script. Don't timeout just because remote servers are + being sluggish. + --> + <exec_method + type='method' + name='start' + exec='/lib/svc/method/smb-client %m' + timeout_seconds='300' /> + + <exec_method + type='method' + name='stop' + exec='/lib/svc/method/smb-client %m' + timeout_seconds='60' /> + + <property_group name='general' type='framework'> + <!-- To Start/Stop/Refresh the service --> + <propval name='action_authorization' type='astring' + value='solaris.smf.manage.smbfs' /> + </property_group> + + <property_group + name='startd' + type='framework'> + <propval name='duration' type='astring' value='transient' /> + </property_group> + + <stability value='Unstable' /> + + <template> + <common_name> + <loctext xml:lang='C'> + SMB client + </loctext> + </common_name> + <documentation> + <manpage title='mount_smbfs' section='1M' + manpath='/usr/share/man' /> + </documentation> + </template> +</service> + +</service_bundle>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/svc/smb-client Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,49 @@ +#!/sbin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +# +# Start/stop client SMB service +# + +. /lib/svc/share/smf_include.sh + +case "$1" in +'start') + + /sbin/mountall -F smbfs + ;; + +'stop') + /sbin/umountall -F smbfs + ;; + +*) + echo "Usage: $0 { start | stop }" + exit 1 + ;; +esac +exit $SMF_EXIT_OK
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/umount/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,67 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# cmd/fs.d/smbclnt/umount/Makefile +# + +FSTYPE= smbfs +LIBPROG= umount +ROOTFS_PROG= $(LIBPROG) + +include ../../Makefile.fstype + +COMMON= $(FSLIB) +OBJS= $(LIBPROG).o $(COMMON) +SRCS= $(LIBPROG).c $(FSLIBSRC) +POFILE= $(LIBPROG).po + +CPPFLAGS += -I../.. -I../lib +CFLAGS += $(CCVERBOSE) + +CLOBBERFILES += $(LIBPROG) + +.KEEP_STATE: + +all: $(ROOTFS_PROG) + +include $(SRC)/cmd/fs.d/Makefile.mount.targ + +# +# Message catalog +# +POFILE= umount.po + +# +# message catalog +# +catalog: $(POFILE) + +install: $(ROOTLIBFSTYPEPROG) + +lint: lint_SRCS + +clean: + $(RM) $(LIBPROG).o $(POFILE)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/fs.d/smbclnt/umount/umount.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,167 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * smbfs umount + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <signal.h> +#include <unistd.h> +#include <kstat.h> +#include <rpc/rpc.h> +#include <sys/mnttab.h> +#include <sys/mount.h> +#include <sys/mntent.h> +#include <errno.h> +#include <locale.h> +#include <fslib.h> +#include <priv.h> + +#define RET_OK 0 +#define RET_ERR 32 + +static void pr_err(const char *fmt, ...); +static void usage(); +static int smbfs_unmount(char *, int); +static struct extmnttab *mnttab_find(); + +static char *myname; +static char typename[64]; + +int +main(int argc, char *argv[]) +{ + extern int optind; + int c; + int umnt_flag = 0; + + (void) setlocale(LC_ALL, ""); + +#if !defined(TEXT_DOMAIN) +#define TEXT_DOMAIN "SYS_TEST" +#endif + (void) textdomain(TEXT_DOMAIN); + + myname = strrchr(argv[0], '/'); + myname = myname ? myname+1 : argv[0]; + (void) sprintf(typename, "smbfs %s", myname); + argv[0] = typename; + + /* + * Set options + */ + while ((c = getopt(argc, argv, "f")) != EOF) { + switch (c) { + case 'f': + umnt_flag |= MS_FORCE; /* forced unmount is desired */ + break; + default: + usage(); + exit(RET_ERR); + } + } + if (argc - optind != 1) { + usage(); + exit(RET_ERR); + } + + return (smbfs_unmount(argv[optind], umnt_flag)); +} + +static void +pr_err(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + (void) fprintf(stderr, "%s: ", typename); + (void) vfprintf(stderr, fmt, ap); + (void) fflush(stderr); + va_end(ap); +} + +static void +usage() +{ + (void) fprintf(stderr, + gettext("Usage: smbfs umount [-o opts] {//server/share | dir}\n")); + exit(RET_ERR); +} + +static int +smbfs_unmount(char *pathname, int umnt_flag) +{ + struct extmnttab *mntp; + + mntp = mnttab_find(pathname); + if (mntp) { + pathname = mntp->mnt_mountp; + } + + if (umount2(pathname, umnt_flag) < 0) { + pr_err(gettext("%s: %s\n"), pathname, strerror(errno)); + return (RET_ERR); + } + + return (RET_OK); +} + +/* + * Find the mnttab entry that corresponds to "name". + * We're not sure what the name represents: either + * a mountpoint name, or a special name (server:/path). + * Return the last entry in the file that matches. + */ +static struct extmnttab * +mnttab_find(dirname) + char *dirname; +{ + FILE *fp; + struct extmnttab mnt; + struct extmnttab *res = NULL; + + fp = fopen(MNTTAB, "r"); + if (fp == NULL) { + pr_err("%s: %s\n", MNTTAB, strerror(errno)); + return (NULL); + } + while (getextmntent(fp, &mnt, sizeof (struct extmnttab)) == 0) { + if (strcmp(mnt.mnt_mountp, dirname) == 0 || + strcmp(mnt.mnt_special, dirname) == 0) { + if (res) + fsfreemnttab(res); + res = fsdupmnttab(&mnt); + } + } + + fclose(fp); + return (res); +}
--- a/usr/src/cmd/fs.d/umount.c Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/cmd/fs.d/umount.c Wed Feb 13 19:51:22 2008 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -258,8 +258,8 @@ mntnull(&mget); if (listlength == 0) { fprintf(stderr, gettext( - "%s: warning: no entries found in %s\n"), - myname, mnttab); + "%s: warning: no entries found in %s\n"), + myname, mnttab); mget.mnt_mountp = mname; /* assume mount point */ no_mnttab++; doexec(&mget); @@ -310,15 +310,15 @@ lmp = getmntlast(mntll, NULL, mp->ment.mnt_mountp); if (lmp && strcmp(lmp->ment.mnt_special, - mp->ment.mnt_special)) { + mp->ment.mnt_special)) { errno = EBUSY; rpterr(mname); exit(1); } } else { fprintf(stderr, gettext( - "%s: warning: %s not in mnttab\n"), - myname, mname); + "%s: warning: %s not in mnttab\n"), + myname, mname); if (Vflg) exit(1); /* @@ -346,7 +346,7 @@ #ifdef DEBUG if (dflg) fprintf(stderr, "%d: umounting %s\n", - getpid(), ment->mnt_mountp); + getpid(), ment->mnt_mountp); #endif /* try to exec the dependent portion */ @@ -355,19 +355,26 @@ char alter_path[FULLPATH_MAX]; char *newargv[ARGV_MAX]; int ii; + int smbfs; if (strlen(ment->mnt_fstype) > (size_t)FSTYPE_MAX) { fprintf(stderr, gettext( - "%s: FSType %s exceeds %d characters\n"), - myname, ment->mnt_fstype, FSTYPE_MAX); + "%s: FSType %s exceeds %d characters\n"), + myname, ment->mnt_fstype, FSTYPE_MAX); exit(1); } + /* + * Special case smbfs file system. + * Execute command in profile if possible. + */ + smbfs = strcmp(ment->mnt_fstype, "smbfs") == 0; + /* build the full pathname of the fstype dependent command. */ sprintf(full_path, "%s/%s/%s", fs_path, ment->mnt_fstype, - myname); + myname); sprintf(alter_path, "%s/%s/%s", alt_path, ment->mnt_fstype, - myname); + myname); /* * create the new arg list, and end the list with a @@ -385,7 +392,7 @@ newargv[ii++] = "-f"; } newargv[ii++] = (ment->mnt_mountp) - ? ment->mnt_mountp : ment->mnt_special; + ? ment->mnt_mountp : ment->mnt_special; newargv[ii] = NULL; /* set the new argv[0] to the filename */ @@ -401,12 +408,29 @@ } /* Try to exec the fstype dependent umount. */ + if (smbfs) { + /* + * Run umount_smbfs(1m) with pfexec so that we can + * add sys_mount privilege, (via exec_attr, etc.) + * allowing normal users to unmount any directory + * they own. + */ + newargv[0] = "pfexec"; + newargv[1] = full_path; + execv("/usr/bin/pfexec", &newargv[0]); + newargv[1] = myname; + } execv(full_path, &newargv[1]); if (errno == ENOEXEC) { newargv[0] = "sh"; newargv[1] = full_path; execv("/sbin/sh", &newargv[0]); } + if (smbfs) { + newargv[0] = "pfexec"; + newargv[1] = alter_path; + execv("/usr/bin/pfexec", &newargv[0]); + } newargv[1] = myname; execv(alter_path, &newargv[1]); if (errno == ENOEXEC) { @@ -417,7 +441,7 @@ /* exec failed */ if (errno != ENOENT) { fprintf(stderr, gettext("umount: cannot execute %s\n"), - full_path); + full_path); exit(1); } } @@ -429,8 +453,9 @@ /* don't use -o with generic */ if (oflg) { fprintf(stderr, gettext( - "%s: %s specific umount does not exist; -o suboption ignored\n"), - myname, ment->mnt_fstype ? ment->mnt_fstype : "<null>"); + "%s: %s specific umount does not exist;" + " -o suboption ignored\n"), + myname, ment->mnt_fstype ? ment->mnt_fstype : "<null>"); } signal(SIGHUP, SIG_IGN); @@ -446,12 +471,12 @@ */ if (fflg) { if (((ret = umount2(ment->mnt_mountp, MS_FORCE)) < 0) && - (errno != EBUSY && errno != ENOTSUP && - errno != EPERM)) + (errno != EBUSY && errno != ENOTSUP && + errno != EPERM)) ret = umount2(ment->mnt_special, MS_FORCE); } else { if (((ret = umount2(ment->mnt_mountp, 0)) < 0) && - (errno != EBUSY) && (errno != EPERM)) + (errno != EBUSY) && (errno != EPERM)) ret = umount2(ment->mnt_special, 0); } @@ -478,8 +503,8 @@ break; case ENOENT: fprintf(stderr, - gettext("%s: %s no such file or directory\n"), - myname, sp); + gettext("%s: %s no such file or directory\n"), + myname, sp); break; case EINVAL: fprintf(stderr, gettext("%s: %s not mounted\n"), myname, sp); @@ -489,11 +514,11 @@ break; case ENOTBLK: fprintf(stderr, - gettext("%s: %s block device required\n"), myname, sp); + gettext("%s: %s block device required\n"), myname, sp); break; case ECOMM: fprintf(stderr, - gettext("%s: warning: broken link detected\n"), myname); + gettext("%s: warning: broken link detected\n"), myname); break; default: perror(myname); @@ -506,7 +531,7 @@ { fprintf(stderr, gettext( "Usage:\n%s [-f] [-V] [-o specific_options] {special | mount-point}\n"), - myname); + myname); fprintf(stderr, gettext( "%s -a [-f] [-V] [-o specific_options] [mount_point ...]\n"), myname); exit(1); @@ -518,13 +543,13 @@ switch (flag) { case MNT_TOOLONG: fprintf(stderr, - gettext("%s: line in mnttab exceeds %d characters\n"), - myname, MNT_LINE_MAX-2); + gettext("%s: line in mnttab exceeds %d characters\n"), + myname, MNT_LINE_MAX-2); break; case MNT_TOOFEW: fprintf(stderr, - gettext("%s: line in mnttab has too few entries\n"), - myname); + gettext("%s: line in mnttab has too few entries\n"), + myname); break; default: break; @@ -616,7 +641,7 @@ if (count == 0) /* not an error, just none found */ return (0); fprintf(stderr, gettext("%s: no valid entries found in %s\n"), - myname, mnttab); + myname, mnttab); return (1); } @@ -626,7 +651,7 @@ */ if (lofscnt == 0) { qsort((void *)mntarray, listlength, sizeof (mountent_t *), - mcompar); + mcompar); /* * If we do not detect a lofs by now, we never will. */ @@ -702,8 +727,8 @@ cp = *mntlist++; if (realpath(cp, resolve) == NULL) { fprintf(stderr, - gettext("%s: warning: can't resolve %s\n"), - myname, cp); + gettext("%s: warning: can't resolve %s\n"), + myname, cp); exitcode = 1; mp = getmntlast(mntll, NULL, cp); /* try anyways */ } else @@ -716,8 +741,8 @@ * try to umount it: append it to mntarray. */ fprintf(stderr, gettext( - "%s: warning: %s not found in %s\n"), - myname, resolve, mnttab); + "%s: warning: %s not found in %s\n"), + myname, resolve, mnttab); exitcode = 1; mntnull(&mnew); mnew.mnt_special = mnew.mnt_mountp = strdup(resolve); @@ -753,7 +778,7 @@ if ((fp = fopen(mnttab, "r")) == NULL) { fprintf(stderr, gettext("%s: warning cannot open %s\n"), - myname, mnttab); + myname, mnttab); return (0); } mtail = NULL; @@ -844,7 +869,7 @@ #ifdef DEBUG if (dflg && pid > 0) { fprintf(stderr, "parent %d: umounting %d %s\n", - getpid(), pid, mp->ment.mnt_mountp); + getpid(), pid, mp->ment.mnt_mountp); } #endif if (pid == 0) { /* child */ @@ -934,7 +959,7 @@ */ #ifdef DEBUG fprintf(stderr, gettext( - "%s: unknown child %d\n"), myname, child); + "%s: unknown child %d\n"), myname, child); #endif exitcode = 1; return (1);
--- a/usr/src/cmd/mdb/Makefile.common Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/cmd/mdb/Makefile.common Wed Feb 13 19:51:22 2008 -0800 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -68,11 +68,13 @@ logindmux \ md \ nca \ + nsmb \ ptm \ random \ s1394 \ scsi_vhci \ sctp \ + smbfs \ smbsrv \ specfs \ sppp \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,575 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/mdb_modapi.h> +#include <sys/types.h> + +#include "smb_conn.h" +#include "smb_rq.h" +#include "smb_pass.h" + +#define OPT_VERBOSE 0x0001 /* Be [-v]erbose in dcmd's */ +#define OPT_RECURSE 0x0002 /* recursive display */ + +/* + * We need to read in a private copy + * of every string we want to print out. + */ +void +print_str(uintptr_t addr) +{ + char buf[32]; + int len, mx = sizeof (buf) - 4; + + if ((len = mdb_readstr(buf, sizeof (buf), addr)) <= 0) { + mdb_printf(" (%p)", addr); + } else { + if (len > mx) + strcpy(&buf[mx], "..."); + mdb_printf(" %s", buf); + } +} + + +/* + * Walker for smb_connobj_t structures, including + * smb_vc_t and smb_share_t which "inherit" from it. + * Tricky: Exploit the "inheritance" of smb_connobj_t + * with common functions for walk_init, walk_next. + */ +typedef struct smb_co_walk_data { + uintptr_t pp; + int level; /* SMBL_SM, SMBL_VC, SMBL_SHARE */ + int size; /* sizeof (union member) */ + union co_u { + smb_connobj_t co; /* copy of the list element */ + smb_vc_t vc; + smb_share_t ss; + } u; +} smb_co_walk_data_t; + +/* + * Common walk_init for walking structs inherited + * from smb_connobj_t (smb_vc_t, smb_share_t) + */ +int +smb_co_walk_init(mdb_walk_state_t *wsp, int level) +{ + smb_co_walk_data_t *smbw; + size_t psz; + + if (wsp->walk_addr == NULL) + return (WALK_ERR); + + smbw = mdb_alloc(sizeof (*smbw), UM_SLEEP | UM_GC); + wsp->walk_data = smbw; + + /* + * Save the parent pointer for later checks, and + * the level so we know which union member it is. + * Also the size of this union member. + */ + smbw->pp = wsp->walk_addr; + smbw->level = level; + switch (level) { + case SMBL_SM: + smbw->size = sizeof (smbw->u.co); + break; + case SMBL_VC: + smbw->size = sizeof (smbw->u.vc); + break; + case SMBL_SHARE: + smbw->size = sizeof (smbw->u.ss); + break; + default: + smbw->size = sizeof (smbw->u); + break; + } + + /* + * Read in the parent object. Just need the + * invariant part (smb_connobj_t) so we can + * get the list of children below it. + */ + psz = sizeof (smbw->u.co); + if (mdb_vread(&smbw->u.co, psz, smbw->pp) != psz) { + mdb_warn("cannot read connobj from %p", smbw->pp); + return (WALK_ERR); + } + + /* + * Finally, setup to walk the list of children. + */ + wsp->walk_addr = (uintptr_t)smbw->u.co.co_children.slh_first; + + return (WALK_NEXT); +} + +/* + * Walk the (global) VC list. + */ +int +smb_vc_walk_init(mdb_walk_state_t *wsp) +{ + GElf_Sym sym; + + if (wsp->walk_addr != NULL) { + mdb_warn("::walk smb_vc only supports global walks\n"); + return (WALK_ERR); + } + + /* Locate the VC list head. */ + if (mdb_lookup_by_obj("nsmb", "smb_vclist", &sym)) { + mdb_warn("failed to lookup `smb_vclist'\n"); + return (WALK_ERR); + } + wsp->walk_addr = sym.st_value; + + return (smb_co_walk_init(wsp, SMBL_VC)); +} + +/* + * Walk the share list below some VC. + */ +int +smb_ss_walk_init(mdb_walk_state_t *wsp) +{ + + /* + * Initial walk_addr is address of parent (VC) + */ + if (wsp->walk_addr == 0) { + mdb_warn("::walk smb_ss does not support global walks\n"); + return (WALK_ERR); + } + + return (smb_co_walk_init(wsp, SMBL_SHARE)); +} + +/* + * Common walk_step for walking structs inherited + * from smb_connobj_t (smb_vc_t, smb_share_t) + */ +int +smb_co_walk_step(mdb_walk_state_t *wsp) +{ + smb_co_walk_data_t *smbw = wsp->walk_data; + int status; + + if (wsp->walk_addr == NULL) + return (WALK_DONE); + + if (mdb_vread(&smbw->u, smbw->size, wsp->walk_addr) + != smbw->size) { + mdb_warn("cannot read connobj from %p", wsp->walk_addr); + return (WALK_ERR); + } + + /* XXX: Sanity check level? parent pointer? */ + + status = wsp->walk_callback(wsp->walk_addr, &smbw->u, + wsp->walk_cbdata); + + wsp->walk_addr = (uintptr_t)smbw->u.co.co_next.sle_next; + + return (status); +} + + +/* + * Dcmd (and callback function) to print a summary of + * all VCs, and optionally all shares under each VC. + */ + +typedef struct smb_co_cbdata { + int flags; /* OPT_... */ + int printed_header; +} smb_co_cbdata_t; + +/* + * Call-back function for walking a share list. + */ +int +smb_ss_cb(uintptr_t addr, const void *data, void *arg) +{ + const smb_share_t *ssp = data; + smb_co_cbdata_t *cbd = arg; + + mdb_printf(" %-p", addr); + print_str((uintptr_t)ssp->ss_name); + mdb_printf("\n"); + + if (cbd->flags & OPT_VERBOSE) { + mdb_inc_indent(2); + /* Anything wanted here? */ + mdb_dec_indent(2); + } + + return (WALK_NEXT); +} + +/* + * Call-back function for walking the VC list. + */ +int +smb_vc_cb(uintptr_t addr, const void *data, void *arg) +{ + const smb_vc_t *vcp = data; + smb_co_cbdata_t *cbd = arg; + + if (cbd->printed_header == 0) { + cbd->printed_header = 1; + mdb_printf("// smb_vc_t uid server user\n"); + } + + mdb_printf("%-p", addr); + mdb_printf(" %d", vcp->vc_uid); + print_str((uintptr_t)vcp->vc_srvname); + print_str((uintptr_t)vcp->vc_username); + mdb_printf("\n"); + + if (cbd->flags & OPT_RECURSE) { + mdb_inc_indent(2); + if (mdb_pwalk("nsmb_ss", smb_ss_cb, cbd, addr) < 0) { + mdb_warn("failed to walk 'nsmb_ss'"); + /* Don't: return (WALK_ERR); */ + } + mdb_dec_indent(2); + } + + return (WALK_NEXT); +} + +int +smb_vc_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + smb_co_cbdata_t cbd; + smb_vc_t *vcp; + size_t vcsz; + + memset(&cbd, 0, sizeof (cbd)); + + if (mdb_getopts(argc, argv, + 'r', MDB_OPT_SETBITS, OPT_RECURSE, &cbd.flags, + 'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd.flags, + NULL) != argc) { + return (DCMD_USAGE); + } + + if (!(flags & DCMD_ADDRSPEC)) { + if (mdb_walk("nsmb_vc", smb_vc_cb, &cbd) == -1) { + mdb_warn("failed to walk 'nsmb_vc'"); + return (DCMD_ERR); + } + return (DCMD_OK); + } + + vcsz = sizeof (*vcp); + vcp = mdb_alloc(vcsz, UM_SLEEP | UM_GC); + if (mdb_vread(vcp, vcsz, addr) != vcsz) { + mdb_warn("cannot read VC from %p", addr); + return (DCMD_ERR); + } + smb_vc_cb(addr, vcp, &cbd); + + return (DCMD_OK); +} + +void +smb_vc_help(void) +{ + mdb_printf("Options:\n" + " -r recursive display of share lists\n" + " -v be verbose when displaying smb_vc\n"); +} + +/* + * Walker for the request list on a VC, + * and dcmd to show a summary. + */ +int +rqlist_walk_init(mdb_walk_state_t *wsp) +{ + struct smb_rqhead rqh; + uintptr_t addr; + + /* + * Initial walk_addr is the address of the VC. + * Add offsetof(iod_rqlist) to get the rqhead. + */ + if (wsp->walk_addr == 0) { + mdb_warn("::walk smb_ss does not support global walks\n"); + return (WALK_ERR); + } + addr = wsp->walk_addr; + addr += OFFSETOF(smb_vc_t, iod_rqlist); + + if (mdb_vread(&rqh, sizeof (rqh), addr) == -1) { + mdb_warn("failed to read smb_rqhead at %p", addr); + return (WALK_ERR); + } + wsp->walk_addr = (uintptr_t)rqh.tqh_first; + + return (WALK_NEXT); +} + +int +rqlist_walk_step(mdb_walk_state_t *wsp) +{ + smb_rq_t rq; + int status; + + if (wsp->walk_addr == NULL) + return (WALK_DONE); + + if (mdb_vread(&rq, sizeof (rq), wsp->walk_addr) == -1) { + mdb_warn("cannot read smb_rq from %p", wsp->walk_addr); + return (WALK_ERR); + } + + status = wsp->walk_callback(wsp->walk_addr, &rq, + wsp->walk_cbdata); + + wsp->walk_addr = (uintptr_t)rq.sr_link.tqe_next; + + return (status); +} + +typedef struct rqlist_cbdata { + int printed_header; + uintptr_t uid; /* optional filtering by UID */ +} rqlist_cbdata_t; + +int +rqlist_cb(uintptr_t addr, const void *data, void *arg) +{ + const smb_rq_t *rq = data; + rqlist_cbdata_t *cbd = arg; + + if (cbd->printed_header == 0) { + cbd->printed_header = 1; + mdb_printf("// smb_rq_t MID cmd sr_state sr_flags\n"); + } + + mdb_printf(" %-p", addr); /* smb_rq_t */ + mdb_printf(" x%04x", rq->sr_mid); + mdb_printf(" x%02x", rq->sr_cmd); + mdb_printf(" %d", rq->sr_state); + mdb_printf(" x%x", rq->sr_flags); + mdb_printf("\n"); + + return (WALK_NEXT); +} + +/*ARGSUSED*/ +int +rqlist_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + rqlist_cbdata_t cbd; + + memset(&cbd, 0, sizeof (cbd)); + + /* + * Initial walk_addr is address of parent (VC) + */ + if (!(flags & DCMD_ADDRSPEC)) { + mdb_warn("address required\n"); + return (DCMD_ERR); + } + + if (mdb_pwalk("nsmb_rqlist", rqlist_cb, &cbd, addr) == -1) { + mdb_warn("failed to walk 'nsmb_rqlist'"); + return (DCMD_ERR); + } + + return (DCMD_OK); +} + + +/* + * AVL walker for the passwords AVL tree, + * and dcmd to show a summary. + */ +static int +pwtree_walk_init(mdb_walk_state_t *wsp) +{ + GElf_Sym sym; + + if (wsp->walk_addr != NULL) { + mdb_warn("pwtree walk only supports global walks\n"); + return (WALK_ERR); + } + + if (mdb_lookup_by_obj("nsmb", "smb_ptd", &sym) == -1) { + mdb_warn("failed to find symbol 'smb_ptd'"); + return (WALK_ERR); + } + + wsp->walk_addr = (uintptr_t)sym.st_value; + + if (mdb_layered_walk("avl", wsp) == -1) { + mdb_warn("failed to walk 'avl'\n"); + return (WALK_ERR); + } + + return (WALK_NEXT); +} + +static int +pwtree_walk_step(mdb_walk_state_t *wsp) +{ + smb_passid_t ptnode; + + if (mdb_vread(&ptnode, sizeof (ptnode), wsp->walk_addr) == -1) { + mdb_warn("failed to read smb_passid_t at %p", wsp->walk_addr); + return (WALK_ERR); + } + + return (wsp->walk_callback(wsp->walk_addr, &ptnode, wsp->walk_cbdata)); +} + +typedef struct pwtree_cbdata { + int printed_header; + uid_t uid; /* optional filtering by UID */ +} pwtree_cbdata_t; + +int +pwtree_cb(uintptr_t addr, const void *data, void *arg) +{ + const smb_passid_t *ptn = data; + pwtree_cbdata_t *cbd = arg; + + /* Optional filtering by UID. */ + if (cbd->uid != (uid_t)-1 && cbd->uid != ptn->uid) { + return (WALK_NEXT); + } + + if (cbd->printed_header == 0) { + cbd->printed_header = 1; + mdb_printf("// smb_passid_t UID domain user\n"); + } + + mdb_printf(" %-p", addr); /* smb_passid_t */ + mdb_printf(" %d", (uintptr_t)ptn->uid); + print_str((uintptr_t)ptn->srvdom); + print_str((uintptr_t)ptn->username); + mdb_printf("\n"); + + return (WALK_NEXT); +} + +/*ARGSUSED*/ +int +pwtree_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + pwtree_cbdata_t cbd; + char *uid_str = NULL; + char buf[32]; + + memset(&cbd, 0, sizeof (cbd)); + + if (mdb_getopts(argc, argv, + 'u', MDB_OPT_STR, &uid_str, NULL) != argc) { + return (DCMD_USAGE); + } + if (uid_str) { + /* + * Want the the default radix to be 10 here. + * If the string has some kind of radix prefix, + * just use that as-is, otherwise prepend "0t". + * Cheating on the "not a digit" test, but + * mdb_strtoull will do a real syntax check. + */ + if (uid_str[0] == '0' && uid_str[1] > '9') { + cbd.uid = (uid_t)mdb_strtoull(uid_str); + } else { + strcpy(buf, "0t"); + strlcat(buf, uid_str, sizeof (buf)); + cbd.uid = (uid_t)mdb_strtoull(buf); + } + } else + cbd.uid = (uid_t)-1; + + if (flags & DCMD_ADDRSPEC) { + mdb_warn("address not allowed\n"); + return (DCMD_ERR); + } + + if (mdb_pwalk("nsmb_pwtree", pwtree_cb, &cbd, 0) == -1) { + mdb_warn("failed to walk 'nsmb_pwtree'"); + return (DCMD_ERR); + } + + return (DCMD_OK); +} + +void +pwtree_help(void) +{ + mdb_printf("Options:\n" + " -u uid show only entries belonging to uid (decimal)\n"); +} + + +static const mdb_dcmd_t dcmds[] = { + { "nsmb_vc", "?[-rv]", + "show smb_vc (or list)", + smb_vc_dcmd, smb_vc_help }, + { "nsmb_rqlist", ":", + "show smb_rq list on a VC", + rqlist_dcmd, NULL }, + { "nsmb_pwtree", "?[-u uid]", + "list smb_passid_t (password tree)", + pwtree_dcmd, pwtree_help }, + {NULL} +}; + +static const mdb_walker_t walkers[] = { + { "nsmb_vc", "walk nsmb VC list", + smb_vc_walk_init, smb_co_walk_step, NULL }, + { "nsmb_ss", "walk nsmb share list for some VC", + smb_ss_walk_init, smb_co_walk_step, NULL }, + { "nsmb_rqlist", "walk request list for some VC", + rqlist_walk_init, rqlist_walk_step, NULL }, + { "nsmb_pwtree", "walk passord AVL tree", + pwtree_walk_init, pwtree_walk_step, NULL }, + {NULL} +}; + +static const mdb_modinfo_t modinfo = { + MDB_API_VERSION, + dcmds, + walkers +}; + +const mdb_modinfo_t * +_mdb_init(void) +{ + return (&modinfo); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,397 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/mdb_modapi.h> +#include <sys/types.h> +#include <sys/refstr_impl.h> +#include <sys/vnode.h> +#include <sys/vfs.h> + +#include "smbfs.h" +#include "smbfs_node.h" + +#define OPT_VERBOSE 0x0001 /* Be [-v]erbose in dcmd's */ + +/* + * This macro lets us easily use both sizeof (typename) + * and the string-ified typename for the error message. + */ +#define SMBFS_OBJ_FETCH(obj_addr, obj_type, dest, err) \ + if (mdb_vread(dest, sizeof (obj_type), ((uintptr_t)obj_addr)) \ + != sizeof (obj_type)) { \ + mdb_warn("error reading "#obj_type" at %p", obj_addr); \ + return (err); \ + } + +/* + * We need to read in a private copy + * of every string we want to print out. + */ +void +print_str(uintptr_t addr) +{ + char buf[64]; + int len, mx = sizeof (buf) - 4; + + if ((len = mdb_readstr(buf, sizeof (buf), addr)) <= 0) { + mdb_printf(" (%p)", addr); + } else { + if (len > mx) + strcpy(&buf[mx], "..."); + mdb_printf(" %s", buf); + } +} + +/* + * Dcmd (and callback function) to print a summary of + * all "smbfs" entries in the VFS list. + */ + +typedef struct smbfs_vfs_cbdata { + int flags; + int printed_header; + uintptr_t vfsops; /* filter by vfs ops pointer */ + smbmntinfo_t smi; /* scratch space for smbfs_vfs_cb */ +} smbfs_vfs_cbdata_t; + +int +smbfs_vfs_cb(uintptr_t addr, const void *data, void *arg) +{ + const vfs_t *vfs = data; + smbfs_vfs_cbdata_t *cbd = arg; + uintptr_t ta; + + /* Filter by matching smbfs ops vector. */ + if (cbd->vfsops && cbd->vfsops != (uintptr_t)vfs->vfs_op) { + return (WALK_NEXT); + } + + if (cbd->printed_header == 0) { + cbd->printed_header = 1; + mdb_printf("// vfs_t smbmntinfo_t mnt_path\n"); + } + + mdb_printf(" %-p", addr); /* vfs_t */ + mdb_printf(" %-p", (uintptr_t)vfs->vfs_data); + /* + * Note: vfs_mntpt is a refstr_t. + * Advance to string member. + */ + ta = (uintptr_t)vfs->vfs_mntpt; + ta += OFFSETOF(struct refstr, rs_string); + print_str(ta); + mdb_printf("\n"); + + if (cbd->flags & OPT_VERBOSE) { + mdb_inc_indent(2); + /* Don't fail the walk if this fails. */ + if (mdb_vread(&cbd->smi, sizeof (cbd->smi), + (uintptr_t)vfs->vfs_data) == -1) { + mdb_warn("error reading smbmntinfo_t at %p", + (uintptr_t)vfs->vfs_data); + } else { + /* Interesting parts of smbmntinfo_t */ + mdb_printf("smi_share: %p, smi_root: %p\n", + cbd->smi.smi_share, cbd->smi.smi_root); + } + mdb_dec_indent(2); + } + + return (WALK_NEXT); +} + +int +smbfs_vfs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + smbfs_vfs_cbdata_t *cbd; + vfs_t *vfs; + + cbd = mdb_zalloc(sizeof (*cbd), UM_SLEEP | UM_GC); + + /* + * Get the ops address here, so things work + * even if the smbfs module is loaded later + * than this mdb module. + */ + if (mdb_readvar(&cbd->vfsops, "smbfs_vfsops") == -1) { + mdb_warn("failed to find 'smbfs_vfsops'\n"); + return (DCMD_ERR); + } + + if (mdb_getopts(argc, argv, + 'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd->flags, + NULL) != argc) { + return (DCMD_USAGE); + } + + if (!(flags & DCMD_ADDRSPEC)) { + if (mdb_walk("genunix`vfs", smbfs_vfs_cb, cbd) + == -1) { + mdb_warn("can't walk smbfs vfs"); + return (DCMD_ERR); + } + return (DCMD_OK); + } + + vfs = mdb_alloc(sizeof (*vfs), UM_SLEEP | UM_GC); + SMBFS_OBJ_FETCH(addr, vfs_t, vfs, DCMD_ERR); + smbfs_vfs_cb(addr, vfs, cbd); + return (DCMD_OK); +} + +void +smbfs_vfs_help(void) +{ + mdb_printf( + "Display addresses of the mounted smbfs structures\n" + "and the pathname of the mountpoint\n" + "\nOptions:\n" + " -v display details of the smbmntinfo\n"); +} + +/* + * Walker for the smbnode hash table. + */ + +typedef struct smbnode_walk_data { + rhashq_t *smbtab; /* (our copy of) the smbtable */ + int tabsize; /* size of table */ + int nextidx; /* next bucket index */ + uintptr_t buckptr; /* target addr of current bucket */ + uintptr_t nodeptr; /* target addr of current smbnode */ + smbnode_t node; /* scratch space for _step */ +} smbnode_walk_data_t; + +int +smbnode_walk_init(mdb_walk_state_t *wsp) +{ + size_t tabsz_bytes; + int tabsize; + uintptr_t smbtab; + smbnode_walk_data_t *smbw; + + if (wsp->walk_addr != NULL) { + mdb_warn("smbnode only supports global walks\n"); + return (WALK_ERR); + } + + if (mdb_readvar(&tabsize, "smbtablesize") == -1) { + mdb_warn("failed to read `smbtablesize'\n"); + return (WALK_ERR); + } + + if (tabsize == 0) { + return (WALK_DONE); + } + + if (mdb_readvar(&smbtab, "smbtable") == -1) { + mdb_warn("failed to read `smbtable'\n"); + return (WALK_ERR); + } + + smbw = mdb_alloc(sizeof (*smbw), UM_SLEEP | UM_GC); + + tabsz_bytes = tabsize * sizeof (rhashq_t); + smbw->smbtab = mdb_alloc(tabsz_bytes, UM_SLEEP | UM_GC); + if (mdb_vread(smbw->smbtab, tabsz_bytes, smbtab) != tabsz_bytes) { + mdb_warn("failed to read in smbtable from %p", smbtab); + return (WALK_ERR); + } + smbw->tabsize = tabsize; + smbw->nextidx = 1; + smbw->buckptr = smbtab; + smbw->nodeptr = (uintptr_t)smbw->smbtab[0].r_hashf; + wsp->walk_data = smbw; + + return (WALK_NEXT); +} + +int +smbnode_walk_step(mdb_walk_state_t *wsp) +{ + smbnode_walk_data_t *smbw = wsp->walk_data; + int status; + +next_bucket: + while (smbw->nodeptr == smbw->buckptr && + smbw->nextidx < smbw->tabsize) { + + /* Skip an empty bucket */ + rhashq_t *h = &smbw->smbtab[smbw->nextidx]; + smbw->nodeptr = (uintptr_t)h->r_hashf; + smbw->nextidx++; + smbw->buckptr += sizeof (rhashq_t); + } + + if (smbw->nodeptr == smbw->buckptr) + return (WALK_DONE); + + if (mdb_vread(&smbw->node, sizeof (smbw->node), + smbw->nodeptr) != sizeof (smbw->node)) { + mdb_warn("failed to read smbnode at %p in bucket %p\n", + smbw->nodeptr, smbw->buckptr); + /* Proceed with next bucket. */ + smbw->nodeptr = smbw->buckptr; + goto next_bucket; + } + + status = wsp->walk_callback(smbw->nodeptr, + &smbw->node, wsp->walk_cbdata); + + /* Move to next node in this bucket */ + smbw->nodeptr = (uintptr_t)smbw->node.r_hashf; + + return (status); +} + +/*ARGSUSED*/ +void +smbnode_walk_fini(mdb_walk_state_t *wsp) +{ + /* UM_GC takes care of it all. */ +} + +/* + * Dcmd (and callback function) to print a summary of + * all smbnodes in the node hash table. + */ + +typedef struct smbnode_cbdata { + int flags; + int printed_header; + uintptr_t smi; /* optional filtering by VFS */ + /* TODO: only nodes with a given [-h]ash */ + vnode_t vn; /* scratch space for smbnode_cb */ +} smbnode_cbdata_t; + +int +smbnode_cb(uintptr_t addr, const void *data, void *arg) +{ + const smbnode_t *np = data; + smbnode_cbdata_t *cbd = arg; + + /* Optional filtering by mount point. */ + if (cbd->smi && cbd->smi != (uintptr_t)np->n_mount) { + return (WALK_NEXT); + } + + if (cbd->printed_header == 0) { + cbd->printed_header = 1; + mdb_printf("// smbnode vnode rpath\n"); + } + + mdb_printf(" %-p", addr); /* smbnode */ + mdb_printf(" %-p", (uintptr_t)np->r_vnode); + print_str((uintptr_t)np->n_rpath); + mdb_printf("\n"); + + if (cbd->flags & OPT_VERBOSE) { + mdb_inc_indent(2); + /* Don't fail the walk if this fails. */ + if (mdb_vread(&cbd->vn, sizeof (cbd->vn), + (uintptr_t)np->r_vnode) == -1) { + mdb_warn("error reading vnode_t at %p", + (uintptr_t)np->r_vnode); + } else { + /* Interesting parts of vnode_t */ + mdb_printf("v_type: %d v_path:", + cbd->vn.v_type); + print_str((uintptr_t)cbd->vn.v_path); + mdb_printf("\n"); + } + mdb_dec_indent(2); + } + + return (WALK_NEXT); +} + +int +smbnode_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + smbnode_cbdata_t *cbd; + smbnode_t *np; + + cbd = mdb_zalloc(sizeof (*cbd), UM_SLEEP | UM_GC); + + if (mdb_getopts(argc, argv, + 'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd->flags, + 'm', MDB_OPT_UINTPTR, &cbd->smi, NULL) != argc) { + return (DCMD_USAGE); + } + + if (!(flags & DCMD_ADDRSPEC)) { + if (mdb_walk("smbnode", smbnode_cb, cbd) + == -1) { + mdb_warn("cannot walk smbnodes"); + return (DCMD_ERR); + } + return (DCMD_OK); + } + + np = mdb_alloc(sizeof (*np), UM_SLEEP | UM_GC); + SMBFS_OBJ_FETCH(addr, smbnode_t, np, DCMD_ERR); + smbnode_cb(addr, np, cbd); + + return (DCMD_OK); +} + +void +smbnode_help(void) +{ + mdb_printf("Options:\n" + " -m mntinfo only show smbnodes belonging to mntinfo\n" + " -v be verbose when displaying smbnodes\n"); +} + +static const mdb_dcmd_t dcmds[] = { + { "smbfs_vfs", "?[-v]", + "show smbfs-mounted vfs structs", + smbfs_vfs_dcmd, smbfs_vfs_help }, + { "smbnode", "?[-v] [-m mntinfo]", + "show smbnodes", smbnode_dcmd, smbnode_help }, + {NULL} +}; + +static const mdb_walker_t walkers[] = { + { "smbnode", "walk smbnode hash table", + smbnode_walk_init, smbnode_walk_step, smbnode_walk_fini }, + {NULL} +}; + +static const mdb_modinfo_t modinfo = { + MDB_API_VERSION, + dcmds, + walkers +}; + +const mdb_modinfo_t * +_mdb_init(void) +{ + return (&modinfo); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/intel/amd64/nsmb/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,41 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. + +#pragma ident "%Z%%M% %I% %E% SMI" + +MDBTGT = kvm +MODULE = nsmb.so +MODSRCS_DIR = ../../../common/modules/nsmb +MODSRCS = nsmb.c + +include ../../../../Makefile.cmd +include ../../../../Makefile.cmd.64 +include ../../Makefile.amd64 +include ../../../Makefile.module + +CPPFLAGS += -I$(SRC)/uts/common/fs/smbclnt/netsmb +CPPFLAGS += -I$(SRC)/uts/common + +C99MODE= -xc99=%all +C99LMODE= -Xc99=%all
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/intel/amd64/smbfs/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,39 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. + +#pragma ident "%Z%%M% %I% %E% SMI" + +MDBTGT = kvm +MODULE = smbfs.so +MODSRCS_DIR = ../../../common/modules/smbfs +MODSRCS = smbfs.c + +include ../../../../Makefile.cmd +include ../../../../Makefile.cmd.64 +include ../../Makefile.amd64 +include ../../../Makefile.module + +CPPFLAGS += -I$(SRC)/uts/common/fs/smbclnt/smbfs +CPPFLAGS += -I$(SRC)/uts/common +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/intel/ia32/nsmb/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,40 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. + +#pragma ident "%Z%%M% %I% %E% SMI" + +MDBTGT = kvm +MODULE = nsmb.so +MODSRCS_DIR = ../../../common/modules/nsmb +MODSRCS = nsmb.c + +include ../../../../Makefile.cmd +include ../../Makefile.ia32 +include ../../../Makefile.module + +CPPFLAGS += -I$(SRC)/uts/common/fs/smbclnt/netsmb +CPPFLAGS += -I$(SRC)/uts/common + +C99MODE= -xc99=%all +C99LMODE= -Xc99=%all
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/intel/ia32/smbfs/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,38 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. + +#pragma ident "%Z%%M% %I% %E% SMI" + +MDBTGT = kvm +MODULE = smbfs.so +MODSRCS_DIR = ../../../common/modules/smbfs +MODSRCS = smbfs.c + +include ../../../../Makefile.cmd +include ../../Makefile.ia32 +include ../../../Makefile.module + +CPPFLAGS += -I$(SRC)/uts/common/fs/smbclnt/smbfs +CPPFLAGS += -I$(SRC)/uts/common +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/sparc/v9/nsmb/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,41 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. + +#pragma ident "%Z%%M% %I% %E% SMI" + +MDBTGT = kvm +MODULE = nsmb.so +MODSRCS_DIR = ../../../common/modules/nsmb +MODSRCS = nsmb.c + +include ../../../../Makefile.cmd +include ../../../../Makefile.cmd.64 +include ../../Makefile.sparcv9 +include ../../../Makefile.module + +CPPFLAGS += -I$(SRC)/uts/common/fs/smbclnt/netsmb +CPPFLAGS += -I$(SRC)/uts/common + +C99MODE= -xc99=%all +C99LMODE= -Xc99=%all
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/mdb/sparc/v9/smbfs/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,39 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. + +#pragma ident "%Z%%M% %I% %E% SMI" + +MDBTGT = kvm +MODULE = smbfs.so +MODSRCS_DIR = ../../../common/modules/smbfs +MODSRCS = smbfs.c + +include ../../../../Makefile.cmd +include ../../../../Makefile.cmd.64 +include ../../Makefile.sparcv9 +include ../../../Makefile.module + +CPPFLAGS += -I$(SRC)/uts/common/fs/smbclnt/smbfs +CPPFLAGS += -I$(SRC)/uts/common +
--- a/usr/src/cmd/svc/profile/generic_limited_net.xml Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/cmd/svc/profile/generic_limited_net.xml Wed Feb 13 19:51:22 2008 -0800 @@ -20,7 +20,7 @@ CDDL HEADER END - Copyright 2007 Sun Microsystems, Inc. All rights reserved. + Copyright 2008 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. ident "%Z%%M% %I% %E% SMI" @@ -117,6 +117,9 @@ <service name='network/nfs/mapid' version='1' type='service'> <instance name='default' enabled='false'/> </service> + <service name='network/smb/client' version='1' type='service'> + <instance name='default' enabled='false'/> + </service> <service name='network/ssh' version='1' type='service'> <instance name='default' enabled='true'/>
--- a/usr/src/cmd/svc/profile/generic_open.xml Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/cmd/svc/profile/generic_open.xml Wed Feb 13 19:51:22 2008 -0800 @@ -20,7 +20,7 @@ CDDL HEADER END - Copyright 2007 Sun Microsystems, Inc. All rights reserved. + Copyright 2008 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. ident "%Z%%M% %I% %E% SMI" @@ -111,6 +111,9 @@ <service name='network/nfs/mapid' version='1' type='service'> <instance name='default' enabled='true'/> </service> + <service name='network/smb/client' version='1' type='service'> + <instance name='default' enabled='true'/> + </service> <service name='network/ssh' version='1' type='service'> <instance name='default' enabled='true'/> </service>
--- a/usr/src/lib/Makefile Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -145,7 +145,8 @@ ncad_addr \ gss_mechs/mech_krb5 .WAIT \ libkrb5 .WAIT \ - krb5 .WAIT + krb5 .WAIT \ + libsmbfs $(CLOSED_BUILD)SUBDIRS += \ $(CLOSED)/lib/smartcard SUBDIRS += \ @@ -304,6 +305,7 @@ libshell \ libsldap \ libslp \ + libsmbfs \ libsmedia \ libtsol \ libuutil \ @@ -521,6 +523,7 @@ libsctp: libsocket libshell: libast libcmd libdll libsocket libsecdb libsip: libmd5 +libsmbfs: libsocket libnsl libkrb5 libsocket: libnsl libldap5: libsasl libsocket libnsl libmd libsldap: libldap5 libtsol @@ -549,7 +552,7 @@ libzpool: libavl libumem libnvpair libsec: libavl brand: libc libsocket -libshare: libscf libzfs libuuid libfsmgt libsecdb +libshare: libscf libzfs libuuid libfsmgt libsecdb libumem libsmbfs libexacct/demo: libexacct libproject libsocket libnsl libtsalarm: libpcp smbsrv: libsocket libnsl libmd libxnet libpthread librt \
--- a/usr/src/lib/brand/native/zone/platform.xml Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/brand/native/zone/platform.xml Wed Feb 13 19:51:22 2008 -0800 @@ -61,6 +61,7 @@ <device match="lo3" /> <device match="log" /> <device match="logindmux" /> + <device match="nsmb" /> <device match="net/*" /> <device match="null" /> <device match="openprom" arch="sparc" />
--- a/usr/src/lib/libsecdb/auth_attr.txt Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libsecdb/auth_attr.txt Wed Feb 13 19:51:22 2008 -0800 @@ -18,7 +18,7 @@ # # CDDL HEADER END # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # /etc/security/auth_attr @@ -122,6 +122,7 @@ solaris.smf.manage.nwam:::Manage Network Auto-Magic Service States::help=SmfNWAMStates.html solaris.smf.manage.power:::Manage Power Management Service States::help=SmfPowerStates.html solaris.smf.manage.smb:::Manage SMB Service States::help=SmfSMBStates.html +solaris.smf.manage.smbfs:::Manage SMB Client States::help=SmfSMBFSStates.html solaris.smf.manage.rmvolmgr:::Manage Rmvolmgr Service States::help=SmfRmvolmgrStates.html solaris.smf.manage.routing:::Manage Routing Service States::help=SmfRoutingStates.html solaris.smf.manage.rpc.bind:::Manage RPC Program number mapper::help=SmfRPCBind.html
--- a/usr/src/lib/libsecdb/exec_attr.txt Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libsecdb/exec_attr.txt Wed Feb 13 19:51:22 2008 -0800 @@ -18,7 +18,7 @@ # # CDDL HEADER END # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # /etc/security/exec_attr @@ -38,6 +38,8 @@ Audit Review:suser:cmd:::/usr/sbin/auditreduce:euid=0 Audit Review:suser:cmd:::/usr/sbin/auditstat:euid=0 Audit Review:suser:cmd:::/usr/sbin/praudit:euid=0 +Basic Solaris User:solaris:cmd:::/usr/lib/fs/smbfs/mount:privs=sys_mount +Basic Solaris User:solaris:cmd:::/usr/lib/fs/smbfs/umount:privs=sys_mount Contract Observer:solaris:cmd:::/usr/bin/ctwatch:\ privs=contract_event,contract_observer Cron Management:suser:cmd:::/usr/bin/crontab:euid=0
--- a/usr/src/lib/libsecdb/help/auths/Makefile Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libsecdb/help/auths/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -18,7 +18,7 @@ # # CDDL HEADER END # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -98,6 +98,7 @@ SmfValueRouting.html \ SmfValueSMB.html \ AuthReadSMB.html \ + SmfSMBFSStates.html \ SmfSMBStates.html \ SmfValueVscan.html \ SmfVscanStates.html \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsecdb/help/auths/SmfSMBFSStates.html Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,40 @@ +<HTML> +<!-- + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + +Copyright 2008 Sun Microsystems, Inc. All rights reserved. +Use is subject to license terms. +--> +<!-- SCCS keyword +#pragma ident "%Z%%M% %I% %E% SMI" +--> +<!-- + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> +--> +<BODY> +When Manage SMBFS Service States is in the Authorizations Include +column, it grants the authorization to enable, disable, or restart +the SMB client. +<p> +If Manage SMBFS Service States is grayed, then you are not entitled +to Add or Remove this authorization. +<BR> +</BODY> +</HTML>
--- a/usr/src/lib/libsecdb/help/profiles/Makefile Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libsecdb/help/profiles/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -18,7 +18,7 @@ # # CDDL HEADER END # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -64,6 +64,7 @@ RtProcManagement.html \ RtRightsDelegate.html \ RtSMBMngmnt.html \ + RtSMBFSMngmnt.html \ RtSoftwareInstall.html \ RtSysEvMngmnt.html \ RtUserMngmnt.html \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsecdb/help/profiles/RtSMBFSMngmnt.html Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,40 @@ +<HTML> +<!-- + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + +-- Copyright 2008 Sun Microsystems, Inc. All rights reserved. +-- Use is subject to license terms. +--> +<HEAD> + <TITLE> </TITLE> + + +</HEAD> +<BODY> +<!-- ident "%Z%%M% %I% %E% SMI" --> + +When SMBFS Service Management is in the Rights Included column, it grants +the right to administer the SMB client. +<p> +If SMBFS Service Management is grayed, then you are not entitled to Add or +Remove this right. +<p> +</BODY> +</HTML>
--- a/usr/src/lib/libsecdb/prof_attr.txt Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libsecdb/prof_attr.txt Wed Feb 13 19:51:22 2008 -0800 @@ -20,7 +20,7 @@ # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -42,7 +42,7 @@ Basic Solaris User:::Automatically assigned rights:auths=solaris.profmgr.read,solaris.jobs.user,solaris.mail.mailq,solaris.device.mount.removable;profiles=All;help=RtDefault.html Device Security:::Manage devices and Volume Manager:auths=solaris.device.*;help=RtDeviceSecurity.html DHCP Management:::Manage the DHCP service:auths=solaris.dhcpmgr.*;help=RtDHCPMngmnt.html -File System Management:::Manage, mount, share file systems:profiles=SMB Management,VSCAN Management;auths=solaris.smf.manage.autofs,solaris.smf.manage.shares.*,solaris.smf.value.shares.*;help=RtFileSysMngmnt.html +File System Management:::Manage, mount, share file systems:profiles=SMB Management,VSCAN Management,SMBFS Management;auths=solaris.smf.manage.autofs,solaris.smf.manage.shares.*,solaris.smf.value.shares.*;help=RtFileSysMngmnt.html File System Security:::Manage file system security attributes:help=RtFileSysSecurity.html HAL Management:::Manage HAL SMF service:auths=solaris.smf.manage.hal;help=RtHALMngmnt.html Idmap Name Mapping Management:::Manage Name-based Mapping Rules of Identity Mapping Service:auths=solaris.admin.idmap.rules;help=RtIdmapNameRulesMngmnt.html @@ -77,6 +77,7 @@ Kerberos Server Management:::Maintain and Administer Kerberos Servers:profiles=Kerberos Client Management;help=RtKerberosSrvrMngmnt.html DAT Administration:::Manage the DAT configuration:help=RtDatAdmin.html SMB Management:::Manage the SMB service:auths=solaris.smf.manage.smb,solaris.smf.value.smb,solaris.smf.read.smb;help=RtSMBMngmnt.html +SMBFS Management:::Manage the SMB client:auths=solaris.smf.manage.smbfs,solaris.smf.value,solaris.smf.modify.application;help=RtSMBFSMngmnt.html ZFS File System Management:::Create and Manage ZFS File Systems:help=RtZFSFileSysMngmnt.html ZFS Storage Management:::Create and Manage ZFS Storage Pools:help=RtZFSStorageMngmnt.html Zone Management:::Zones Virtual Application Environment Administration:help=RtZoneMngmnt.html
--- a/usr/src/lib/libshare/Makefile Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libshare/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -21,7 +21,7 @@ # # ident "%Z%%M% %I% %E% SMI" # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -35,7 +35,7 @@ # Add plugin module directories here. They need to build after the libshare # objects are built. -PLUGINS = smb nfs +PLUGINS = nfs smb smbfs $(PLUGINS): $(MACHS) SUBDIRS = $(MACHS) $(PLUGINS)
--- a/usr/src/lib/libshare/Makefile.com Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libshare/Makefile.com Wed Feb 13 19:51:22 2008 -0800 @@ -21,7 +21,7 @@ # # ident "%Z%%M% %I% %E% SMI" # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY = libshare.a @@ -41,8 +41,7 @@ lintcheck := SRCS = $(LIBSRCS) LIBS = $(DYNLIB) $(LINTLIB) -LDLIBS += -lc -lnsl -lscf -lzfs -luuid -all install := LDLIBS += -lxml2 +LDLIBS += -lc -lnsl -lscf -lzfs -luuid -lxml2 $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) #add nfs/lib directory as part of the include path
--- a/usr/src/lib/libshare/common/libshare.c Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libshare/common/libshare.c Wed Feb 13 19:51:22 2008 -0800 @@ -211,6 +211,18 @@ case SA_PATH_IS_PARENTDIR: ret = dgettext(TEXT_DOMAIN, "path is parent of a share"); break; + case SA_NO_SECTION: + ret = dgettext(TEXT_DOMAIN, "protocol requires a section"); + break; + case SA_NO_PROPERTIES: + ret = dgettext(TEXT_DOMAIN, "properties not found"); + break; + case SA_NO_SUCH_SECTION: + ret = dgettext(TEXT_DOMAIN, "section not found"); + break; + case SA_PASSWORD_ENC: + ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted"); + break; default: (void) snprintf(errstr, sizeof (errstr), dgettext(TEXT_DOMAIN, "unknown %d"), err); @@ -357,8 +369,9 @@ int ret; (void) snprintf(tstring, sizeof (tstring), "%lld", tval); - xmlSetProp(node, (xmlChar *)"timestamp", (xmlChar *)tstring); - xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); + (void) xmlSetProp(node, (xmlChar *)"timestamp", + (xmlChar *)tstring); + (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); /* now commit to SMF */ ret = sa_get_instance(handle->scfhandle, "default"); if (ret == SA_OK) { @@ -907,7 +920,7 @@ (xmlChar *)"sharecfg"); if (handle->doc != NULL && handle->tree != NULL) { - xmlDocSetRootElement(handle->doc, + (void) xmlDocSetRootElement(handle->doc, handle->tree); err = add_handle_for_root(handle->tree, handle); @@ -1375,7 +1388,7 @@ } } if (exclude_list[0] != '\0') - xmlSetProp(share, (xmlChar *)"exclude", + (void) xmlSetProp(share, (xmlChar *)"exclude", (xmlChar *)exclude_list); } @@ -1432,8 +1445,8 @@ return (node); } - xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); - xmlSetProp(node, (xmlChar *)"type", + (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); + (void) xmlSetProp(node, (xmlChar *)"type", persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); if (flags != 0) mark_excluded_protos(group, node, flags); @@ -1745,7 +1758,7 @@ * now that the share isn't in its old group, add to * the new one */ - xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); + (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); /* need to deal with SMF */ impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); if (impl_handle != NULL) { @@ -1808,9 +1821,9 @@ node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", NULL); if (node != NULL) { - xmlSetProp(node, (xmlChar *)"name", + (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); - xmlSetProp(node, (xmlChar *)"state", + (void) xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); } } @@ -1831,8 +1844,10 @@ node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); if (node != NULL) { - xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); - xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); + (void) xmlSetProp(node, (xmlChar *)"name", + (xmlChar *)groupname); + (void) xmlSetProp(node, (xmlChar *)"state", + (xmlChar *)"enabled"); } return ((sa_group_t)node); @@ -1871,10 +1886,10 @@ node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", NULL); if (node != NULL) { - xmlSetProp(node, (xmlChar *)"name", + (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); /* default to the group being enabled */ - xmlSetProp(node, (xmlChar *)"state", + (void) xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); ret = sa_create_instance(impl_handle->scfhandle, groupname); @@ -2032,9 +2047,10 @@ xmlNodePtr node = (xmlNodePtr)nodehdl; if (node != NULL && tag != NULL) { if (value != NULL) - xmlSetProp(node, (xmlChar *)tag, (xmlChar *)value); + (void) xmlSetProp(node, (xmlChar *)tag, + (xmlChar *)value); else - xmlUnsetProp(node, (xmlChar *)tag); + (void) xmlUnsetProp(node, (xmlChar *)tag); } } @@ -3124,7 +3140,36 @@ } /* - * sa_create_property(name, value) + * sa_create_section(name, value) + * + * Create a new section with the specified name and extra data. + */ + +sa_property_t +sa_create_section(char *name, char *extra) +{ + xmlNodePtr node; + + node = xmlNewNode(NULL, (xmlChar *)"section"); + if (node != NULL) { + if (name != NULL) + (void) xmlSetProp(node, (xmlChar *)"name", + (xmlChar *)name); + if (extra != NULL) + (void) xmlSetProp(node, (xmlChar *)"extra", + (xmlChar *)extra); + } + return ((sa_property_t)node); +} + +void +sa_set_section_attr(sa_property_t sect, char *name, char *value) +{ + (void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value); +} + +/* + * sa_create_property(section, name, value) * * Create a new property with the specified name and value. */ @@ -3136,8 +3181,8 @@ node = xmlNewNode(NULL, (xmlChar *)"option"); if (node != NULL) { - xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); - xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); + (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); + (void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); } return ((sa_property_t)node); } @@ -3333,6 +3378,91 @@ } /* + * sa_get_protocol_section(propset, prop) + * + * Get the specified protocol specific section. These are global to + * the protocol and not specific to a group or share. + */ + +sa_protocol_properties_t +sa_get_protocol_section(sa_protocol_properties_t propset, char *section) +{ + xmlNodePtr node = (xmlNodePtr)propset; + xmlChar *value = NULL; + char *proto; + + proto = sa_get_optionset_attr(propset, "type"); + if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) + return (propset); + + for (node = node->children; node != NULL; + node = node->next) { + if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { + if (section == NULL) + break; + value = xmlGetProp(node, (xmlChar *)"name"); + if (value != NULL && + xmlStrcasecmp(value, (xmlChar *)section) == 0) { + break; + } + if (value != NULL) { + xmlFree(value); + value = NULL; + } + } + } + if (value != NULL) + xmlFree(value); + if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) { + /* + * avoid a non option node -- it is possible to be a + * text node + */ + node = NULL; + } + return ((sa_protocol_properties_t)node); +} + +/* + * sa_get_next_protocol_section(prop, find) + * + * Get the next protocol specific section in the list. + */ + +sa_property_t +sa_get_next_protocol_section(sa_property_t prop, char *find) +{ + xmlNodePtr node; + xmlChar *value = NULL; + char *proto; + + proto = sa_get_optionset_attr(prop, "type"); + if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) + return ((sa_property_t)NULL); + + for (node = ((xmlNodePtr)prop)->next; node != NULL; + node = node->next) { + if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { + if (find == NULL) + break; + value = xmlGetProp(node, (xmlChar *)"name"); + if (value != NULL && + xmlStrcasecmp(value, (xmlChar *)find) == 0) { + break; + } + if (value != NULL) { + xmlFree(value); + value = NULL; + } + + } + } + if (value != NULL) + xmlFree(value); + return ((sa_property_t)node); +} + +/* * sa_get_protocol_property(propset, prop) * * Get the specified protocol specific property. These are global to @@ -3345,6 +3475,9 @@ xmlNodePtr node = (xmlNodePtr)propset; xmlChar *value = NULL; + if (propset == NULL) + return (NULL); + for (node = node->children; node != NULL; node = node->next) { if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { @@ -3380,16 +3513,30 @@ */ sa_property_t -sa_get_next_protocol_property(sa_property_t prop) +sa_get_next_protocol_property(sa_property_t prop, char *find) { xmlNodePtr node; + xmlChar *value = NULL; for (node = ((xmlNodePtr)prop)->next; node != NULL; node = node->next) { if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { - break; + if (find == NULL) + break; + value = xmlGetProp(node, (xmlChar *)"type"); + if (value != NULL && + xmlStrcasecmp(value, (xmlChar *)find) == 0) { + break; + } + if (value != NULL) { + xmlFree(value); + value = NULL; + } + } } + if (value != NULL) + xmlFree(value); return ((sa_property_t)node); } @@ -3401,7 +3548,7 @@ */ int -sa_set_protocol_property(sa_property_t prop, char *value) +sa_set_protocol_property(sa_property_t prop, char *section, char *value) { sa_protocol_properties_t propset; char *proto; @@ -3411,6 +3558,9 @@ if (propset != NULL) { proto = sa_get_optionset_attr(propset, "type"); if (proto != NULL) { + if (section != NULL) + set_node_attr((xmlNodePtr)prop, "section", + section); set_node_attr((xmlNodePtr)prop, "value", value); ret = sa_proto_set_property(proto, prop); sa_free_attr_string(proto); @@ -3450,7 +3600,7 @@ node = xmlNewNode(NULL, (xmlChar *)"propertyset"); if (node != NULL) - xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); + (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); return (node); } @@ -3575,15 +3725,15 @@ node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"resource", NULL); if (node != NULL) { - xmlSetProp(node, (xmlChar *)"name", + (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)resource); - xmlSetProp(node, (xmlChar *)"type", persist ? + (void) xmlSetProp(node, (xmlChar *)"type", persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); if (persist != SA_SHARE_TRANSIENT) { index = _sa_get_next_resource_index(share); (void) snprintf(istring, sizeof (istring), "%d", index); - xmlSetProp(node, (xmlChar *)"id", + (void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)istring); if (!sa_group_is_zfs(group) && sa_is_persistent((sa_group_t)share)) {
--- a/usr/src/lib/libshare/common/libshare.h Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libshare/common/libshare.h Wed Feb 13 19:51:22 2008 -0800 @@ -85,6 +85,10 @@ #define SA_MULTIPLE_ERROR 26 /* multiple protocols reported error */ #define SA_PATH_IS_SUBDIR 27 /* check_path found path is subdir */ #define SA_PATH_IS_PARENTDIR 28 /* check_path found path is parent */ +#define SA_NO_SECTION 29 /* protocol requires section info */ +#define SA_NO_SUCH_SECTION 30 /* no section found */ +#define SA_NO_PROPERTIES 31 /* no properties found */ +#define SA_PASSWORD_ENC 32 /* passwords must be encrypted */ /* API Initialization */ #define SA_INIT_SHARE_API 0x0001 /* init share specific interface */ @@ -122,6 +126,8 @@ #define SA_FEATURE_DFSTAB 0x0002 /* need to manage in dfstab */ #define SA_FEATURE_ALLOWSUBDIRS 0x0004 /* allow subdirs to be shared */ #define SA_FEATURE_ALLOWPARDIRS 0x0008 /* allow parent dirs to be shared */ +#define SA_FEATURE_HAS_SECTIONS 0x0010 /* protocol supports sections */ +#define SA_FEATURE_ADD_PROPERTIES 0x0020 /* can add properties */ /* * legacy files @@ -208,6 +214,8 @@ extern sa_property_t sa_get_property(sa_optionset_t, char *); extern sa_property_t sa_get_next_property(sa_group_t); extern char *sa_get_property_attr(sa_property_t, char *); +extern sa_property_t sa_create_section(char *, char *); +extern void sa_set_section_attr(sa_property_t, char *, char *); extern sa_property_t sa_create_property(char *, char *); extern int sa_add_property(void *, sa_property_t); extern int sa_update_property(sa_property_t, char *); @@ -233,9 +241,11 @@ extern int sa_is_security(char *, char *); extern sa_protocol_properties_t sa_proto_get_properties(char *); extern uint64_t sa_proto_get_featureset(char *); +extern sa_property_t sa_get_protocol_section(sa_protocol_properties_t, char *); +extern sa_property_t sa_get_next_protocol_section(sa_property_t, char *); extern sa_property_t sa_get_protocol_property(sa_protocol_properties_t, char *); -extern sa_property_t sa_get_next_protocol_property(sa_property_t); -extern int sa_set_protocol_property(sa_property_t, char *); +extern sa_property_t sa_get_next_protocol_property(sa_property_t, char *); +extern int sa_set_protocol_property(sa_property_t, char *, char *); extern char *sa_get_protocol_status(char *); extern void sa_format_free(char *); extern sa_protocol_properties_t sa_create_protocol_properties(char *); @@ -246,6 +256,7 @@ extern int sa_proto_get_transients(sa_handle_t, char *); extern int sa_proto_notify_resource(sa_resource_t, char *); extern int sa_proto_change_notify(sa_share_t, char *); +extern int sa_proto_delete_section(char *, char *); /* handle legacy (dfstab/sharetab) files */ extern int sa_delete_legacy(sa_share_t, char *);
--- a/usr/src/lib/libshare/common/libshare_impl.h Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libshare/common/libshare_impl.h Wed Feb 13 19:51:22 2008 -0800 @@ -55,19 +55,19 @@ #define SA_PLUGIN_VERSION 1 struct sa_plugin_ops { - int sa_version; + int sa_version; /* version number */ char *sa_protocol; /* protocol name */ int (*sa_init)(); void (*sa_fini)(); int (*sa_share)(sa_share_t); /* start sharing */ int (*sa_unshare)(sa_share_t, char *); /* stop sharing */ - int (*sa_valid_prop)(sa_property_t, sa_optionset_t); + int (*sa_valid_prop)(sa_property_t, sa_optionset_t); /* validate */ int (*sa_valid_space)(char *); /* is name valid optionspace? */ int (*sa_security_prop)(char *); /* property is security */ int (*sa_legacy_opts)(sa_group_t, char *); /* parse legacy opts */ char *(*sa_legacy_format)(sa_group_t, int); - int (*sa_set_proto_prop)(sa_property_t); - sa_protocol_properties_t (*sa_get_proto_set)(); + int (*sa_set_proto_prop)(sa_property_t); /* set a property */ + sa_protocol_properties_t (*sa_get_proto_set)(); /* get properties */ char *(*sa_get_proto_status)(); char *(*sa_space_alias)(char *); int (*sa_update_legacy)(sa_share_t); @@ -81,6 +81,7 @@ int (*sa_rename_resource)(sa_handle_t, sa_resource_t, char *); int (*sa_run_command)(int, int, char **); /* proto specific */ int (*sa_command_help)(); + int (*sa_delete_proto_section)(char *); }; struct sa_proto_handle {
--- a/usr/src/lib/libshare/common/mapfile-vers Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libshare/common/mapfile-vers Wed Feb 13 19:51:22 2008 -0800 @@ -29,6 +29,8 @@ global: sa_get_optionset; sa_create_property; + sa_create_section; + sa_set_section_attr; sa_get_property; sa_create_security; sa_update_legacy; @@ -45,6 +47,7 @@ sa_get_group; sa_get_security; sa_get_protocol_property; + sa_get_protocol_section; sa_add_share; sa_valid_group_name; sa_get_optionset_attr; @@ -77,6 +80,7 @@ sa_proto_valid_space; sa_proto_space_alias; sa_get_next_protocol_property; + sa_get_next_protocol_section; sa_remove_share; sa_is_share; sa_get_share_description; @@ -128,6 +132,7 @@ sa_set_resource_description; sa_get_resource_description; sa_fix_resource_name; + sa_proto_delete_section; sa_needs_refresh; sa_get_zfs_handle; sa_zfs_process_share;
--- a/usr/src/lib/libshare/common/plugin.c Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libshare/common/plugin.c Wed Feb 13 19:51:22 2008 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -518,8 +518,36 @@ if (ops != NULL) { if (ops->sa_delete_legacy != NULL) ret = ops->sa_delete_legacy(share); - } else if (proto == NULL) { - ret = SA_INVALID_PROTOCOL; + } else { + if (proto != NULL) + ret = SA_NOT_IMPLEMENTED; + else + ret = SA_INVALID_PROTOCOL; + } + return (ret); +} + +/* + * sa_proto_delete_section(proto, section) + * + * Remove the specified section from the protocol specific legacy files, + * if supported. + */ + +int +sa_proto_delete_section(char *proto, char *section) +{ + struct sa_plugin_ops *ops = find_protocol(proto); + int ret = SA_OK; + + if (ops != NULL) { + if (ops->sa_delete_proto_section != NULL) + ret = ops->sa_delete_proto_section(section); + } else { + if (proto != NULL) + ret = SA_NOT_IMPLEMENTED; + else + ret = SA_INVALID_PROTOCOL; } return (ret); } @@ -540,6 +568,7 @@ if (ops->sa_change_notify != NULL) ret = ops->sa_change_notify(share); } else if (proto == NULL) { + ret = SA_INVALID_PROTOCOL; } return (ret);
--- a/usr/src/lib/libshare/nfs/Makefile.com Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libshare/nfs/Makefile.com Wed Feb 13 19:51:22 2008 -0800 @@ -21,7 +21,7 @@ # # ident "%Z%%M% %I% %E% SMI" # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -44,8 +44,7 @@ lintcheck := SRCS = $(LIBSRCS) LIBS = $(DYNLIB) -LDLIBS += -lshare -lnsl -lscf -lumem -lc -all install := LDLIBS += -lxml2 +LDLIBS += -lshare -lnsl -lscf -lumem -lc -lxml2 #add nfs/lib directory as part of the include path CFLAGS += $(CCVERBOSE)
--- a/usr/src/lib/libshare/nfs/libshare_nfs.c Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libshare/nfs/libshare_nfs.c Wed Feb 13 19:51:22 2008 -0800 @@ -104,7 +104,10 @@ nfs_features, NULL, /* transient shares */ NULL, /* notify resource */ - NULL + NULL, /* rename_resource */ + NULL, /* run_command */ + NULL, /* command_help */ + NULL /* delete_proto_section */ }; /*
--- a/usr/src/lib/libshare/smb/libshare_smb.c Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/libshare/smb/libshare_smb.c Wed Feb 13 19:51:22 2008 -0800 @@ -114,16 +114,16 @@ smb_enable_share, smb_disable_share, smb_validate_property, - NULL, - NULL, + NULL, /* valid_space */ + NULL, /* security_prop */ smb_parse_optstring, smb_format_options, smb_set_proto_prop, smb_get_proto_set, smb_get_status, - NULL, - NULL, - NULL, + NULL, /* space_alias */ + NULL, /* update_legacy */ + NULL, /* delete_legacy */ smb_share_changed, smb_enable_resource, smb_disable_resource, @@ -131,8 +131,9 @@ smb_list_transient, smb_resource_changed, smb_rename_resource, - NULL, - NULL + NULL, /* run_command */ + NULL, /* command_help */ + NULL /* delete_proto_section */ }; /*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libshare/smbfs/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,57 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +include ../../Makefile.lib + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +MSGFILES = libshare_smbfs.c +POFILE = libshare_smbfs.po + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +$(POFILE): $(MSGFILES) + $(BUILDPO.msgfiles) + +_msg: $(MSGDOMAINPOFILE) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include ../../Makefile.targ +include ../../../Makefile.msg.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libshare/smbfs/Makefile.com Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,63 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +LIBRARY = libshare_smbfs.a +VERS = .1 + +LIBOBJS = libshare_smbfs.o +SMBBASE_OBJ = smbfs_scfutil.o +OBJECTS = $(LIBOBJS) $(SMBBASE_OBJ) + +include ../../../Makefile.lib + +ROOTLIBDIR = $(ROOT)/usr/lib/fs/smbfs +ROOTLIBDIR64 = $(ROOT)/usr/lib/fs/smbfs/$(MACH64) + +LIBSRCS = $(LIBOBJS:%.o=$(SRCDIR)/%.c) + +LIBS = $(DYNLIB) +LDLIBS += -lshare -lscf -lumem -luuid -lc -lxml2 -lsmbfs + +CFLAGS += $(CCVERBOSE) +CPPFLAGS += -D_REENTRANT -I/usr/include/libxml2 -I$(SRCDIR)/../common \ + -I$(SRC)/lib/libsmbfs -I$(SRC)/uts/common + +.KEEP_STATE: + +all: $(LIBS) + +install: $(ROOTLIBDIR) $(ROOTLIBDIR64) all + +lint: lintcheck + +$(ROOTLIBDIR): + $(INS.dir) + +$(ROOTLIBDIR64): + $(INS.dir) + +include ../../../Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libshare/smbfs/amd64/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +include ../Makefile.com +include ../../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libshare/smbfs/i386/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libshare/smbfs/libshare_smbfs.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,813 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * SMB specific functions + */ +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <zone.h> +#include <errno.h> +#include <locale.h> +#include <signal.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <syslog.h> +#include "libshare.h" +#include "libshare_impl.h" +#include <pwd.h> +#include <limits.h> +#include <libscf.h> +#include <strings.h> +#include "libshare_smbfs.h" +#include <rpcsvc/daemon_utils.h> +#include <arpa/inet.h> +#include <uuid/uuid.h> +#include <netsmb/smb_lib.h> + +#define SMBFS_PROTOCOL_NAME "smbfs" + +/* internal functions */ +static uint64_t smbfs_features(); +static int smbfs_init(); +static void smbfs_fini(); +static int smbfs_set_proto_prop(sa_property_t); +static sa_protocol_properties_t smbfs_get_proto_set(); +static char *smbfs_get_status(); +static int smbfs_delete_section(char *); +static int smbfs_delete_property_group(char *); + +static int range_check_validator(int, char *, char *); +static int string_length_check_validator(int, char *, char *); +static int yes_no_validator(int, char *, char *); +static int ip_address_validator(int, char *, char *); +static int minauth_validator(int, char *, char *); +static int password_validator(int, char *, char *); +#ifdef NOT_DEFINED +static int nbscope_validator(int, char *, char *); +#endif + +int propset_changed = 0; + +/* + * ops vector that provides the protocol specific info and operations + * for share management. + */ + +struct sa_plugin_ops sa_plugin_ops = { + SA_PLUGIN_VERSION, + SMBFS_PROTOCOL_NAME, + smbfs_init, + smbfs_fini, + NULL, /* share */ + NULL, /* unshare */ + NULL, /* valid_prop */ + NULL, /* valid_space */ + NULL, /* security_prop */ + NULL, /* legacy_opts */ + NULL, /* legacy_format */ + smbfs_set_proto_prop, + smbfs_get_proto_set, + smbfs_get_status, + NULL, /* space_alias */ + NULL, /* update_legacy */ + NULL, /* delete_legacy */ + NULL, /* change_notify */ + NULL, /* enable_resource */ + NULL, /* disable_resource */ + smbfs_features, + NULL, /* get_transient_shares */ + NULL, /* notify_resource */ + NULL, /* rename_resource */ + NULL, /* run_command */ + NULL, /* command_help */ + smbfs_delete_section, +}; + +/* + * is_a_number(number) + * + * is the string a number in one of the forms we want to use? + */ + +static int +is_a_number(char *number) +{ + int ret = 1; + int hex = 0; + + if (strncmp(number, "0x", 2) == 0) { + number += 2; + hex = 1; + } else if (*number == '-') { + number++; /* skip the minus */ + } + + while (ret == 1 && *number != '\0') { + if (hex) { + ret = isxdigit(*number++); + } else { + ret = isdigit(*number++); + } + } + return (ret); +} + +/* + * Protocol management functions + * + * properties defined in the default files are defined in + * proto_option_defs for parsing and validation. + */ + +struct smbclnt_proto_option_defs smbclnt_proto_options[] = { + { "section", NULL, PROTO_OPT_SECTION, + 0, 0, MAX_VALUE_BUFLEN, + string_length_check_validator}, + { "addr", NULL, PROTO_OPT_ADDR, + 0, 0, MAX_VALUE_BUFLEN, + ip_address_validator}, + { "minauth", NULL, PROTO_OPT_MINAUTH, + 0, 0, MAX_VALUE_BUFLEN, + minauth_validator}, + { "nbns_broadcast", NULL, PROTO_OPT_NBNS_BROADCAST, + 0, 0, 0, + yes_no_validator}, + { "nbns_enable", NULL, PROTO_OPT_NBNS_ENABLE, + 0, 0, 0, + yes_no_validator}, + { "nbns", NULL, PROTO_OPT_NBNSADDR, + 0, 0, MAX_VALUE_BUFLEN, + ip_address_validator}, + { "password", NULL, PROTO_OPT_PASSWORD, + 0, 0, MAX_VALUE_BUFLEN, + password_validator}, + { "timeout", NULL, PROTO_OPT_TIMEOUT, + 0, 0, 60, + range_check_validator}, + { "user", NULL, PROTO_OPT_USER, + 0, 0, MAX_VALUE_BUFLEN, + string_length_check_validator}, + { "domain", NULL, PROTO_OPT_DOMAIN, + 0, 0, MAX_VALUE_BUFLEN, + string_length_check_validator}, + { "workgroup", NULL, PROTO_OPT_WORKGROUP, + 0, 0, MAX_VALUE_BUFLEN, + string_length_check_validator}, +#ifdef NOT_DEFINED + { "nbscope", NULL, PROTO_OPT_NBSCOPE, + 0, 0, MAX_VALUE_BUFLEN, + nbscope_validator}, + { "nbtimeout", NULL, PROTO_OPT_NBTIMEOUT, + 0, 0, 60, + range_check_validator}, + { "retry_count", NULL, PROTO_OPT_RETRY_COUNT, + 0, 0, 10, + range_check_validator}, + { "use_negprot_domain", NULL, PROTO_OPT_USE_NEGPROT_DOMAIN, + 0, 0, 0, + yes_no_validator}, + { "charset", NULL, PROTO_OPT_CHARSETS, + 0, 0, MAX_VALUE_BUFLEN, + ip_address_validator}, +#endif + {NULL} +}; + +/* + * Check the range of value as int range. + */ +/*ARGSUSED*/ +static int +range_check_validator(int index, char *section, char *value) +{ + int ret = SA_OK; + + if (value == NULL) + return (SA_BAD_VALUE); + if (strlen(value) == 0) + return (SA_OK); + if (!is_a_number(value)) { + ret = SA_BAD_VALUE; + } else { + int val; + val = strtoul(value, NULL, 0); + if (val < smbclnt_proto_options[index].minval || + val > smbclnt_proto_options[index].maxval) + ret = SA_BAD_VALUE; + } + return (ret); +} + +/* + * Check the length of the string + */ +/*ARGSUSED*/ +static int +string_length_check_validator(int index, char *section, char *value) +{ + int ret = SA_OK; + + if (value == NULL) + return (SA_BAD_VALUE); + if (strlen(value) == 0) + return (SA_OK); + if (strlen(value) > smbclnt_proto_options[index].maxval) + ret = SA_BAD_VALUE; + return (ret); +} + +/* + * Check yes/no + */ +/*ARGSUSED*/ +static int +yes_no_validator(int index, char *section, char *value) +{ + if (value == NULL) + return (SA_BAD_VALUE); + if (strlen(value) == 0) + return (SA_OK); + if ((strcasecmp(value, "yes") == 0) || + (strcasecmp(value, "no") == 0) || + (strcasecmp(value, "true") == 0) || + (strcasecmp(value, "false") == 0)) + return (SA_OK); + return (SA_BAD_VALUE); +} + +/* + * Check IP address. + */ +/*ARGSUSED*/ +static int +ip_address_validator(int index, char *section, char *value) +{ + int len; + + if (value == NULL) + return (SA_BAD_VALUE); + len = strlen(value); + if (len == 0) + return (SA_OK); + if (len > MAX_VALUE_BUFLEN) + return (SA_BAD_VALUE); + return (SA_OK); +} + +/*ARGSUSED*/ +static int +minauth_validator(int index, char *section, char *value) +{ + if (value == NULL) + return (SA_BAD_VALUE); + if (strlen(value) == 0) + return (SA_OK); + if (strcmp(value, "kerberos") == 0 || + strcmp(value, "ntlmv2") == 0 || + strcmp(value, "ntlm") == 0 || + strcmp(value, "lm") == 0 || + strcmp(value, "none") == 0) + return (SA_OK); + else + return (SA_BAD_VALUE); +} + +#ifdef NOT_DEFINED +/*ARGSUSED*/ +static int +nbscope_validator(int index, char *section, char *value) +{ + /* + * XXX - not sure what's legal here. Looks like it's not + * used in nb_name_encode() right now anyway. + */ + return (SA_OK); +} +#endif + +/*ARGSUSED*/ +static int +password_validator(int index, char *section, char *value) +{ + char buffer[100]; + + /* mangled passwords will start with this pattern */ + if (strlen(value) == 0) + return (SA_OK); + if (strncmp(value, "$$1", 3) != 0) + return (SA_PASSWORD_ENC); + if (smb_simpledecrypt(buffer, value) != 0) + return (SA_BAD_VALUE); + return (SA_OK); +} + + +/* + * the protoset holds the defined options so we don't have to read + * them multiple times + */ +sa_protocol_properties_t protoset; + +static int +findprotoopt(char *name) +{ + int i; + for (i = 0; smbclnt_proto_options[i].name != NULL; i++) { + if (strcasecmp(smbclnt_proto_options[i].name, name) == 0) + return (i); + } + return (-1); +} + +/* + * Load the persistent settings from SMF. Each section is an SMF + * property group with an "S-" prefix and a UUID, and the section + * is itself a property which can have a more flexible name than + * a property group name can have. The section name need not be + * the first property, so we have to be a little flexible, but + * the change of name of the property groups is a reliable way + * to know that we're seeing a different section. + */ +int +smbclnt_config_load() +{ + scf_simple_app_props_t *props = NULL; + scf_simple_prop_t *prop = NULL, *lastprop = NULL; + char *lastpgname = NULL, *pgname = NULL; + char *name = NULL, *value = NULL; + sa_property_t sect, node; + int pending = 0; +#ifdef DEBUG + char *sectname = NULL; +#endif + + props = scf_simple_app_props_get(NULL, SMBC_DEFAULT_INSTANCE_FMRI); + if (props == NULL) + return (-1); + + while ((prop = (scf_simple_prop_t *) + scf_simple_app_props_next(props, lastprop)) != NULL) { + + /* Ignore properties that don't have our prefix */ + pgname = scf_simple_prop_pgname(prop); + if (strncmp("S-", pgname, 2) != 0) { + lastprop = prop; + continue; + } + + /* Note property group name changes, which mark sections */ + if (lastpgname == NULL || strcmp(lastpgname, pgname) != 0) { +#ifdef DEBUG + if (pending) + fprintf(stderr, "smbclnt_config_load: " + "Ignoring empty section %s\n", sectname); + fprintf(stderr, "smbclnt_config_load: new pg=%s\n", + pgname); +#endif + sect = sa_create_section(NULL, pgname+2); + (void) xmlSetProp(sect, (xmlChar *)"type", + (xmlChar *)SMBFS_PROTOCOL_NAME); + if (lastpgname) + free(lastpgname); + lastpgname = strdup(pgname); + pending = 1; + } + name = scf_simple_prop_name(prop); + value = scf_simple_prop_next_astring(prop); + + /* If we get a section name, apply it and consume it */ + if (strncmp("section", name, 7) == 0 && value != NULL) { +#ifdef DEBUG + if (sectname) + free(sectname); + sectname = strdup(value); + fprintf(stderr, "smbclnt_config_load: section=%s\n", + sectname); +#endif + (void) xmlSetProp(sect, (xmlChar *)"name", + (xmlChar *)value); + lastprop = prop; + continue; + } +#ifdef DEBUG + fprintf(stderr, "pg=%s, sect=%s, nm=%s, val=%s\n", + pgname, sectname ? sectname : "NULL", name, value); +#endif + /* + * If we have an ordinary property, add to the section. + * Also, if this is the first ordinary property, we + * can commit the non-empty section to the protoset. + */ + node = sa_create_property(name, value); + (void) sa_add_protocol_property(sect, node); + lastprop = prop; + if (pending) { + (void) sa_add_protocol_property(protoset, sect); + pending = 0; + } + } + scf_simple_app_props_free(props); + if (pending) { +#ifdef DEBUG + fprintf(stderr, "smbclnt_config_load: " + "Deleting empty section %s\n", sectname); +#endif + (void) smbfs_delete_property_group(lastpgname); + } + if (lastpgname) + free(lastpgname); + return (0); +} + +/* + * Save the set of properties for a particular section, which is + * stored as a single property group. Properties will have been + * changed earlier by one or more calls to smbfs_save_property(), + * which only set the value in our array and marked them as + * SMBC_MODIFIED. + */ +int +smbfs_save_propset() +{ + smb_scfhandle_t *handle = NULL; + char propgroup[256]; + char *section = smbclnt_proto_options[PROTO_OPT_SECTION].value; + char *uu = NULL; + uuid_t uuid; + int i, ret = 0; + sa_property_t propset; + int new = 0, nonnull = 0; + + propset = sa_get_protocol_section(protoset, section); + (void) strncpy(propgroup, SMBC_PG_PREFIX, SMBC_PG_PREFIX_LEN); + propgroup[SMBC_PG_PREFIX_LEN] = '\0'; + uu = sa_get_property_attr(propset, "extra"); + if (uu != NULL) { + (void) strncat(propgroup, uu, UUID_PRINTABLE_STRING_LENGTH); + free(uu); + } else { + new = 1; + smbclnt_proto_options[PROTO_OPT_SECTION].flags |= SMBC_MODIFIED; + uuid_generate(uuid); + uuid_unparse(uuid, &propgroup[SMBC_PG_PREFIX_LEN]); + } +#ifdef DEBUG + fprintf(stderr, "smbfs_save_propset: %s pgname=%s\n", + new ? "new" : "old", propgroup); +#endif + + handle = smb_smf_scf_init(SMBC_FMRI_PREFIX); + if (handle == NULL) { + return (1); + } + + if ((ret = smb_smf_instance_create(handle, SMBC_FMRI_PREFIX, + SMBC_PG_INSTANCE)) != SMBC_SMF_OK) { + goto out; + } + + if ((ret = smb_smf_create_instance_pgroup(handle, propgroup)) + != SMBC_SMF_OK) { + goto out; + } + + if ((ret = smb_smf_start_transaction(handle)) != SMBC_SMF_OK) { + goto out; + } + + for (i = PROTO_OPT_SECTION+1; i <= SMBC_OPT_MAX; i++) { + if ((smbclnt_proto_options[i].flags & SMBC_MODIFIED) == 0) + continue; +#ifdef DEBUG + fprintf(stderr, "smbfs_save_propset: saving " + "i=%d/name=%s/value=%s\n", i, + smbclnt_proto_options[i].name, + smbclnt_proto_options[i].value); +#endif + if (strcmp(smbclnt_proto_options[i].value, "") == 0) + ret = smb_smf_delete_property(handle, + smbclnt_proto_options[i].name); + else { + ret = smb_smf_set_string_property(handle, + smbclnt_proto_options[i].name, + smbclnt_proto_options[i].value); + nonnull = 1; + } + free(smbclnt_proto_options[i].value); + smbclnt_proto_options[i].value = NULL; + smbclnt_proto_options[i].flags &= ~SMBC_MODIFIED; + if (ret != SMBC_SMF_OK) + goto outtrans; + } + /* + * Suppress new, null entries by not saving the section name. + */ + if (!new || nonnull) { +#ifdef DEBUG + fprintf(stderr, "smbfs_save_propset: saving " + "i=%d/name=%s/value=%s\n", PROTO_OPT_SECTION, + smbclnt_proto_options[PROTO_OPT_SECTION].name, + smbclnt_proto_options[PROTO_OPT_SECTION].value); +#endif + ret = smb_smf_set_string_property(handle, + smbclnt_proto_options[PROTO_OPT_SECTION].name, + smbclnt_proto_options[PROTO_OPT_SECTION].value); + free(smbclnt_proto_options[PROTO_OPT_SECTION].value); + smbclnt_proto_options[PROTO_OPT_SECTION].value = NULL; + smbclnt_proto_options[PROTO_OPT_SECTION].flags &= + ~SMBC_MODIFIED; + } + propset_changed = 0; + +outtrans: + ret = smb_smf_end_transaction(handle); +out: + smb_smf_scf_fini(handle); + return (ret); +} + +/* + * initprotofromdefault() + * + * read the default file(s) and add the defined values to the + * protoset. Note that default values are known from the built in + * table in case the file doesn't have a definition. + */ + +static int +initprotofromdefault() +{ + protoset = sa_create_protocol_properties(SMBFS_PROTOCOL_NAME); + if (protoset == NULL) + return (SA_NO_MEMORY); + if (smbclnt_config_load() != 0) + return (SA_OK); + + return (SA_OK); +} + +/* + * + * smbfs_features() + * + * Report the plugin's features + */ +static uint64_t +smbfs_features() +{ + return (SA_FEATURE_HAS_SECTIONS | SA_FEATURE_ADD_PROPERTIES); +} + +/* + * smbfs_init() + * + * Initialize the smb plugin. + */ + +static int +smbfs_init() +{ + int ret = SA_OK; + + if (sa_plugin_ops.sa_init != smbfs_init) { + return (SA_SYSTEM_ERR); + } + + if (initprotofromdefault() != SA_OK) { + return (SA_SYSTEM_ERR); + } + + return (ret); +} + +/* + * smbfs_fini() + * + * uninitialize the smb plugin. Want to avoid memory leaks. + */ + +static void +smbfs_fini() +{ + if (propset_changed) + (void) smbfs_save_propset(); +} + +/* + * smbfs_get_proto_set() + * + * Return an optionset with all the protocol specific properties in + * it. + */ + +static sa_protocol_properties_t +smbfs_get_proto_set() +{ + return (protoset); +} + +/* + * smbfs_validate_proto_prop(index, name, value) + * + * Verify that the property specifed by name can take the new + * value. This is a sanity check to prevent bad values getting into + * the default files. + */ +static int +smbfs_validate_proto_prop(int index, char *section, char *name, char *value) +{ + if ((section == NULL) || (name == NULL) || (index < 0)) + return (SA_BAD_VALUE); + + if (smbclnt_proto_options[index].validator == NULL) + return (SA_OK); + + return (smbclnt_proto_options[index].validator(index, section, value)); +} + +/* + * Save a property to our array; it will be stored to SMF later by + * smbfs_save_propset(). + */ +int +smbfs_save_property(int index, char *section, char *value) +{ + char *s; + + if (index == PROTO_OPT_WORKGROUP) { +#ifdef DEBUG + fprintf(stderr, "smbfs_save_property: " + "index %d being mapped to %d\n", + index, PROTO_OPT_DOMAIN); +#endif + index = PROTO_OPT_DOMAIN; + } +#ifdef DEBUG + fprintf(stderr, "smbfs_save_property: " + "section=%s, index=%d, name=%s, value=%s\n", + section, index, smbclnt_proto_options[index].name, value); +#endif + propset_changed = 1; + s = strdup(section); + if (s == NULL) + return (-1); + smbclnt_proto_options[PROTO_OPT_SECTION].value = s; + s = strdup(value); + if (s == NULL) + return (-1); + smbclnt_proto_options[index].value = s; + smbclnt_proto_options[index].flags |= SMBC_MODIFIED; + return (0); +} + +/* + * smbfs_set_proto_prop(prop) + * + * check that prop is valid. + */ +/*ARGSUSED*/ +static int +smbfs_set_proto_prop(sa_property_t prop) +{ + int ret = SA_OK; + char *name; + char *value; + char *section; + int i = -1; + + section = sa_get_property_attr(prop, "section"); + if (section == NULL) + return (SA_NO_SECTION); + name = sa_get_property_attr(prop, "type"); + value = sa_get_property_attr(prop, "value"); + if (name != NULL && value != NULL) { + i = findprotoopt(name); + if (i >= 0) { + ret = smbfs_validate_proto_prop(i, section, + name, value); + if (ret == SA_OK) { + if (smbfs_save_property(i, section, + value) != 0) { + ret = SA_SYSTEM_ERR; + errno = EIO; + } + } + } else + ret = SA_INVALID_NAME; + } + if (name != NULL) + sa_free_attr_string(name); + if (value != NULL) + sa_free_attr_string(value); + + return (ret); +} + +/* + * smbfs_get_status() + * + * What is the current status of the smbd? We use the SMF state here. + * Caller must free the returned value. + */ + +static char * +smbfs_get_status() +{ + char *state = "enabled"; + state = smf_get_state(SMBC_DEFAULT_INSTANCE_FMRI); + return (state != NULL ? state : strdup("-")); +} + +/* + * Delete a section by its name, which we will have read into an + * XML optionset above. We need to find it and find its UUID to + * be able to generate the property group name in order to call + * smbfs_delete_property_group(). + */ +static int +smbfs_delete_section(char *section) +{ + char propgroup[256]; + char *uu = NULL; + sa_property_t propset; + int ret = SA_SYSTEM_ERR; + + propset = sa_get_protocol_section(protoset, section); + (void) strncpy(propgroup, SMBC_PG_PREFIX, SMBC_PG_PREFIX_LEN); + propgroup[SMBC_PG_PREFIX_LEN] = '\0'; + uu = sa_get_property_attr(propset, "extra"); + if (uu == NULL) + goto out; + (void) strncat(propgroup, uu, UUID_PRINTABLE_STRING_LENGTH); + free(uu); + if ((ret = smbfs_delete_property_group(propgroup)) != SMBC_SMF_OK) + goto out; + ret = SA_OK; +out: + return (ret); +} + +/* + * Delete a property group by its name. Called to do a 'delsect' + * or called when smbclnt_config_load() notices an empty section + * at the end of the properties. + */ +static int +smbfs_delete_property_group(char *propgroup) +{ + smb_scfhandle_t *handle = NULL; + int ret = SA_SYSTEM_ERR; + +#ifdef DEBUG + fprintf(stderr, "smbfs_delete_property_group: pgname=%s\n", propgroup); +#endif + + handle = smb_smf_scf_init(SMBC_FMRI_PREFIX); + if (handle == NULL) + goto out; + + if ((ret = smb_smf_instance_create(handle, SMBC_FMRI_PREFIX, + SMBC_PG_INSTANCE)) != SMBC_SMF_OK) + goto out; + + if ((ret = smb_smf_delete_instance_pgroup(handle, propgroup)) + != SMBC_SMF_OK) + goto out; + ret = SA_OK; +out: + smb_smf_scf_fini(handle); +#ifdef DEBUG + fprintf(stderr, "smbfs_delete_property_group: returning %d\n", ret); +#endif + return (ret); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libshare/smbfs/libshare_smbfs.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,147 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * basic API declarations for share management + */ + +#ifndef _LIBSHARE_SMBFS_H +#define _LIBSHARE_SMBFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct smbclnt_proto_option_defs { + char *name; /* display name -- remove protocol identifier */ + char *value; + int index; + int flags; + int32_t minval; + int32_t maxval; /* In case of length of string this should be max */ + int (*validator)(int, char *, char *); +}; + +extern struct smbclnt_proto_option_defs smbclnt_proto_options[]; + +#define PROTO_OPT_SECTION 0 +#define PROTO_OPT_ADDR 1 +#define PROTO_OPT_MINAUTH 2 +#define PROTO_OPT_NBNS_BROADCAST 3 +#define PROTO_OPT_NBNS_ENABLE 4 +#define PROTO_OPT_NBNSADDR 5 +#define PROTO_OPT_PASSWORD 6 +#define PROTO_OPT_TIMEOUT 7 +#define PROTO_OPT_USER 8 +#define PROTO_OPT_DOMAIN 9 +#define PROTO_OPT_WORKGROUP 10 + +#ifdef NOT_DEFINED +#define PROTO_OPT_NBSCOPE 11 +#define PROTO_OPT_NBTIMEOUT 12 +#define PROTO_OPT_RETRY_COUNT 13 +#define PROTO_OPT_USE_NEGPROT_DOMAIN 14 +#define PROTO_OPT_CHARSETS 15 +#endif + +#define SMBC_OPT_MAX PROTO_OPT_WORKGROUP + +/* + * Flags values + */ +#define SMBC_MODIFIED 0x01 + +/* Max value length of all SMB properties */ +#define MAX_VALUE_BUFLEN 600 + +/* + * SMF access + */ + +#define SMBC_FMRI_PREFIX "network/smb/client" +#define SMBC_DEFAULT_INSTANCE_FMRI "svc:/network/smb/client:default" +#define SMBC_PG_PREFIX "S-" +#define SMBC_PG_PREFIX_LEN 2 +#define SMBC_PG_INSTANCE "default" + +#define SMBC_SMF_OK 0 +#define SMBC_SMF_NO_MEMORY 1 /* no memory for data structures */ +#define SMBC_SMF_SYSTEM_ERR 2 /* system error, use errno */ +#define SMBC_SMF_NO_PERMISSION 3 /* no permission for operation */ + +#define SCH_STATE_UNINIT 0 +#define SCH_STATE_INITIALIZING 1 +#define SCH_STATE_INIT 2 + +typedef struct smb_scfhandle { + scf_handle_t *scf_handle; + int scf_state; + scf_service_t *scf_service; + scf_scope_t *scf_scope; + scf_transaction_t *scf_trans; + scf_transaction_entry_t *scf_entry; + scf_propertygroup_t *scf_pg; + scf_instance_t *scf_instance; + scf_iter_t *scf_inst_iter; + scf_iter_t *scf_pg_iter; +} smb_scfhandle_t; + +extern void smb_smf_scf_fini(smb_scfhandle_t *); +extern smb_scfhandle_t *smb_smf_scf_init(char *); +extern int smb_smf_get_instance(smb_scfhandle_t *, char *); +extern int smb_smf_create_instance(smb_scfhandle_t *, char *); +extern int smb_smf_start_transaction(smb_scfhandle_t *); +extern int smb_smf_end_transaction(smb_scfhandle_t *); + +extern int smb_smf_set_string_property(smb_scfhandle_t *, char *, char *); +extern int smb_smf_get_string_property(smb_scfhandle_t *, char *, + char *, size_t); +extern int smb_smf_set_integer_property(smb_scfhandle_t *, char *, int64_t); +extern int smb_smf_get_integer_property(smb_scfhandle_t *, char *, int64_t *); +extern int smb_smf_set_boolean_property(smb_scfhandle_t *, char *, uint8_t); +extern int smb_smf_get_boolean_property(smb_scfhandle_t *, char *, uint8_t *); +extern int smb_smf_set_opaque_property(smb_scfhandle_t *, char *, + void *, size_t); +extern int smb_smf_get_opaque_property(smb_scfhandle_t *, char *, + void *, size_t); + +extern int smb_smf_create_service_pgroup(smb_scfhandle_t *, char *); +extern int smb_smf_delete_service_pgroup(smb_scfhandle_t *, char *); +extern int smb_smf_create_instance_pgroup(smb_scfhandle_t *, char *); +extern int smb_smf_delete_instance_pgroup(smb_scfhandle_t *, char *); +extern int smb_smf_delete_property(smb_scfhandle_t *, char *); +extern int smb_smf_instance_exists(smb_scfhandle_t *, char *); +extern int smb_smf_instance_create(smb_scfhandle_t *, char *, char *); +extern int smb_smf_instance_delete(smb_scfhandle_t *, char *); +extern smb_scfhandle_t *smb_smf_get_iterator(char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBSHARE_SMBFS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libshare/smbfs/mapfile-vers Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate_1.1 { + global: + sa_plugin_ops; + local: + *; +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libshare/smbfs/smbfs_scfutil.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,991 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* helper functions for using libscf with CIFS */ + +#include <libscf.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <errno.h> +#include <uuid/uuid.h> +#include <sys/param.h> +#include <libintl.h> +#include <assert.h> +#include <strings.h> + +#include "libshare.h" +#include "libshare_smbfs.h" + +/* + * smb_smf_scf_log_error(msg) + * Logs error messages from scf API's + */ +static void +smb_smf_scf_log_error(char *msg) +{ + if (!msg) { + syslog(LOG_ERR, " SMBC SMF problem: %s\n", + scf_strerror(scf_error())); + } else { /*LINTED E_SEC_PRINTF_E_VAR_FMT*/ + syslog(LOG_ERR, msg, scf_strerror(scf_error())); + } +} + +/* + * smb_smf_scf_fini(handle) + * + * must be called when done. Called with the handle allocated in + * smb_smf_scf_init(), it cleans up the state and frees any SCF resources + * still in use. + */ +void +smb_smf_scf_fini(smb_scfhandle_t *handle) +{ + if (handle != NULL) { + int unbind = 0; + if (handle->scf_pg_iter != NULL) { + scf_iter_destroy(handle->scf_pg_iter); + handle->scf_pg_iter = NULL; + } + if (handle->scf_inst_iter != NULL) { + scf_iter_destroy(handle->scf_inst_iter); + handle->scf_inst_iter = NULL; + } + if (handle->scf_scope != NULL) { + unbind = 1; + scf_scope_destroy(handle->scf_scope); + handle->scf_scope = NULL; + } + if (handle->scf_instance != NULL) { + scf_instance_destroy(handle->scf_instance); + handle->scf_instance = NULL; + } + if (handle->scf_service != NULL) { + scf_service_destroy(handle->scf_service); + handle->scf_service = NULL; + } + if (handle->scf_pg != NULL) { + scf_pg_destroy(handle->scf_pg); + handle->scf_pg = NULL; + } + if (handle->scf_handle != NULL) { + handle->scf_state = SCH_STATE_UNINIT; + if (unbind) + (void) scf_handle_unbind(handle->scf_handle); + scf_handle_destroy(handle->scf_handle); + handle->scf_handle = NULL; + } + free(handle); + } +} + + +/* + * Check if instance with given name exists for a service. + * Returns 0 is instance exist + */ +int +smb_smf_instance_exists(smb_scfhandle_t *handle, char *inst_name) +{ + int ret = SMBC_SMF_OK; + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + handle->scf_instance = scf_instance_create(handle->scf_handle); + if (scf_service_get_instance(handle->scf_service, inst_name, + handle->scf_instance) != SCF_SUCCESS) { + ret = SMBC_SMF_SYSTEM_ERR; + } + scf_instance_destroy(handle->scf_instance); + handle->scf_instance = NULL; + return (ret); +} + +/* + * Create a service instance. returns 0 if successful. + * If instance already exists enable it. + */ +int +smb_smf_instance_create(smb_scfhandle_t *handle, char *serv_prefix, + char *inst_name) +{ + char *instance; + int ret = SMBC_SMF_OK; + int sz; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + if (!serv_prefix || !inst_name) { + return (SMBC_SMF_SYSTEM_ERR); + } + sz = strlen(serv_prefix) + strlen(inst_name) + 2; + instance = malloc(sz); + if (!instance) { + return (SMBC_SMF_SYSTEM_ERR); + } + (void) snprintf(instance, sz, "%s:%s", serv_prefix, inst_name); + handle->scf_instance = scf_instance_create(handle->scf_handle); + if (scf_service_get_instance(handle->scf_service, inst_name, + handle->scf_instance) != SCF_SUCCESS) { + if (scf_service_add_instance(handle->scf_service, + inst_name, handle->scf_instance) == SCF_SUCCESS) { + if (smf_enable_instance(instance, 0)) + ret = SMBC_SMF_SYSTEM_ERR; + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + } else { + if (smf_enable_instance(instance, 0)) + ret = SMBC_SMF_SYSTEM_ERR; + } + free(instance); + return (ret); +} + +/* + * Delete a specified instance. Return SMBC_SMF_OK for success. + */ +int +smb_smf_instance_delete(smb_scfhandle_t *handle, char *inst_name) +{ + int ret = SMBC_SMF_OK; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + handle->scf_instance = scf_instance_create(handle->scf_handle); + if (scf_service_get_instance(handle->scf_service, inst_name, + handle->scf_instance) == SCF_SUCCESS) { + if (scf_instance_delete(handle->scf_instance) == SCF_SUCCESS) { + return (ret); + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + } else { + smb_smf_scf_log_error(NULL); + ret = SMBC_SMF_SYSTEM_ERR; + } + return (ret); +} + +/* + * smb_smf_scf_init() + * + * must be called before using any of the SCF functions. + * Returns smb_scfhandle_t pointer if success. + */ +smb_scfhandle_t * +smb_smf_scf_init(char *svc_name) +{ + smb_scfhandle_t *handle; + + handle = malloc(sizeof (smb_scfhandle_t)); + if (handle != NULL) { + bzero((char *)handle, sizeof (smb_scfhandle_t)); + handle->scf_state = SCH_STATE_INITIALIZING; + handle->scf_handle = scf_handle_create(SCF_VERSION); + if (handle->scf_handle != NULL) { + if (scf_handle_bind(handle->scf_handle) == 0) { + handle->scf_scope = + scf_scope_create(handle->scf_handle); + if (scf_handle_get_local_scope( + handle->scf_handle, handle->scf_scope) != 0) + goto err; + + handle->scf_service = + scf_service_create(handle->scf_handle); + + if (scf_scope_get_service(handle->scf_scope, + svc_name, handle->scf_service) + != SCF_SUCCESS) { + goto err; + } + handle->scf_pg = + scf_pg_create(handle->scf_handle); + handle->scf_state = SCH_STATE_INIT; + } else { + goto err; + } + } else { + free(handle); + handle = NULL; + smb_smf_scf_log_error("Could not access SMF " + "repository: %s\n"); + } + } + return (handle); + + /* error handling/unwinding */ +err: + (void) smb_smf_scf_fini(handle); + (void) smb_smf_scf_log_error("SMF initialization problem: %s\n"); + return (NULL); +} + +/* + * smb_smf_create_service_pgroup(handle, pgroup) + * + * create a new property group at service level. + */ +int +smb_smf_create_service_pgroup(smb_scfhandle_t *handle, char *pgroup) +{ + int ret = SMBC_SMF_OK; + int err; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + /* + * only create a handle if it doesn't exist. It is ok to exist + * since the pg handle will be set as a side effect. + */ + if (handle->scf_pg == NULL) { + handle->scf_pg = scf_pg_create(handle->scf_handle); + } + /* + * if the pgroup exists, we are done. If it doesn't, then we + * need to actually add one to the service instance. + */ + if (scf_service_get_pg(handle->scf_service, + pgroup, handle->scf_pg) != 0) { + /* doesn't exist so create one */ + if (scf_service_add_pg(handle->scf_service, pgroup, + SCF_GROUP_FRAMEWORK, 0, handle->scf_pg) != 0) { + err = scf_error(); + if (err != SCF_ERROR_NONE) + smb_smf_scf_log_error(NULL); + switch (err) { + case SCF_ERROR_PERMISSION_DENIED: + ret = SMBC_SMF_NO_PERMISSION; + break; + default: + ret = SMBC_SMF_SYSTEM_ERR; + break; + } + } + } + return (ret); +} + +/* + * smb_smf_create_instance_pgroup(handle, pgroup) + * + * create a new property group at instance level. + */ +int +smb_smf_create_instance_pgroup(smb_scfhandle_t *handle, char *pgroup) +{ + int ret = SMBC_SMF_OK; + int err; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + /* + * only create a handle if it doesn't exist. It is ok to exist + * since the pg handle will be set as a side effect. + */ + if (handle->scf_pg == NULL) { + handle->scf_pg = scf_pg_create(handle->scf_handle); + } + + /* + * if the pgroup exists, we are done. If it doesn't, then we + * need to actually add one to the service instance. + */ + if (scf_instance_get_pg(handle->scf_instance, + pgroup, handle->scf_pg) != 0) { + /* doesn't exist so create one */ + if (scf_instance_add_pg(handle->scf_instance, pgroup, + SCF_GROUP_APPLICATION, 0, handle->scf_pg) != 0) { + err = scf_error(); + if (err != SCF_ERROR_NONE) + smb_smf_scf_log_error(NULL); + switch (err) { + case SCF_ERROR_PERMISSION_DENIED: + ret = SMBC_SMF_NO_PERMISSION; + break; + default: + ret = SMBC_SMF_SYSTEM_ERR; + break; + } + } + } + return (ret); +} + +/* + * smb_smf_delete_service_pgroup(handle, pgroup) + * + * remove the property group from the current service. + * but only if it actually exists. + */ +int +smb_smf_delete_service_pgroup(smb_scfhandle_t *handle, char *pgroup) +{ + int ret = SMBC_SMF_OK; + int err; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + /* + * only create a handle if it doesn't exist. It is ok to exist + * since the pg handle will be set as a side effect. + */ + if (handle->scf_pg == NULL) { + handle->scf_pg = scf_pg_create(handle->scf_handle); + } + + /* + * only delete if it does exist. + */ + if (scf_service_get_pg(handle->scf_service, + pgroup, handle->scf_pg) == 0) { + /* does exist so delete it */ + if (scf_pg_delete(handle->scf_pg) != 0) { + ret = SMBC_SMF_SYSTEM_ERR; + err = scf_error(); + if (err != SCF_ERROR_NONE) { + smb_smf_scf_log_error("SMF delpg " + "problem: %s\n"); + } + } + } else { + err = scf_error(); + if (err != SCF_ERROR_NONE) + smb_smf_scf_log_error("SMF getpg problem: %s\n"); + ret = SMBC_SMF_SYSTEM_ERR; + } + if (ret == SMBC_SMF_SYSTEM_ERR && + scf_error() == SCF_ERROR_PERMISSION_DENIED) { + ret = SMBC_SMF_NO_PERMISSION; + } + return (ret); +} + +/* + * smb_smf_delete_instance_pgroup(handle, pgroup) + * + * remove the property group from the current instance. + * but only if it actually exists. + */ +int +smb_smf_delete_instance_pgroup(smb_scfhandle_t *handle, char *pgroup) +{ + int ret = SMBC_SMF_OK; + int err; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + /* + * only create a handle if it doesn't exist. It is ok to exist + * since the pg handle will be set as a side effect. + */ + if (handle->scf_pg == NULL) { + handle->scf_pg = scf_pg_create(handle->scf_handle); + } + + /* + * only delete if it does exist. + */ + if (scf_instance_get_pg(handle->scf_instance, + pgroup, handle->scf_pg) == 0) { + /* does exist so delete it */ + if (scf_pg_delete(handle->scf_pg) != 0) { + ret = SMBC_SMF_SYSTEM_ERR; + err = scf_error(); + if (err != SCF_ERROR_NONE) { + smb_smf_scf_log_error("SMF delpg " + "problem: %s\n"); + } + } + } else { + err = scf_error(); + if (err != SCF_ERROR_NONE) + smb_smf_scf_log_error("SMF getpg problem: %s\n"); + ret = SMBC_SMF_SYSTEM_ERR; + } + if (ret == SMBC_SMF_SYSTEM_ERR && + scf_error() == SCF_ERROR_PERMISSION_DENIED) { + ret = SMBC_SMF_NO_PERMISSION; + } + return (ret); +} + +/* + * Start transaction on current pg in handle. + * The pg could be service or instance level. + * Must be called after pg handle is obtained + * from create or get. + */ +int +smb_smf_start_transaction(smb_scfhandle_t *handle) +{ + int ret = SMBC_SMF_OK; + + if (!handle || (!handle->scf_pg)) { + return (SMBC_SMF_SYSTEM_ERR); + } + /* + * lookup the property group and create it if it doesn't already + * exist. + */ + if (handle->scf_state == SCH_STATE_INIT) { + if (ret == SMBC_SMF_OK) { + handle->scf_trans = + scf_transaction_create(handle->scf_handle); + if (handle->scf_trans != NULL) { + if (scf_transaction_start(handle->scf_trans, + handle->scf_pg) != 0) { + ret = SMBC_SMF_SYSTEM_ERR; + scf_transaction_destroy( + handle->scf_trans); + handle->scf_trans = NULL; + } + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + } + } + if (ret == SMBC_SMF_SYSTEM_ERR && + scf_error() == SCF_ERROR_PERMISSION_DENIED) { + ret = SMBC_SMF_NO_PERMISSION; + } + return (ret); +} + +/* + * smb_smf_end_transaction(handle) + * + * Commit the changes that were added to the transaction in the + * handle. Do all necessary cleanup. + */ +int +smb_smf_end_transaction(smb_scfhandle_t *handle) +{ + int ret = SMBC_SMF_OK; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + if (handle->scf_trans == NULL) { + ret = SMBC_SMF_SYSTEM_ERR; + } else { + if (scf_transaction_commit(handle->scf_trans) < 0) { + ret = SMBC_SMF_SYSTEM_ERR; + smb_smf_scf_log_error("Failed to commit " + "transaction: %s"); + } + scf_transaction_destroy_children(handle->scf_trans); + scf_transaction_destroy(handle->scf_trans); + handle->scf_trans = NULL; + } + return (ret); +} + +/* + * Deletes property in current pg + */ +int +smb_smf_delete_property(smb_scfhandle_t *handle, char *propname) +{ + int ret = SMBC_SMF_OK; + scf_transaction_entry_t *entry = NULL; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + /* + * properties must be set in transactions and don't take + * effect until the transaction has been ended/committed. + */ + entry = scf_entry_create(handle->scf_handle); + if (entry != NULL) { + if (scf_transaction_property_delete(handle->scf_trans, entry, + propname) != 0) { + ret = SMBC_SMF_SYSTEM_ERR; + } + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + if (ret == SMBC_SMF_SYSTEM_ERR) { + switch (scf_error()) { + case SCF_ERROR_PERMISSION_DENIED: + ret = SMBC_SMF_NO_PERMISSION; + break; + } + } + + /* + * cleanup if there were any errors that didn't leave these + * values where they would be cleaned up later. + */ + if ((ret != SMBC_SMF_OK) && (entry != NULL)) { + scf_entry_destroy(entry); + } + return (ret); +} + +/* + * Sets string property in current pg + */ +int +smb_smf_set_string_property(smb_scfhandle_t *handle, + char *propname, char *valstr) +{ + int ret = SMBC_SMF_OK; + scf_value_t *value = NULL; + scf_transaction_entry_t *entry = NULL; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + /* + * properties must be set in transactions and don't take + * effect until the transaction has been ended/committed. + */ + value = scf_value_create(handle->scf_handle); + entry = scf_entry_create(handle->scf_handle); + if (value != NULL && entry != NULL) { + if (scf_transaction_property_change(handle->scf_trans, entry, + propname, SCF_TYPE_ASTRING) == 0 || + scf_transaction_property_new(handle->scf_trans, entry, + propname, SCF_TYPE_ASTRING) == 0) { + if (scf_value_set_astring(value, valstr) == 0) { + if (scf_entry_add_value(entry, value) != 0) { + ret = SMBC_SMF_SYSTEM_ERR; + scf_value_destroy(value); + } + /* the value is in the transaction */ + value = NULL; + } else { + /* value couldn't be constructed */ + ret = SMBC_SMF_SYSTEM_ERR; + } + /* the entry is in the transaction */ + entry = NULL; + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + if (ret == SMBC_SMF_SYSTEM_ERR) { + switch (scf_error()) { + case SCF_ERROR_PERMISSION_DENIED: + ret = SMBC_SMF_NO_PERMISSION; + break; + } + } + + /* + * cleanup if there were any errors that didn't leave these + * values where they would be cleaned up later. + */ + if (value != NULL) + scf_value_destroy(value); + if (entry != NULL) + scf_entry_destroy(entry); + return (ret); +} + +/* + * Gets string property value.upto sz size. + * Caller is responsible to have enough memory allocated. + */ +int +smb_smf_get_string_property(smb_scfhandle_t *handle, char *propname, + char *valstr, size_t sz) +{ + int ret = SMBC_SMF_OK; + scf_value_t *value; + scf_property_t *prop; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + value = scf_value_create(handle->scf_handle); + prop = scf_property_create(handle->scf_handle); + if (value && prop && + (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { + if (scf_property_get_value(prop, value) == 0) { + if (scf_value_get_astring(value, valstr, sz) < 0) { + ret = SMBC_SMF_SYSTEM_ERR; + } + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + if (value != NULL) + scf_value_destroy(value); + if (prop != NULL) + scf_property_destroy(prop); + return (ret); +} + +/* + * Get integer value of property. + * The value is returned as int64_t value + * Caller ensures appropriate translation. + */ +int +smb_smf_set_integer_property(smb_scfhandle_t *handle, char *propname, + int64_t valint) +{ + int ret = SMBC_SMF_OK; + scf_value_t *value = NULL; + scf_transaction_entry_t *entry = NULL; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + /* + * properties must be set in transactions and don't take + * effect until the transaction has been ended/committed. + */ + value = scf_value_create(handle->scf_handle); + entry = scf_entry_create(handle->scf_handle); + if (value != NULL && entry != NULL) { + if (scf_transaction_property_change(handle->scf_trans, entry, + propname, SCF_TYPE_INTEGER) == 0 || + scf_transaction_property_new(handle->scf_trans, entry, + propname, SCF_TYPE_INTEGER) == 0) { + scf_value_set_integer(value, valint); + if (scf_entry_add_value(entry, value) != 0) { + ret = SMBC_SMF_SYSTEM_ERR; + scf_value_destroy(value); + } + /* the value is in the transaction */ + value = NULL; + } + /* the entry is in the transaction */ + entry = NULL; + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + if (ret == SMBC_SMF_SYSTEM_ERR) { + switch (scf_error()) { + case SCF_ERROR_PERMISSION_DENIED: + ret = SMBC_SMF_NO_PERMISSION; + break; + } + } + /* + * cleanup if there were any errors that didn't leave these + * values where they would be cleaned up later. + */ + if (value != NULL) + scf_value_destroy(value); + if (entry != NULL) + scf_entry_destroy(entry); + return (ret); +} + +/* + * Sets integer property value. + * Caller is responsible to have enough memory allocated. + */ +int +smb_smf_get_integer_property(smb_scfhandle_t *handle, char *propname, + int64_t *valint) +{ + int ret = SMBC_SMF_OK; + scf_value_t *value = NULL; + scf_property_t *prop = NULL; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + value = scf_value_create(handle->scf_handle); + prop = scf_property_create(handle->scf_handle); + if ((prop) && (value) && + (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { + if (scf_property_get_value(prop, value) == 0) { + if (scf_value_get_integer(value, + valint) != 0) { + ret = SMBC_SMF_SYSTEM_ERR; + } + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + if (value != NULL) + scf_value_destroy(value); + if (prop != NULL) + scf_property_destroy(prop); + return (ret); +} + +/* + * Get boolean value of property. + * The value is returned as int64_t value + * Caller ensures appropriate translation. + */ +int +smb_smf_set_boolean_property(smb_scfhandle_t *handle, char *propname, + uint8_t valbool) +{ + int ret = SMBC_SMF_OK; + scf_value_t *value = NULL; + scf_transaction_entry_t *entry = NULL; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + /* + * properties must be set in transactions and don't take + * effect until the transaction has been ended/committed. + */ + value = scf_value_create(handle->scf_handle); + entry = scf_entry_create(handle->scf_handle); + if (value != NULL && entry != NULL) { + if (scf_transaction_property_change(handle->scf_trans, entry, + propname, SCF_TYPE_BOOLEAN) == 0 || + scf_transaction_property_new(handle->scf_trans, entry, + propname, SCF_TYPE_BOOLEAN) == 0) { + scf_value_set_boolean(value, valbool); + if (scf_entry_add_value(entry, value) != 0) { + ret = SMBC_SMF_SYSTEM_ERR; + scf_value_destroy(value); + } + /* the value is in the transaction */ + value = NULL; + } + /* the entry is in the transaction */ + entry = NULL; + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + if (ret == SMBC_SMF_SYSTEM_ERR) { + switch (scf_error()) { + case SCF_ERROR_PERMISSION_DENIED: + ret = SMBC_SMF_NO_PERMISSION; + break; + } + } + /* + * cleanup if there were any errors that didn't leave these + * values where they would be cleaned up later. + */ + if (value != NULL) + scf_value_destroy(value); + if (entry != NULL) + scf_entry_destroy(entry); + return (ret); +} + +/* + * Sets boolean property value. + * Caller is responsible to have enough memory allocated. + */ +int +smb_smf_get_boolean_property(smb_scfhandle_t *handle, char *propname, + uint8_t *valbool) +{ + int ret = SMBC_SMF_OK; + scf_value_t *value = NULL; + scf_property_t *prop = NULL; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + value = scf_value_create(handle->scf_handle); + prop = scf_property_create(handle->scf_handle); + if ((prop) && (value) && + (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { + if (scf_property_get_value(prop, value) == 0) { + if (scf_value_get_boolean(value, + valbool) != 0) { + ret = SMBC_SMF_SYSTEM_ERR; + } + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + if (value != NULL) + scf_value_destroy(value); + if (prop != NULL) + scf_property_destroy(prop); + return (ret); +} + +/* + * Sets a blob property value. + */ +int +smb_smf_set_opaque_property(smb_scfhandle_t *handle, char *propname, + void *voidval, size_t sz) +{ + int ret = SMBC_SMF_OK; + scf_value_t *value; + scf_transaction_entry_t *entry; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + /* + * properties must be set in transactions and don't take + * effect until the transaction has been ended/committed. + */ + value = scf_value_create(handle->scf_handle); + entry = scf_entry_create(handle->scf_handle); + if (value != NULL && entry != NULL) { + if (scf_transaction_property_change(handle->scf_trans, entry, + propname, SCF_TYPE_OPAQUE) == 0 || + scf_transaction_property_new(handle->scf_trans, entry, + propname, SCF_TYPE_OPAQUE) == 0) { + if (scf_value_set_opaque(value, voidval, sz) == 0) { + if (scf_entry_add_value(entry, value) != 0) { + ret = SMBC_SMF_SYSTEM_ERR; + scf_value_destroy(value); + } + /* the value is in the transaction */ + value = NULL; + } else { + /* value couldn't be constructed */ + ret = SMBC_SMF_SYSTEM_ERR; + } + /* the entry is in the transaction */ + entry = NULL; + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + if (ret == SMBC_SMF_SYSTEM_ERR) { + switch (scf_error()) { + case SCF_ERROR_PERMISSION_DENIED: + ret = SMBC_SMF_NO_PERMISSION; + break; + } + } + /* + * cleanup if there were any errors that didn't leave these + * values where they would be cleaned up later. + */ + if (value != NULL) + scf_value_destroy(value); + if (entry != NULL) + scf_entry_destroy(entry); + return (ret); +} + +/* + * Gets a blob property value. + * Caller is responsible to have enough memory allocated. + */ +int +smb_smf_get_opaque_property(smb_scfhandle_t *handle, char *propname, + void *v, size_t sz) +{ + int ret = SMBC_SMF_OK; + scf_value_t *value = NULL; + scf_property_t *prop = NULL; + + if (handle == NULL) { + return (SMBC_SMF_SYSTEM_ERR); + } + + value = scf_value_create(handle->scf_handle); + prop = scf_property_create(handle->scf_handle); + if ((prop) && (value) && + (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { + if (scf_property_get_value(prop, value) == 0) { + if (scf_value_get_opaque(value, (char *)v, sz) != sz) { + ret = SMBC_SMF_SYSTEM_ERR; + } + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + } else { + ret = SMBC_SMF_SYSTEM_ERR; + } + if (value != NULL) + scf_value_destroy(value); + if (prop != NULL) + scf_property_destroy(prop); + return (ret); +} + +/* + * Gets an instance iterator for the service specified. + */ +smb_scfhandle_t * +smb_smf_get_iterator(char *svc_name) +{ + smb_scfhandle_t *handle = NULL; + + handle = smb_smf_scf_init(svc_name); + if (!handle) { + return (NULL); + } + + handle->scf_inst_iter = scf_iter_create(handle->scf_handle); + if (handle->scf_inst_iter) { + if (scf_iter_service_instances(handle->scf_inst_iter, + handle->scf_service) != 0) { + smb_smf_scf_fini(handle); + handle = NULL; + } else { + handle->scf_instance = NULL; + } + } else { + smb_smf_scf_fini(handle); + handle = NULL; + } + return (handle); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libshare/smbfs/sparc/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libshare/smbfs/sparcv9/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +include ../Makefile.com +include ../../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,72 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# lib/libsmbfs/Makefile +# + +include $(SRC)/lib/Makefile.lib + +# ISA targets +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +# conditional assignments +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint + +POFILE = libsmbfs.po + +.KEEP_STATE: + +all install clean clobber lint: $(SUBDIRS) + +include $(SRC)/Makefile.msg.targ + +MSGFILES=smb/cfopt.c smb/charsets.c smb/charsets.h smb/ctx.c smb/derparse.c \ + smb/derparse.h smb/file.c smb/keychain.c smb/mbuf.c smb/nb.c \ + smb/nb_name.c smb/nb_net.c smb/nbns_rq.c smb/netshareenum.c \ + smb/nls.c smb/print.c smb/queue.h smb/rap.c smb/rcfile.c \ + smb/rcfile_priv.h smb/rq.c smb/spnego.c smb/spnego.h \ + smb/spnegoparse.c smb/spnegoparse.h smb/subr.c smb/ui-sun.c + +_msg: $(MSGDOMAINPOFILE) + +$(MSGDOMAINPOFILE): $(POFILE) + +$(POFILE): $(MSGFILES) + $(BUILDPO.msgfiles) + +install: $(ROOTLIBS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include $(SRC)/lib/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/Makefile.com Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,98 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# lib/libsmbfs/Makefile.com + +LIBRARY= libsmbfs.a +VERS= .1 + +# leaving out: kiconv.o + +OBJECTS=\ + charsets.o \ + cfopt.o \ + ctx.o \ + derparse.o \ + file.o \ + keychain.o \ + mbuf.o \ + nb.o \ + nb_name.o \ + nb_net.o \ + nbns_rq.o \ + netshareenum.o \ + nls.o \ + print.o \ + rap.o \ + rcfile.o \ + rq.o \ + spnego.o \ + spnegoparse.o \ + subr.o \ + ui-sun.o + +include $(SRC)/lib/Makefile.lib + +LIBS = $(DYNLIB) $(LINTLIB) + +SRCDIR= ../smb + +SRCS= $(OBJECTS:%.o=../smb/%.c) + +$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) + +C99MODE= $(C99_ENABLE) + +LDLIBS += -lsocket -lnsl -lc -lkrb5 + +# normal warnings... +CFLAGS += $(CCVERBOSE) + +CPPFLAGS += -D__EXTENSIONS__ -D_REENTRANT -DMIA \ + -I$(SRCDIR) -I.. -I$(SRC)/uts/common + +# uncomment these if you want to use dbx +#COPTFLAG = -g +#CTF_FLAGS = +#CTFCONVERT_O= +#CTFMERGE_LIB= + +# disable some of the less important lint +LINTCHECKFLAGS += -erroff=E_FUNC_ARG_UNUSED +LINTCHECKFLAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2 +LINTCHECKFLAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2 +LINTCHECKFLAGS += -erroff=E_FUNC_VAR_UNUSED +LINTCHECKFLAGS += -erroff=E_STATIC_UNUSED +LINTCHECKFLAGS += -erroff=E_CONSTANT_CONDITION +LINTCHECKFLAGS += -erroff=E_TRUE_LOGICAL_EXPR + +.KEEP_STATE: + +all: $(LIBS) + +lint: lintcheck + +include ../../Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/amd64/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/cflib.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: cflib.h,v 1.1.1.1 2001/06/09 00:28:11 zarzycki Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef _CFLIB_H_ +#define _CFLIB_H_ + +struct rcfile; + +/* + * A unified options parser + */ +enum opt_argtype {OPTARG_STR, OPTARG_INT, OPTARG_BOOL}; + +struct opt_args; + +typedef int opt_callback_t (struct opt_args *); + +#define OPTFL_NONE 0x0000 +#define OPTFL_HAVEMIN 0x0001 +#define OPTFL_HAVEMAX 0x0002 +#define OPTFL_MINMAX NAFL_HAVEMIN | NAFL_HAVEMAX + +struct opt_args { + enum opt_argtype type; + int opt; /* command line option */ + char *name; /* rc file equiv */ + int flag; /* OPTFL_* */ + int ival; /* int/bool values, or max len for str value */ + char *str; /* string value */ + int min; /* min for ival */ + int max; /* max for ival */ + opt_callback_t *fn; /* call back to validate */ +}; +typedef struct opt_args opt_args_t; + +extern int cf_opterr, cf_optind, cf_optopt, cf_optreset; +extern const char *cf_optarg; + +#ifdef __cplusplus +extern "C" { +#endif + +int opt_args_parse(struct rcfile *, struct opt_args *, const char *, + opt_callback_t *); +int opt_args_parseopt(struct opt_args *, int, char *, opt_callback_t *); + +int cf_getopt(int, char * const *, const char *); + +int rc_open(const char *, const char *, struct rcfile **); +int rc_close(struct rcfile *); +int rc_merge(const char *, struct rcfile **); +int rc_merge_pipe(const char *, struct rcfile **); +int rc_getstringptr(struct rcfile *, const char *, const char *, char **); +int rc_getstring(struct rcfile *, const char *, const char *, size_t, char *); +int rc_getint(struct rcfile *, const char *, const char *, int *); +int rc_getbool(struct rcfile *, const char *, const char *, int *); + +#ifdef __cplusplus +} +#endif + +#endif /* _CFLIB_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/i386/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/netsmb/nb_lib.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2000, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: nb_lib.h,v 1.4 2004/12/11 05:23:58 lindak Exp $ + */ + +#ifndef _NETSMB_NB_LIB_H_ +#define _NETSMB_NB_LIB_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Error codes + */ +#define NBERR_INVALIDFORMAT 0x0001 +#define NBERR_SRVFAILURE 0x0002 +#define NBERR_NAMENOTFOUND 0x0003 +#define NBERR_IMP 0x0004 +#define NBERR_REFUSED 0x0005 +#define NBERR_ACTIVE 0x0006 +#define NBERR_HOSTNOTFOUND 0x0101 +#define NBERR_TOOMANYREDIRECTS 0x0102 +#define NBERR_INVALIDRESPONSE 0x0103 +#define NBERR_NAMETOOLONG 0x0104 +#define NBERR_NOBCASTIFS 0x0105 +#define NBERR_MAX 0x0106 +#define NBERROR(e) ((e) | SMB_NB_ERROR) + +#define NBCF_RESOLVED 0x0001 +#define NBCF_NS_ENABLE 0x0002 /* any NetBIOS lookup */ +#define NBCF_BC_ENABLE 0x0004 /* lookup via broadcast */ + +/* + * nb environment + */ +struct nb_ctx { + int nb_flags; + int nb_timo; + char *nb_scope; /* NetBIOS scope */ + in_addr_t nb_wins1; /* primary WINS */ + in_addr_t nb_wins2; /* secondary WINS (unused now) */ + struct sockaddr_in nb_lastns; /* see cmd:lookup.c */ +}; +typedef struct nb_ctx nb_ctx_t; + +/* + * resource record + */ +struct nbns_rr { + uchar_t *rr_name; /* compressed NETBIOS name */ + uint16_t rr_type; + uint16_t rr_class; + uint32_t rr_ttl; + uint16_t rr_rdlength; + uchar_t *rr_data; +}; +typedef struct nbns_rr nfns_rr_t; + +/* + * NetBIOS name return + */ +struct nbns_nr { + char ns_name[NB_NAMELEN]; + uint16_t ns_flags; +}; +typedef struct nbns_nr nbns_nr_t; + +#define NBRQF_POINT 0x0000 +#define NBRQF_BROADCAST 0x0001 + +#define NBNS_GROUPFLG 0x8000 + +/* + * nbns request + */ +struct nbns_rq { + int nr_opcode; + int nr_nmflags; + int nr_rcode; + int nr_qdcount; + int nr_ancount; + int nr_nscount; + int nr_arcount; + struct nb_name *nr_qdname; + uint16_t nr_qdtype; + uint16_t nr_qdclass; + struct in_addr nr_dest; /* receiver of query */ + struct sockaddr_in nr_sender; /* sender of response */ + int nr_rpnmflags; + int nr_rprcode; + uint16_t nr_rpancount; + uint16_t nr_rpnscount; + uint16_t nr_rparcount; + uint16_t nr_trnid; + struct nb_ctx *nr_nbd; + struct mbdata nr_rq; + struct mbdata nr_rp; + struct nb_ifdesc *nr_if; + int nr_flags; + int nr_fd; + int nr_maxretry; +}; +typedef struct nbns_rq nbns_rq_t; + +struct nb_ifdesc { + int id_flags; + struct in_addr id_addr; + struct in_addr id_mask; + char id_name[16]; /* actually IFNAMSIZ */ + struct nb_ifdesc *id_next; +}; +typedef struct nb_ifdesc nb_ifdesc_t; + +struct sockaddr; + +#ifdef __cplusplus +extern "C" { +#endif + +int nb_name_len(struct nb_name *); +/* new flag UCflag. 1=uppercase,0=don't */ +int nb_name_encode(struct nb_name *, uchar_t *); +int nb_encname_len(const uchar_t *); + +int nb_snballoc(int namelen, struct sockaddr_nb **); +void nb_snbfree(struct sockaddr *); +int nb_sockaddr(struct sockaddr *, struct nb_name *, struct sockaddr_nb **); + +int nb_resolvehost_in(const char *, struct sockaddr **); +int nbns_resolvename(const char *, struct nb_ctx *, struct sockaddr **); +int nbns_getnodestatus(struct sockaddr *targethost, + struct nb_ctx *ctx, char *system, char *workgroup); +int nb_getlocalname(char *name, size_t maxlen); +int nb_enum_if(struct nb_ifdesc **); + +const char *nb_strerror(int error); + +int nb_ctx_create(struct nb_ctx **); +void nb_ctx_done(struct nb_ctx *); +int nb_ctx_setns(struct nb_ctx *, const char *); +int nb_ctx_setscope(struct nb_ctx *, const char *); +int nb_ctx_resolve(struct nb_ctx *); +int nb_ctx_readrcsection(struct rcfile *, struct nb_ctx *, const char *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* !_NETSMB_NB_LIB_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/netsmb/smb_keychain.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,82 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SMB_KEYCHAIN_H +#define _SMB_KEYCHAIN_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * External interface to the libsmbfs/netsmb keychain + * storage mechanism. This interface is consumed by + * the "smbutil" commands: login, logout, ... + * and by the SMBFS PAM module. + */ + +#define SMB_KEYCHAIN_SUCCESS 0 +#define SMB_KEYCHAIN_BADPASSWD 300 +#define SMB_KEYCHAIN_BADDOMAIN 301 +#define SMB_KEYCHAIN_BADUSER 302 +#define SMB_KEYCHAIN_NODRIVER 303 +#define SMB_KEYCHAIN_UNKNOWN 304 + +/* Add a password to the keychain. */ +int smbfs_keychain_add(uid_t uid, const char *domain, const char *user, + const char *password); + +/* Delete a password from the keychain. */ +int smbfs_keychain_del(uid_t uid, const char *domain, const char *user); + +/* + * Check for existence of a keychain entry. + * Returns 0 if it exists, else ENOENT. + */ +int smbfs_keychain_chk(const char *domain, const char *user); + +/* + * Delete all keychain entries owned by the caller. + */ +int smbfs_keychain_del_owner(void); + +/* + * Delete all keychain entries (regardless of owner). + * Requires super-user privliege. + */ +int smbfs_keychain_del_everyone(void); + +/* + * This is not really part of the keychain library, + * but is typically needed in code that wants to + * provide (editable) defaults for domain/user + * + * Get default domain and user names + * Server name is optional. + */ +int +smbfs_default_dom_usr(const char *home, const char *server, + char *dom, int maxdom, char *usr, int maxusr); + +#endif /* _SMB_KEYCHAIN_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2000-2001 Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_lib.h,v 1.21.82.2 2005/06/02 00:55:39 lindak Exp $ + */ + +#ifndef _NETSMB_SMB_LIB_H_ +#define _NETSMB_SMB_LIB_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/byteorder.h> + +#include <netsmb/smb.h> +#include <netsmb/smb_dev.h> + +#define SMB_CFG_FILE "/etc/nsmb.conf" +#define OLD_SMB_CFG_FILE "/usr/local/etc/nsmb.conf" + +#define STDPARAM_ARGS \ + 'A':case 'B':case 'C':case 'E':case 'I':case 'L':case \ + 'M':case 'N':case 'U':case 'R':case 'S':case 'T':case \ + 'W':case 'O':case 'P' + +#define STDPARAM_OPT "ABCE:I:L:M:NO:P:U:R:S:T:W:" + +/* + * bits to indicate the source of error + */ +#define SMB_ERRTYPE_MASK 0xf0000 +#define SMB_SYS_ERROR 0x00000 +#define SMB_RAP_ERROR 0x10000 +#define SMB_NB_ERROR 0x20000 + +/* + * These get/set macros do not handle mis-aligned data. + * The data are all supposed to be aligned, but that's + * up to the server. If we ever encounter a server that + * doesn't obey this rule, a "strict alignment" client + * (i.e. SPARC) may get an alignment trap in one of these. + * If that ever happens, make these macros into functions + * that can handle mis-aligned data. (Or catch traps.) + */ +#define getb(buf, ofs) (((const uint8_t *)(buf))[ofs]) +#define setb(buf, ofs, val) (((uint8_t *)(buf))[ofs]) = val +#define getbw(buf, ofs) ((uint16_t)(getb(buf, ofs))) +#define getw(buf, ofs) (*((uint16_t *)(&((uint8_t *)(buf))[ofs]))) +#define getdw(buf, ofs) (*((uint32_t *)(&((uint8_t *)(buf))[ofs]))) + +#ifdef _LITTLE_ENDIAN + +#define getwle(buf, ofs) (*((uint16_t *)(&((uint8_t *)(buf))[ofs]))) +#define getdle(buf, ofs) (*((uint32_t *)(&((uint8_t *)(buf))[ofs]))) +#define getwbe(buf, ofs) (ntohs(getwle(buf, ofs))) +#define getdbe(buf, ofs) (ntohl(getdle(buf, ofs))) + +#define setwle(buf, ofs, val) getwle(buf, ofs) = val +#define setwbe(buf, ofs, val) getwle(buf, ofs) = htons(val) +#define setdle(buf, ofs, val) getdle(buf, ofs) = val +#define setdbe(buf, ofs, val) getdle(buf, ofs) = htonl(val) + +#else /* _LITTLE_ENDIAN */ + +#define getwbe(buf, ofs) (*((uint16_t *)(&((uint8_t *)(buf))[ofs]))) +#define getdbe(buf, ofs) (*((uint32_t *)(&((uint8_t *)(buf))[ofs]))) +#define getwle(buf, ofs) (BSWAP_16(getwbe(buf, ofs))) +#define getdle(buf, ofs) (BSWAP_32(getdbe(buf, ofs))) + +#define setwbe(buf, ofs, val) getwbe(buf, ofs) = val +#define setwle(buf, ofs, val) getwbe(buf, ofs) = BSWAP_16(val) +#define setdbe(buf, ofs, val) getdbe(buf, ofs) = val +#define setdle(buf, ofs, val) getdbe(buf, ofs) = BSWAP_32(val) + +#endif /* _LITTLE_ENDIAN */ + +/* + * SMB work context. Used to store all values which are necessary + * to establish connection to an SMB server. + */ +struct smb_ctx { + int ct_flags; /* SMBCF_ */ + int ct_fd; /* handle of connection */ + int ct_parsedlevel; + int ct_minlevel; + int ct_maxlevel; + char *ct_fullserver; /* original server name from cmd line */ + char *ct_srvaddr; /* hostname or IP address of server */ + struct sockaddr_in ct_srvinaddr; /* IP address of server */ + char ct_locname[SMB_MAXUSERNAMELEN + 1]; + struct nb_ctx *ct_nb; + struct smbioc_ossn ct_ssn; + struct smbioc_oshare ct_sh; + char *ct_origshare; + char *ct_home; +#ifdef APPLE + /* temporary automount hack */ + char **ct_xxx; + int ct_maxxxx; /* max # to mount (-x arg) */ +#endif + void *ct_secblob; + int ct_secbloblen; + /* krb5 stuff: all anonymous struct pointers here. */ + struct _krb5_context *ct_krb5ctx; + struct _krb5_ccache *ct_krb5cc; /* credentials cache */ + struct krb5_principal_data *ct_krb5cp; /* client principal */ +}; +typedef struct smb_ctx smb_ctx_t; + +#define SMBCF_NOPWD 0x0001 /* don't ask for a password */ +#define SMBCF_SRIGHTS 0x0002 /* share access rights supplied */ +#define SMBCF_LOCALE 0x0004 /* use current locale */ +#define SMBCF_CMD_DOM 0x0010 /* CMD specified domain */ +#define SMBCF_CMD_USR 0x0020 /* CMD specified user */ +#define SMBCF_CMD_PW 0x0040 /* CMD specified password */ +#define SMBCF_RESOLVED 0x8000 /* structure has been verified */ +#define SMBCF_KCBAD 0x00080000 /* keychain password failed */ +#define SMBCF_KCFOUND 0x00100000 /* password is from keychain */ +#define SMBCF_BROWSEOK 0x00200000 /* browser dialogue may be used */ +#define SMBCF_AUTHREQ 0x00400000 /* auth. dialog requested */ +#define SMBCF_KCSAVE 0x00800000 /* add to keychain requested */ +#define SMBCF_XXX 0x01000000 /* mount-all, a very bad thing */ +#define SMBCF_SSNACTIVE 0x02000000 /* session setup succeeded */ +#define SMBCF_KCDOMAIN 0x04000000 /* use domain in KC lookup */ + +/* + * access modes (see also smb_dev.h) + */ +#define SMBM_READ S_IRUSR /* read conn attrs. (like list shares) */ +#define SMBM_WRITE S_IWUSR /* modify conn attrs */ +#define SMBM_EXEC S_IXUSR /* can send SMB requests */ +#define SMBM_READGRP S_IRGRP +#define SMBM_WRITEGRP S_IWGRP +#define SMBM_EXECGRP S_IXGRP +#define SMBM_READOTH S_IROTH +#define SMBM_WRITEOTH S_IWOTH +#define SMBM_EXECOTH S_IXOTH +#define SMBM_ALL S_IRWXU +#define SMBM_DEFAULT S_IRWXU + + +/* + * Share type for smb_ctx_init + */ +#define SMB_ST_DISK STYPE_DISKTREE +#define SMB_ST_PRINTER STYPE_PRINTQ +#define SMB_ST_COMM STYPE_DEVICE +#define SMB_ST_PIPE STYPE_IPC +#define SMB_ST_ANY STYPE_UNKNOWN +#define SMB_ST_MAX STYPE_UNKNOWN +#define SMB_ST_NONE 0xff /* not a part of protocol */ + + +/* + * request handling structures + */ +struct mbuf { + int m_len; + int m_maxlen; + char *m_data; + struct mbuf *m_next; +}; +typedef struct mbuf mbuf_t; + +struct mbdata { + struct mbuf *mb_top; + struct mbuf *mb_cur; + char *mb_pos; + int mb_count; +}; +typedef struct mbdata mbdata_t; + +#define M_ALIGNFACTOR (sizeof (long)) +#define M_ALIGN(len) (((len) + M_ALIGNFACTOR - 1) & ~(M_ALIGNFACTOR - 1)) +#define M_BASESIZE (sizeof (struct mbuf)) +#define M_MINSIZE (256 - M_BASESIZE) +#define M_TOP(m) ((char *)(m) + M_BASESIZE) +#define M_TRAILINGSPACE(m) ((m)->m_maxlen - (m)->m_len) +#define mtod(m, t) ((t)(m)->m_data) + +struct smb_rq { + uchar_t rq_cmd; + struct mbdata rq_rq; + struct mbdata rq_rp; + struct smb_ctx *rq_ctx; + int rq_wcount; + int rq_bcount; +}; +typedef struct smb_rq smb_rq_t; + +struct smb_bitname { + uint_t bn_bit; + char *bn_name; +}; +typedef struct smb_bitname smb_bitname_t; + +extern int smb_debug, smb_verbose; +extern struct rcfile *smb_rc; + +#ifdef __cplusplus +extern "C" { +#endif + +struct sockaddr; + +int smb_lib_init(void); +int smb_open_driver(void); +int smb_open_rcfile(struct smb_ctx *ctx); +void smb_error(const char *, int, ...); +char *smb_printb(char *, int, const struct smb_bitname *); + +/* + * Context management + */ +int smb_ctx_init(struct smb_ctx *, int, char *[], int, int, int); +void smb_ctx_done(struct smb_ctx *); +int smb_ctx_parseunc(struct smb_ctx *, const char *, int, const char **); +int smb_ctx_setcharset(struct smb_ctx *, const char *); +int smb_ctx_setfullserver(struct smb_ctx *, const char *); +void smb_ctx_setserver(struct smb_ctx *, const char *); +int smb_ctx_setuser(struct smb_ctx *, const char *, int); +int smb_ctx_setshare(struct smb_ctx *, const char *, int); +int smb_ctx_setscope(struct smb_ctx *, const char *); +int smb_ctx_setworkgroup(struct smb_ctx *, const char *, int); +int smb_ctx_setpassword(struct smb_ctx *, const char *, int); +int smb_ctx_setsrvaddr(struct smb_ctx *, const char *); +int smb_ctx_opt(struct smb_ctx *, int, const char *); +int smb_ctx_negotiate(struct smb_ctx *, int, int, char *); +int smb_ctx_tdis(struct smb_ctx *ctx); +int smb_ctx_lookup(struct smb_ctx *, int, int); +int smb_ctx_login(struct smb_ctx *); +int smb_ctx_readrc(struct smb_ctx *); +int smb_ctx_resolve(struct smb_ctx *); +int smb_ctx_setflags(struct smb_ctx *, int, int, int); +int smb_ctx_flags2(struct smb_ctx *); + +int smb_smb_open_print_file(struct smb_ctx *, int, int, const char *, smbfh*); +int smb_smb_close_print_file(struct smb_ctx *, smbfh); + +int smb_read(struct smb_ctx *, smbfh, off_t, size_t, char *); +int smb_write(struct smb_ctx *, smbfh, off_t, size_t, const char *); + +#define smb_rq_getrequest(rqp) (&(rqp)->rq_rq) +#define smb_rq_getreply(rqp) (&(rqp)->rq_rp) + +int smb_rq_init(struct smb_ctx *, uchar_t, size_t, struct smb_rq **); +void smb_rq_done(struct smb_rq *); +void smb_rq_wend(struct smb_rq *); +int smb_rq_simple(struct smb_rq *); +int smb_rq_dmem(struct mbdata *, const char *, size_t); +int smb_rq_dstring(struct mbdata *, const char *); + +int smb_t2_request(struct smb_ctx *, int, uint16_t *, const char *, + int, void *, int, void *, int *, void *, int *, void *, int *); + +void smb_simplecrypt(char *dst, const char *src); +int smb_simpledecrypt(char *dst, const char *src); + +int m_getm(struct mbuf *, size_t, struct mbuf **); +int m_lineup(struct mbuf *, struct mbuf **); +int mb_init(struct mbdata *, size_t); +int mb_initm(struct mbdata *, struct mbuf *); +int mb_done(struct mbdata *); +int mb_fit(struct mbdata *mbp, size_t size, char **pp); +int mb_put_uint8(struct mbdata *, uint8_t); +int mb_put_uint16be(struct mbdata *, uint16_t); +int mb_put_uint16le(struct mbdata *, uint16_t); +int mb_put_uint32be(struct mbdata *, uint32_t); +int mb_put_uint32le(struct mbdata *, uint32_t); +int mb_put_uint64be(struct mbdata *, uint64_t); +int mb_put_uint64le(struct mbdata *, uint64_t); +int mb_put_mem(struct mbdata *, const char *, size_t); +int mb_put_pstring(struct mbdata *mbp, const char *s); +int mb_put_mbuf(struct mbdata *, struct mbuf *); + +int mb_get_uint8(struct mbdata *, uint8_t *); +int mb_get_uint16(struct mbdata *, uint16_t *); +int mb_get_uint16le(struct mbdata *, uint16_t *); +int mb_get_uint16be(struct mbdata *, uint16_t *); +int mb_get_uint32(struct mbdata *, uint32_t *); +int mb_get_uint32be(struct mbdata *, uint32_t *); +int mb_get_uint32le(struct mbdata *, uint32_t *); +int mb_get_uint64(struct mbdata *, uint64_t *); +int mb_get_uint64be(struct mbdata *, uint64_t *); +int mb_get_uint64le(struct mbdata *, uint64_t *); +int mb_get_mem(struct mbdata *, char *, size_t); + +extern uchar_t nls_lower[256], nls_upper[256]; + +int nls_setrecode(const char *, const char *); +int nls_setlocale(const char *); +char *nls_str_toext(char *, const char *); +char *nls_str_toloc(char *, const char *); +void *nls_mem_toext(void *, const void *, int); +void *nls_mem_toloc(void *, const void *, int); +char *nls_str_upper(char *, const char *); +char *nls_str_lower(char *, const char *); + +int smb_get_authentication(char *, size_t, char *, size_t, char *, size_t, + const char *, struct smb_ctx *); +int smb_browse(struct smb_ctx *, int); +void smb_save2keychain(struct smb_ctx *); +#define smb_autherr(e) ((e) == EAUTH || (e) == EACCES || (e) == EPERM) +char *smb_strerror(int); +char *smb_getprogname(); +#define __progname smb_getprogname() + +extern char *unpercent(char *component); + +#ifdef __cplusplus +} +#endif + +#endif /* _NETSMB_SMB_LIB_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/netsmb/smb_netshareenum.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,18 @@ + +#ifndef _NETSMB_SMB_NETSHAREENUM_H_ +#define _NETSMB_SMB_NETSHAREENUM_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* This is from Apple. See ../smb/netshareenum.c */ + +struct share_info { + uint16_t type; + char *netname; + char *remark; +}; +typedef struct share_info share_info_t; + +int smb_netshareenum(struct smb_ctx *, int *, int *, struct share_info **); + +#endif /* _NETSMB_SMB_NETSHAREENUM_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/netsmb/smb_rap.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2000-2001, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_rap.h,v 1.1.1.1 2001/07/06 22:38:38 conrad Exp $ + */ + +#ifndef _NETSMB_SMB_RAP_H_ +#define _NETSMB_SMB_RAP_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +struct smb_rap { + char *r_sparam; + char *r_nparam; + char *r_sdata; + char *r_ndata; + char *r_pbuf; /* rq parameters */ + int r_plen; /* rq param len */ + char *r_npbuf; + char *r_dbuf; /* rq data */ + int r_dlen; /* rq data len */ + char *r_ndbuf; + uint32_t r_result; + char *r_rcvbuf; + int r_rcvbuflen; + int r_entries; +}; + +struct smb_share_info_1 { + char shi1_netname[13]; + char shi1_pad; + uint16_t shi1_type; + uint32_t shi1_remark; /* char * */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int smb_rap_create(int, const char *, const char *, struct smb_rap **); +void smb_rap_done(struct smb_rap *); +int smb_rap_request(struct smb_rap *, struct smb_ctx *); +int smb_rap_setNparam(struct smb_rap *, int); +int smb_rap_setPparam(struct smb_rap *, void *); +int smb_rap_error(struct smb_rap *, int); + +int smb_rap_NetShareEnum(struct smb_ctx *, int, void *, int *, int *, int *); + +#ifdef __cplusplus +} +#endif + +#endif /* _NETSMB_SMB_RAP_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2001 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,1 @@ +PORTIONS OF LIBSMBFS IN CIFS CLIENT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,29 @@ + Copyright (c) 2000, 2001 Boris Popov + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by Boris Popov. + 4. Neither the name of the author nor the names of any co-contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,1 @@ +CIFS CLIENT SOFTWARE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4 Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1982, 1986, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,1 @@ +PORTIONS OF LIBSMBFS IN CIFS CLIENT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,10 @@ +/* +// Copyright (C) 2002 Microsoft Corporation +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" +// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +// OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY +// AND/OR FITNESS FOR A PARTICULAR PURPOSE. +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,1 @@ +PORTIONS OF LIBSMBFS IN CIFS CLIENT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/cfopt.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2000, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: cfopt.c,v 1.1.1.1 2001/06/09 00:28:12 zarzycki Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> + +#include <stdio.h> +#include <string.h> +#include <libintl.h> + +#include <cflib.h> +#include <netsmb/smb_lib.h> + +int cf_opterr = 1, /* if error message should be printed */ + cf_optind = 1, /* index into parent argv vector */ + cf_optopt, /* character checked for validity */ + cf_optreset; /* reset getopt */ +const char *cf_optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +int +cf_getopt(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + static const char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + int tmpind; + + if (cf_optreset || !*place) { /* update scanning pointer */ + cf_optreset = 0; + tmpind = cf_optind; + while (1) { + if (tmpind >= nargc) { + place = EMSG; + return (-1); + } + if (*(place = nargv[tmpind]) != '-') { + tmpind++; + continue; /* lookup next option */ + } + if (place[1] && *++place == '-') { /* found "--" */ + cf_optind = ++tmpind; + place = EMSG; + return (-1); + } + cf_optind = tmpind; + break; + } + } /* option letter okay? */ + if ((cf_optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, cf_optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (cf_optopt == (int)'-') + return (-1); + if (!*place) + ++cf_optind; + if (cf_opterr && *ostr != ':') + (void) fprintf(stderr, dgettext(TEXT_DOMAIN, + "%s: illegal option -- %c\n"), + __progname, cf_optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + cf_optarg = NULL; + if (!*place) + ++cf_optind; + } else { /* need an argument */ + if (*place) /* no white space */ + cf_optarg = place; + else if (nargc <= ++cf_optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (cf_opterr) + (void) fprintf(stderr, dgettext(TEXT_DOMAIN, + "%s: option requires an argument -- %c\n"), + __progname, cf_optopt); + return (BADCH); + } else /* white space */ + cf_optarg = nargv[cf_optind]; + place = EMSG; + ++cf_optind; + } + return (cf_optopt); /* dump back option letter */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/charsets.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2001 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* @(#)charsets.c * + * (c) 2004 Apple Computer, Inc. All Rights Reserved + * + * + * charsets.c -- Routines converting between UTF-8, 16-bit + * little-endian Unicode, and various Windows + * code pages. + * + * MODIFICATION HISTORY: + * 28-Nov-2004 Guy Harris New today + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <iconv.h> +#include <langinfo.h> +#include <strings.h> + +#ifdef NOTPORTED +#include <CoreFoundation/CoreFoundation.h> +#include <CoreFoundation/CFStringDefaultEncoding.h> +#include <CoreFoundation/CFStringEncodingConverter.h> +#include <sys/mchain.h> +#endif /* NOTPORTED */ + +#include <netsmb/smb_lib.h> +#include <netsmb/mchain.h> + +#include "charsets.h" + +#ifdef NOTPORTED +extern uid_t real_uid,eff_uid; +#endif /* NOTPORTED */ + +/* + * On Solaris, we will need to do some rewriting to use our iconv + * routines for the conversions. For now, we're effectively + * stubbing out code, leaving the details of what happens on + * Darwin in case it's useful as a guide later. + */ + +static unsigned +xtoi(char u) +{ + if (isdigit(u)) + return (u - '0'); + else if (islower(u)) + return (10 + u - 'a'); + else if (isupper(u)) + return (10 + u - 'A'); + return (16); +} + + +/* Removes the "%" escape sequences from a URL component. + * See IETF RFC 2396. + */ +char * +unpercent(char * component) +{ + char c, *s; + unsigned hi, lo; + + if (component) + for (s = component; (c = *s) != 0; s++) { + if (c != '%') + continue; + if ((hi = xtoi(s[1])) > 15 || (lo = xtoi(s[2])) > 15) + continue; /* ignore invalid escapes */ + s[0] = hi*16 + lo; + /* + * This was strcpy(s + 1, s + 3); + * But nowadays leftward overlapping copies are + * officially undefined in C. Ours seems to + * work or not depending upon alignment. + */ + memmove(s+1, s+3, strlen(s+3) + 1); + } + return (component); +} + +#ifdef NOTPORTED +static CFStringEncoding +get_windows_encoding_equivalent( void ) +{ + + CFStringEncoding encoding; + uint32_t index,region; + + /* important! use root ID so you can read the config file! */ + seteuid(eff_uid); + __CFStringGetInstallationEncodingAndRegion(&index,®ion); + seteuid(real_uid); + + switch ( index ) + { + case kCFStringEncodingMacRoman: + if (region) /* anything nonzero is not US */ + encoding = kCFStringEncodingDOSLatin1; + else /* US region */ + encoding = kCFStringEncodingDOSLatinUS; + break; + + case kCFStringEncodingMacJapanese: + encoding = kCFStringEncodingDOSJapanese; + break; + + case kCFStringEncodingMacChineseTrad: + encoding = kCFStringEncodingDOSChineseTrad; + break; + + case kCFStringEncodingMacKorean: + encoding = kCFStringEncodingDOSKorean; + break; + + case kCFStringEncodingMacArabic: + encoding = kCFStringEncodingDOSArabic; + break; + + case kCFStringEncodingMacHebrew: + encoding = kCFStringEncodingDOSHebrew; + break; + + case kCFStringEncodingMacGreek: + encoding = kCFStringEncodingDOSGreek; + break; + + case kCFStringEncodingMacCyrillic: + encoding = kCFStringEncodingDOSCyrillic; + break; + + case kCFStringEncodingMacThai: + encoding = kCFStringEncodingDOSThai; + break; + + case kCFStringEncodingMacChineseSimp: + encoding = kCFStringEncodingDOSChineseSimplif; + break; + + case kCFStringEncodingMacCentralEurRoman: + encoding = kCFStringEncodingDOSLatin2; + break; + + case kCFStringEncodingMacTurkish: + encoding = kCFStringEncodingDOSTurkish; + break; + + case kCFStringEncodingMacCroatian: + encoding = kCFStringEncodingDOSLatin2; + break; + + case kCFStringEncodingMacIcelandic: + encoding = kCFStringEncodingDOSIcelandic; + break; + + case kCFStringEncodingMacRomanian: + encoding = kCFStringEncodingDOSLatin2; + break; + + case kCFStringEncodingMacFarsi: + encoding = kCFStringEncodingDOSArabic; + break; + + case kCFStringEncodingMacUkrainian: + encoding = kCFStringEncodingDOSCyrillic; + break; + + default: + encoding = kCFStringEncodingDOSLatin1; + break; + } + + return encoding; +} +#endif /* NOTPORTED */ + +/* + * XXX - NLS, or CF? We should probably use the same routine for all + * conversions. + */ +char * +convert_wincs_to_utf8(const char *windows_string) +{ +#ifdef NOTPORTED + CFStringRef s; + CFIndex maxlen; + char *result; + + s = CFStringCreateWithCString(NULL, windows_string, + get_windows_encoding_equivalent()); + if (s == NULL) { + smb_error("CFStringCreateWithCString for Windows code page failed on \"%s\" ", -1, + windows_string); + + /* kCFStringEncodingMacRoman should always succeed */ + s = CFStringCreateWithCString(NULL, windows_string, + kCFStringEncodingMacRoman); + if (s == NULL) { + smb_error("CFStringCreateWithCString for Windows code page failed on \"%s\" with kCFStringEncodingMacRoman - skipping", + -1, windows_string); + return NULL; + } + } + + maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(s), + kCFStringEncodingUTF8) + 1; + result = malloc(maxlen); + if (result == NULL) { + smb_error("Couldn't allocate buffer for UTF-8 string for \"%s\" - skipping", -1, + windows_string); + CFRelease(s); + return NULL; + } + if (!CFStringGetCString(s, result, maxlen, kCFStringEncodingUTF8)) { + smb_error("CFStringGetCString for UTF-8 failed on \"%s\" - skipping", + -1, windows_string); + CFRelease(s); + return NULL; + } + CFRelease(s); + return result; +#else /* NOTPORTED */ + return ((char*)windows_string); +#endif /* NOTPORTED */ +} + +/* + * XXX - NLS, or CF? We should probably use the same routine for all + * conversions. + */ +char * +convert_utf8_to_wincs(const char *utf8_string) +{ +#ifdef NOTPORTED + CFStringRef s; + CFIndex maxlen; + char *result; + + s = CFStringCreateWithCString(NULL, utf8_string, + kCFStringEncodingUTF8); + if (s == NULL) { + smb_error("CFStringCreateWithCString for UTF-8 failed on \"%s\"", -1, + utf8_string); + return NULL; + } + + maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(s), + get_windows_encoding_equivalent()) + 1; + result = malloc(maxlen); + if (result == NULL) { + smb_error("Couldn't allocate buffer for Windows code page string for \"%s\" - skipping", -1, + utf8_string); + CFRelease(s); + return NULL; + } + if (!CFStringGetCString(s, result, maxlen, + get_windows_encoding_equivalent())) { + smb_error("CFStringGetCString for Windows code page failed on \"%s\" - skipping", + -1, utf8_string); + CFRelease(s); + return NULL; + } + CFRelease(s); + return result; +#else /* NOTPORTED */ + return ((char*)utf8_string); +#endif /* NOTPORTED */ +} + +/* + * Convert little-endian Unicode string to UTF-8. + * Converts the Unicode string to host byte order in place. + */ +char * +convert_leunicode_to_utf8(unsigned short *unicode_string) +{ + unsigned short *unicode_charp, unicode_char; + int len = 0; + + for (unicode_charp = unicode_string; + (unicode_char = *unicode_charp) != 0; + unicode_charp++) { + *unicode_charp = letohs(unicode_char); + len = len + 2; + } + return (convert_unicode_to_utf8(unicode_string, len)); +} + +char * +convert_unicode_to_utf8(unsigned short *unicode_string, int len) +{ + iconv_t cd; + char from[BUFSIZ], to[BUFSIZ]; + char *tptr = NULL; + const char *fptr; + size_t ileft, oleft, ret; + + cd = iconv_open("UTF-8", "UTF-16"); + if (cd != (iconv_t)-1) { + ileft = len; + bcopy((char *)unicode_string, from, ileft); + fptr = from; + oleft = BUFSIZ; + tptr = to; + ret = iconv(cd, &fptr, &ileft, &tptr, &oleft); + if (ret != (size_t)-1) { + to[BUFSIZ-oleft] = '\0'; + tptr = to; + } else { + tptr = NULL; + } + (void) iconv_close(cd); + } + return (tptr); +} + +/* + * Convert UTF-8 string to little-endian Unicode. + */ +unsigned short * +convert_utf8_to_leunicode(const char *utf8_string) +{ +#ifdef NOTPORTED + CFStringRef s; + CFIndex maxlen; + unsigned short *result; + CFRange range; + int i; + + s = CFStringCreateWithCString(NULL, utf8_string, + kCFStringEncodingUTF8); + if (s == NULL) { + smb_error("CFStringCreateWithCString for UTF-8 failed on \"%s\"", -1, + utf8_string); + return NULL; + } + + maxlen = CFStringGetLength(s); + result = malloc(2*(maxlen + 1)); + if (result == NULL) { + smb_error("Couldn't allocate buffer for Unicode string for \"%s\" - skipping", -1, + utf8_string); + CFRelease(s); + return NULL; + } + range.location = 0; + range.length = maxlen; + CFStringGetCharacters(s, range, result); + for (i = 0; i < maxlen; i++) + result[i] = CFSwapInt16HostToLittle(result[i]); + result[maxlen] = 0; + CFRelease(s); + return result; +#else /* NOTPORTED */ + /* LINTED */ /* XXX Really need to fix this! */ + return ((ushort_t *)utf8_string); /* XXX */ +#endif /* NOTPORTED */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/charsets.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2001 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * @(#)charsets.h + * (c) 2004 Apple Computer, Inc. All Rights Reserved + * + * + * charsets.h -- Routines converting between UTF-8, 16-bit + * little-endian Unicode, 16-bit host-byte-order + * Unicode, and various Windows code pages. + * + * MODIFICATION HISTORY: + * 28-Nov-2004 Guy Harris New today + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef __CHARSETS_H__ +#define __CHARSETS_H__ + +extern char *convert_wincs_to_utf8(const char *windows_string); +extern char *convert_utf8_to_wincs(const char *utf8_string); +extern char *convert_leunicode_to_utf8(unsigned short *windows_string); +extern char *convert_unicode_to_utf8(unsigned short *windows_string, int len); +extern unsigned short *convert_utf8_to_leunicode(const char *utf8_string); + +#endif /* __CHARSETS_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/ctx.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,2140 @@ +/* + * Copyright (c) 2000, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: ctx.c,v 1.32.70.2 2005/06/02 00:55:40 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/mount.h> +#include <sys/types.h> +#include <sys/byteorder.h> + +#include <fcntl.h> +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <pwd.h> +#include <grp.h> +#include <unistd.h> +#include <libintl.h> +#include <assert.h> +#include <nss_dbdefs.h> + +#include <kerberosv5/krb5.h> +#include <kerberosv5/com_err.h> + +extern uid_t real_uid, eff_uid; + +#define NB_NEEDRESOLVER + +#include <netsmb/smb_lib.h> +#include <netsmb/netbios.h> +#include <netsmb/nb_lib.h> +#include <netsmb/smb_dev.h> +#include <cflib.h> +#include <charsets.h> + +#include <spnego.h> +#include "derparse.h" + +extern MECH_OID g_stcMechOIDList []; + +#define POWEROF2(x) (((x) & ((x)-1)) == 0) + +/* These two may be set by commands. */ +int smb_debug, smb_verbose; + +/* + * This used to call the DCE/RPC code. + * We want more strict layering than this. + * The redirector should simply export a + * remote pipe API, comsumed by dce rpc. + * Make it a no-op for now. + */ +#if 0 +#include <rpc_cleanup.h> +#else +static void +rpc_cleanup_smbctx(struct smb_ctx *ctx) +{ +} +#endif + +void +dump_ctx_flags(int flags) +{ + printf(" Flags: "); + if (flags == 0) + printf("0"); + if (flags & SMBCF_NOPWD) + printf("NOPWD "); + if (flags & SMBCF_SRIGHTS) + printf("SRIGHTS "); + if (flags & SMBCF_LOCALE) + printf("LOCALE "); + if (flags & SMBCF_CMD_DOM) + printf("CMD_DOM "); + if (flags & SMBCF_CMD_USR) + printf("CMD_USR "); + if (flags & SMBCF_CMD_PW) + printf("CMD_PW "); + if (flags & SMBCF_RESOLVED) + printf("RESOLVED "); + if (flags & SMBCF_KCBAD) + printf("KCBAD "); + if (flags & SMBCF_KCFOUND) + printf("KCFOUND "); + if (flags & SMBCF_BROWSEOK) + printf("BROWSEOK "); + if (flags & SMBCF_AUTHREQ) + printf("AUTHREQ "); + if (flags & SMBCF_KCSAVE) + printf("KCSAVE "); + if (flags & SMBCF_XXX) + printf("XXX "); + if (flags & SMBCF_SSNACTIVE) + printf("SSNACTIVE "); + if (flags & SMBCF_KCDOMAIN) + printf("KCDOMAIN "); + printf("\n"); +} + +void +dump_ctx_ssn(struct smbioc_ossn *ssn) +{ + printf(" srvname=\"%s\", dom=\"%s\", user=\"%s\", password=%s\n", + ssn->ioc_srvname, ssn->ioc_workgroup, ssn->ioc_user, + ssn->ioc_password[0] ? "(non-null)" : "NULL"); + printf(" timeout=%d, retry=%d, owner=%d, group=%d\n", + ssn->ioc_timeout, ssn->ioc_retrycount, + ssn->ioc_owner, ssn->ioc_group); +} + +void +dump_ctx_sh(struct smbioc_oshare *sh) +{ + printf(" share_name=\"%s\", share_pw=\"%s\"\n", + sh->ioc_share, sh->ioc_password); +} + +void +dump_ctx(char *where, struct smb_ctx *ctx) +{ + printf("context %s:\n", where); + dump_ctx_flags(ctx->ct_flags); + + printf(" localname=\"%s\"", ctx->ct_locname); + + if (ctx->ct_fullserver) + printf(" fullserver=\"%s\"", ctx->ct_fullserver); + else + printf(" fullserver=NULL"); + + if (ctx->ct_srvaddr) + printf(" srvaddr=\"%s\"\n", ctx->ct_srvaddr); + else + printf(" srvaddr=NULL\n"); + + dump_ctx_ssn(&ctx->ct_ssn); + dump_ctx_sh(&ctx->ct_sh); +} + +/* + * Initialize an smb_ctx struct. + * + * The sequence for getting all the members filled in + * has some tricky aspects. Here's how it works: + * + * The search order for options is as follows: + * command line options + * values parsed from UNC path (cmd) + * values from RC file (per-user) + * values from SMF (system-wide) + * built-in defaults + * + * Normally, one would simply get all the values starting with + * the bottom of the above list and working to the top, and + * overwriting values as you go. But we need an exception. + * + * In this function, we parse the UNC path and command line options, + * because we need (at least) the server name when we're getting the + * SMF and RC file values. However, values we get from the command + * should not be overwritten by SMF or RC file parsing, so we mark + * values from the command as "from CMD" and the RC file parser + * leaves in place any values so marked. See: SMBCF_CMD_* + * + * The semantics of these flags are: "This value came from the + * current command instance, not from sources that may apply to + * multiple commands." (Different from the old "FROMUSR" flag.) + * + * Note that smb_ctx_opt() is called later to handle the + * remaining options, which should be ignored here. + * The (magic) leading ":" in cf_getopt() makes it + * ignore options not in the options string. + */ +int +smb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[], + int minlevel, int maxlevel, int sharetype) +{ + int opt, error = 0; + const char *arg, *cp; + struct passwd pw; + char pwbuf[NSS_BUFLEN_PASSWD]; + int aflg = 0, uflg = 0; + + bzero(ctx, sizeof (*ctx)); + if (sharetype == SMB_ST_DISK) + ctx->ct_flags |= SMBCF_BROWSEOK; + error = nb_ctx_create(&ctx->ct_nb); + if (error) + return (error); + + ctx->ct_fd = -1; + ctx->ct_parsedlevel = SMBL_NONE; + ctx->ct_minlevel = minlevel; + ctx->ct_maxlevel = maxlevel; + + ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE | SMBVOPT_MINAUTH_NTLM; + ctx->ct_ssn.ioc_timeout = 15; + ctx->ct_ssn.ioc_retrycount = 4; + ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER; + ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP; + ctx->ct_ssn.ioc_mode = SMBM_EXEC; + ctx->ct_ssn.ioc_rights = SMBM_DEFAULT; + + ctx->ct_sh.ioc_opt = SMBVOPT_CREATE; + ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; + ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; + ctx->ct_sh.ioc_mode = SMBM_EXEC; + ctx->ct_sh.ioc_rights = SMBM_DEFAULT; + ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER; + ctx->ct_sh.ioc_group = SMBM_ANY_GROUP; + + nb_ctx_setscope(ctx->ct_nb, ""); + + /* + * if the user name is not specified some other way, + * use the current user name (built-in default) + */ + if (getpwuid_r(geteuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) + smb_ctx_setuser(ctx, pw.pw_name, 0); + + /* + * Set a built-in default domain (workgroup). + * XXX: What's the best default? Use "?" instead? + * Using the Windows/NT default for now. + */ + smb_ctx_setworkgroup(ctx, "WORKGROUP", 0); + + /* + * Parse the UNC path. Values from here are + * marked as "from CMD". + */ + if (argv == NULL) + goto done; + for (opt = 1; opt < argc; opt++) { + cp = argv[opt]; + if (strncmp(cp, "//", 2) != 0) + continue; + error = smb_ctx_parseunc(ctx, cp, sharetype, &cp); + if (error) + return (error); + break; + } + + /* + * Parse options, if any. Values from here too + * are marked as "from CMD". + */ + while (error == 0 && (opt = cf_getopt(argc, argv, ":AU:E:L:")) != -1) { + arg = cf_optarg; + switch (opt) { + case 'A': + aflg = 1; + error = smb_ctx_setuser(ctx, "", TRUE); + error = smb_ctx_setpassword(ctx, "", TRUE); + ctx->ct_flags |= SMBCF_NOPWD; + break; + case 'E': +#if 0 /* We don't support any "charset" stuff. (ignore -E) */ + error = smb_ctx_setcharset(ctx, arg); + if (error) + return (error); +#endif + break; + case 'L': +#if 0 /* Use the standard environment variables (ignore -L) */ + error = nls_setlocale(optarg); + if (error) + break; +#endif + break; + case 'U': + uflg = 1; + error = smb_ctx_setuser(ctx, arg, TRUE); + break; + } + } + if (aflg && uflg) { + printf(gettext("-A and -U flags are exclusive.\n")); + return (1); + } + cf_optind = cf_optreset = 1; + +done: + if (smb_debug) + dump_ctx("after smb_ctx_init", ctx); + + return (error); +} + +void +smb_ctx_done(struct smb_ctx *ctx) +{ + + rpc_cleanup_smbctx(ctx); + + /* Kerberos stuff. See smb_ctx_krb5init() */ + if (ctx->ct_krb5ctx) { + if (ctx->ct_krb5cp) + krb5_free_principal(ctx->ct_krb5ctx, ctx->ct_krb5cp); + krb5_free_context(ctx->ct_krb5ctx); + } + + if (ctx->ct_fd != -1) + close(ctx->ct_fd); +#if 0 /* XXX: not pointers anymore */ + if (&ctx->ct_ssn.ioc_server) + nb_snbfree(&ctx->ct_ssn.ioc_server); + if (&ctx->ct_ssn.ioc_local) + nb_snbfree(&ctx->ct_ssn.ioc_local); +#endif + if (ctx->ct_srvaddr) + free(ctx->ct_srvaddr); + if (ctx->ct_nb) + nb_ctx_done(ctx->ct_nb); + if (ctx->ct_secblob) + free(ctx->ct_secblob); + if (ctx->ct_origshare) + free(ctx->ct_origshare); + if (ctx->ct_fullserver) + free(ctx->ct_fullserver); +} + +static int +getsubstring(const char *p, uchar_t sep, char *dest, int maxlen, + const char **next) +{ + int len; + + maxlen--; + for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) { + if (*p == 0) + return (EINVAL); + *dest = *p; + } + *dest = 0; + *next = *p ? p + 1 : p; + return (0); +} + +/* + * Parse the UNC path. Here we expect something like + * "//[workgroup;][user[:password]@]host[/share[/path]]" + * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt + * Values found here are marked as "from CMD". + */ +int +smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype, + const char **next) +{ + const char *p = unc; + char *p1, *colon, *servername; + char tmp[1024]; + char tmp2[1024]; + int error; + + ctx->ct_parsedlevel = SMBL_NONE; + if (*p++ != '/' || *p++ != '/') { + smb_error(dgettext(TEXT_DOMAIN, + "UNC should start with '//'"), 0); + return (EINVAL); + } + p1 = tmp; + error = getsubstring(p, ';', p1, sizeof (tmp), &p); + if (!error) { + if (*p1 == 0) { + smb_error(dgettext(TEXT_DOMAIN, + "empty workgroup name"), 0); + return (EINVAL); + } + nls_str_upper(tmp, tmp); + error = smb_ctx_setworkgroup(ctx, unpercent(tmp), TRUE); + if (error) + return (error); + } + colon = (char *)p; + error = getsubstring(p, '@', p1, sizeof (tmp), &p); + if (!error) { + if (ctx->ct_maxlevel < SMBL_VC) { + smb_error(dgettext(TEXT_DOMAIN, + "no user name required"), 0); + return (EINVAL); + } + p1 = strchr(tmp, ':'); + if (p1) { + colon += p1 - tmp; + *p1++ = (char)0; + error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE); + if (error) + return (error); + if (p - colon > 2) + memset(colon+1, '*', p - colon - 2); + } + p1 = tmp; + if (*p1 == 0) { + smb_error(dgettext(TEXT_DOMAIN, + "empty user name"), 0); + return (EINVAL); + } + error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE); + if (error) + return (error); + ctx->ct_parsedlevel = SMBL_VC; + } + error = getsubstring(p, '/', p1, sizeof (tmp), &p); + if (error) { + error = getsubstring(p, '\0', p1, sizeof (tmp), &p); + if (error) { + smb_error(dgettext(TEXT_DOMAIN, + "no server name found"), 0); + return (error); + } + } + if (*p1 == 0) { + smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0); + return (EINVAL); + } + + + /* + * It's safe to uppercase this string, which + * consists of ascii characters that should + * be uppercased, %s, and ascii characters representing + * hex digits 0-9 and A-F (already uppercased, and + * if not uppercased they need to be). However, + * it is NOT safe to uppercase after it has been + * converted, below! + */ + + nls_str_upper(tmp2, tmp); + + /* + * scan for % in the string. + * If we find one, convert + * to the assumed codepage. + */ + + if (strchr(tmp2, '%')) { + /* use the 1st buffer, we don't need the old string */ + servername = tmp; + if (!(servername = convert_utf8_to_wincs(unpercent(tmp2)))) { + smb_error(dgettext(TEXT_DOMAIN, "bad server name"), 0); + return (EINVAL); + } + /* + * Converts utf8 to win equivalent of + * what is configured on this machine. + * Note that we are assuming this is the + * encoding used on the server, and that + * assumption might be incorrect. This is + * the best we can do now, and we should + * move to use port 445 to avoid having + * to worry about server codepages. + */ + } else /* no conversion needed */ + servername = tmp2; + + smb_ctx_setserver(ctx, servername); + error = smb_ctx_setfullserver(ctx, servername); + + if (error) + return (error); + if (sharetype == SMB_ST_NONE) { + *next = p; + return (0); + } + if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) { + smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0); + return (EINVAL); + } + error = getsubstring(p, '/', p1, sizeof (tmp), &p); + if (error) { + error = getsubstring(p, '\0', p1, sizeof (tmp), &p); + if (error) { + smb_error(dgettext(TEXT_DOMAIN, + "unexpected end of line"), 0); + return (error); + } + } + if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE && + !(ctx->ct_flags & SMBCF_BROWSEOK)) { + smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0); + return (EINVAL); + } + *next = p; + if (*p1 == 0) + return (0); + error = smb_ctx_setshare(ctx, unpercent(p1), sharetype); + return (error); +} + +int +smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg) +{ + char *cp, *servercs, *localcs; + int cslen = sizeof (ctx->ct_ssn.ioc_localcs); + int scslen, lcslen, error; + + cp = strchr(arg, ':'); + lcslen = cp ? (cp - arg) : 0; + if (lcslen == 0 || lcslen >= cslen) { + smb_error(dgettext(TEXT_DOMAIN, + "invalid local charset specification (%s)"), 0, arg); + return (EINVAL); + } + scslen = (size_t)strlen(++cp); + if (scslen == 0 || scslen >= cslen) { + smb_error(dgettext(TEXT_DOMAIN, + "invalid server charset specification (%s)"), 0, arg); + return (EINVAL); + } + localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen); + localcs[lcslen] = 0; + servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp); + error = nls_setrecode(localcs, servercs); + if (error == 0) + return (0); + smb_error(dgettext(TEXT_DOMAIN, + "can't initialize iconv support (%s:%s)"), + error, localcs, servercs); + localcs[0] = 0; + servercs[0] = 0; + return (error); +} + +int +smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name) +{ + ctx->ct_fullserver = strdup(name); + if (ctx->ct_fullserver == NULL) + return (ENOMEM); + return (0); +} + +/* + * XXX TODO FIXME etc etc + * If the call to nbns_getnodestatus(...) fails we can try one of two other + * methods; use a name of "*SMBSERVER", which is supported by Samba (at least) + * or, as a last resort, try the "truncate-at-dot" heuristic. + * And the heuristic really should attempt truncation at + * each dot in turn, left to right. + * + * These fallback heuristics should be triggered when the attempt to open the + * session fails instead of in the code below. + * + * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt + */ +int +smb_ctx_getnbname(struct smb_ctx *ctx, struct sockaddr *sap) +{ + char server[SMB_MAXSRVNAMELEN + 1]; + char workgroup[SMB_MAXUSERNAMELEN + 1]; + int error; +#if 0 + char *dot; +#endif + + server[0] = workgroup[0] = '\0'; + error = nbns_getnodestatus(sap, ctx->ct_nb, server, workgroup); + if (error == 0) { + /* + * Used to set our domain name to be the same as + * the server's domain name. Unnecessary at best, + * and wrong for accounts in a trusted domain. + */ +#ifdef APPLE + if (workgroup[0] && !ctx->ct_ssn.ioc_workgroup[0]) + smb_ctx_setworkgroup(ctx, workgroup, 0); +#endif + if (server[0]) + smb_ctx_setserver(ctx, server); + } else { + if (smb_verbose) + smb_error(dgettext(TEXT_DOMAIN, + "Failed to get NetBIOS node status."), 0); + if (ctx->ct_ssn.ioc_srvname[0] == (char)0) + smb_ctx_setserver(ctx, "*SMBSERVER"); + } +#if 0 + if (server[0] == (char)0) { + dot = strchr(ctx->ct_fullserver, '.'); + if (dot) + *dot = '\0'; + if (strlen(ctx->ct_fullserver) <= SMB_MAXSRVNAMELEN) { + /* + * don't uppercase the server name. it comes from + * NBNS and uppercasing can clobber the characters + */ + strcpy(ctx->ct_ssn.ioc_srvname, ctx->ct_fullserver); + error = 0; + } else { + error = -1; + } + if (dot) + *dot = '.'; + } +#endif + return (error); +} + +/* this routine does not uppercase the server name */ +void +smb_ctx_setserver(struct smb_ctx *ctx, const char *name) +{ + /* don't uppercase the server name */ + if (strlen(name) > SMB_MAXSRVNAMELEN) { /* NB limit is 15 */ + ctx->ct_ssn.ioc_srvname[0] = '\0'; + } else + strcpy(ctx->ct_ssn.ioc_srvname, name); +} + +int +smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd) +{ + + if (strlen(name) >= SMB_MAXUSERNAMELEN) { + smb_error(dgettext(TEXT_DOMAIN, + "user name '%s' too long"), 0, name); + return (ENAMETOOLONG); + } + + /* + * Don't overwrite a value from the command line + * with one from anywhere else. + */ + if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR)) + return (0); + + /* don't uppercase the username, just copy it. */ + strcpy(ctx->ct_ssn.ioc_user, name); + + /* Mark this as "from the command line". */ + if (from_cmd) + ctx->ct_flags |= SMBCF_CMD_USR; + + return (0); +} + +/* + * Never uppercase the workgroup + * name here, because it might come + * from a Windows codepage encoding. + * + * Don't overwrite a domain name from the + * command line with one from anywhere else. + * See smb_ctx_init() for notes about this. + */ +int +smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name, int from_cmd) +{ + + if (strlen(name) >= SMB_MAXUSERNAMELEN) { + smb_error(dgettext(TEXT_DOMAIN, + "workgroup name '%s' too long"), 0, name); + return (ENAMETOOLONG); + } + + /* + * Don't overwrite a value from the command line + * with one from anywhere else. + */ + if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM)) + return (0); + + strcpy(ctx->ct_ssn.ioc_workgroup, name); + + /* Mark this as "from the command line". */ + if (from_cmd) + ctx->ct_flags |= SMBCF_CMD_DOM; + + return (0); +} + +int +smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd) +{ + + if (passwd == NULL) /* XXX Huh? */ + return (EINVAL); + if (strlen(passwd) >= SMB_MAXPASSWORDLEN) { + smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0); + return (ENAMETOOLONG); + } + + /* + * Don't overwrite a value from the command line + * with one from anywhere else. + */ + if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW)) + return (0); + + if (strncmp(passwd, "$$1", 3) == 0) + smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd); + else + strcpy(ctx->ct_ssn.ioc_password, passwd); + strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password); + + /* Mark this as "from the command line". */ + if (from_cmd) + ctx->ct_flags |= SMBCF_CMD_PW; + + return (0); +} + +int +smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype) +{ + if (strlen(share) >= SMB_MAXSHARENAMELEN) { + smb_error(dgettext(TEXT_DOMAIN, + "share name '%s' too long"), 0, share); + return (ENAMETOOLONG); + } + if (ctx->ct_origshare) + free(ctx->ct_origshare); + if ((ctx->ct_origshare = strdup(share)) == NULL) + return (ENOMEM); + nls_str_upper(ctx->ct_sh.ioc_share, share); + if (share[0] != 0) + ctx->ct_parsedlevel = SMBL_SHARE; + ctx->ct_sh.ioc_stype = stype; + return (0); +} + +int +smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr) +{ + if (addr == NULL || addr[0] == 0) + return (EINVAL); + if (ctx->ct_srvaddr) + free(ctx->ct_srvaddr); + if ((ctx->ct_srvaddr = strdup(addr)) == NULL) + return (ENOMEM); + return (0); +} + +static int +smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) +{ + struct group gr; + struct passwd pw; + char buf[NSS_BUFLEN_PASSWD]; + char *cp; + + cp = strchr(pair, ':'); + if (cp) { + *cp++ = '\0'; + if (*cp) { + if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) { + *gid = gr.gr_gid; + } else + smb_error(dgettext(TEXT_DOMAIN, + "Invalid group name %s, ignored"), 0, cp); + } + } + if (*pair) { + if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) { + *uid = pw.pw_uid; + } else + smb_error(dgettext(TEXT_DOMAIN, + "Invalid user name %s, ignored"), 0, pair); + } + + return (0); +} + +/* + * Commands use this with getopt. See: + * STDPARAM_OPT, STDPARAM_ARGS + * Called after smb_ctx_readrc(). + */ +int +smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg) +{ + int error = 0; + char *p, *cp; + char tmp[1024]; + + switch (opt) { + case 'A': + case 'U': + /* Handled in smb_ctx_init() */ + break; + case 'I': + error = smb_ctx_setsrvaddr(ctx, arg); + break; + case 'M': + ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8); + if (*cp == '/') { + ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8); + ctx->ct_flags |= SMBCF_SRIGHTS; + } + break; + case 'N': + ctx->ct_flags |= SMBCF_NOPWD; + break; + case 'O': + p = strdup(arg); + cp = strchr(p, '/'); + if (cp) { + *cp++ = '\0'; + error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner, + &ctx->ct_sh.ioc_group); + } + if (*p && error == 0) { + error = smb_parse_owner(cp, &ctx->ct_ssn.ioc_owner, + &ctx->ct_ssn.ioc_group); + } + free(p); + break; + case 'P': +/* ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT; */ + break; + case 'R': + ctx->ct_ssn.ioc_retrycount = atoi(arg); + break; + case 'T': + ctx->ct_ssn.ioc_timeout = atoi(arg); + break; + case 'W': + nls_str_upper(tmp, arg); + error = smb_ctx_setworkgroup(ctx, tmp, TRUE); + break; + } + return (error); +} + +#if 0 +static void +smb_hexdump(const uchar_t *buf, int len) { + int ofs = 0; + + while (len--) { + if (ofs % 16 == 0) + printf("\n%02X: ", ofs); + printf("%02x ", *buf++); + ofs++; + } + printf("\n"); +} +#endif + + +static int +smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl) +{ + int error; + + /* + * Not able to find out what is the work of this routine till + * now. Still investigating. + * REVISIT + */ +#ifdef KICONV_SUPPORT + error = kiconv_add_xlat_table(to, from, tbl); + if (error && error != EEXIST) { + smb_error(dgettext(TEXT_DOMAIN, + "can not setup kernel iconv table (%s:%s)"), + error, from, to); + return (error); + } +#endif + return (0); +} + +/* + * Verify context before connect operation(s), + * lookup specified server and try to fill all forgotten fields. + */ +int +smb_ctx_resolve(struct smb_ctx *ctx) +{ + struct smbioc_ossn *ssn = &ctx->ct_ssn; + struct smbioc_oshare *sh = &ctx->ct_sh; + struct nb_name nn; + struct sockaddr *sap; + struct sockaddr_nb *salocal, *saserver; + char *cp; + uchar_t cstbl[256]; + uint_t i; + int error = 0; + int browseok = ctx->ct_flags & SMBCF_BROWSEOK; + int renego = 0; + + ctx->ct_flags &= ~SMBCF_RESOLVED; + if (isatty(STDIN_FILENO)) + browseok = 0; + if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == 0) { + smb_error(dgettext(TEXT_DOMAIN, + "no server name specified"), 0); + return (EINVAL); + } + if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0 && + !browseok) { + smb_error(dgettext(TEXT_DOMAIN, + "no share name specified for %s@%s"), + 0, ssn->ioc_user, ssn->ioc_srvname); + return (EINVAL); + } + error = nb_ctx_resolve(ctx->ct_nb); + if (error) + return (error); + if (ssn->ioc_localcs[0] == 0) + strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */ + error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower); + if (error) + return (error); + error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper); + if (error) + return (error); + if (ssn->ioc_servercs[0] != 0) { + for (i = 0; i < sizeof (cstbl); i++) + cstbl[i] = i; + nls_mem_toext(cstbl, cstbl, sizeof (cstbl)); + error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs, + cstbl); + if (error) + return (error); + for (i = 0; i < sizeof (cstbl); i++) + cstbl[i] = i; + nls_mem_toloc(cstbl, cstbl, sizeof (cstbl)); + error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs, + cstbl); + if (error) + return (error); + } + /* + * If we have an explicit address set for the server in + * an "addr=X" setting in .nsmbrc or SMF, just try using a + * gethostbyname() lookup for it. + */ + if (ctx->ct_srvaddr) { + error = nb_resolvehost_in(ctx->ct_srvaddr, &sap); + if (error == 0) + (void) smb_ctx_getnbname(ctx, sap); + } else + error = -1; + + /* + * Next try a gethostbyname() lookup on the original user- + * specified server name. This is similar to Windows + * NBT option "Use DNS for name resolution." + */ + if (error && ctx->ct_fullserver) { + error = nb_resolvehost_in(ctx->ct_fullserver, &sap); + if (error == 0) + (void) smb_ctx_getnbname(ctx, sap); + } + + /* + * Finally, try the shorter, upper-cased ssn->ioc_srvname + * with a NBNS/WINS lookup if the "nbns_enable" property is + * true (the default). nbns_resolvename() may unicast to the + * "nbns" server or broadcast on the subnet. + */ + if (error && ssn->ioc_srvname[0] && + ctx->ct_nb->nb_flags & NBCF_NS_ENABLE) { + error = nbns_resolvename(ssn->ioc_srvname, + ctx->ct_nb, &sap); + /* + * Used to get the NetBIOS node status here. + * Not necessary (we have the NetBIOS name). + */ + } + if (error) { + smb_error(dgettext(TEXT_DOMAIN, + "can't get server address"), error); + return (error); + } + + /* XXX: no nls_str_upper(ssn->ioc_srvname) here? */ + + assert(sizeof (nn.nn_name) == sizeof (ssn->ioc_srvname)); + memcpy(nn.nn_name, ssn->ioc_srvname, NB_NAMELEN); + nn.nn_type = NBT_SERVER; + nn.nn_scope = ctx->ct_nb->nb_scope; + + error = nb_sockaddr(sap, &nn, &saserver); + memcpy(&ctx->ct_srvinaddr, sap, sizeof (struct sockaddr_in)); + nb_snbfree(sap); + if (error) { + smb_error(dgettext(TEXT_DOMAIN, + "can't allocate server address"), error); + return (error); + } + /* We know it's a NetBIOS address here. */ + bcopy(saserver, &ssn->ioc_server.nb, + sizeof (struct sockaddr_nb)); + if (ctx->ct_locname[0] == 0) { + error = nb_getlocalname(ctx->ct_locname, + SMB_MAXUSERNAMELEN + 1); + if (error) { + smb_error(dgettext(TEXT_DOMAIN, + "can't get local name"), error); + return (error); + } + nls_str_upper(ctx->ct_locname, ctx->ct_locname); + } + + /* XXX: no nls_str_upper(ctx->ct_locname); here? */ + + memcpy(nn.nn_name, ctx->ct_locname, NB_NAMELEN); + nn.nn_type = NBT_WKSTA; + nn.nn_scope = ctx->ct_nb->nb_scope; + + error = nb_sockaddr(NULL, &nn, &salocal); + if (error) { + nb_snbfree((struct sockaddr *)saserver); + smb_error(dgettext(TEXT_DOMAIN, + "can't allocate local address"), error); + return (error); + } + + /* We know it's a NetBIOS address here. */ + bcopy(salocal, &ssn->ioc_local.nb, + sizeof (struct sockaddr_nb)); + + error = smb_ctx_negotiate(ctx, SMBL_SHARE, SMBLK_CREATE, + ssn->ioc_workgroup); + if (error) + return (error); + ctx->ct_flags &= ~SMBCF_AUTHREQ; + if (!ctx->ct_secblob && browseok && !sh->ioc_share[0] && + !(ctx->ct_flags & SMBCF_XXX)) { + /* assert: anon share list is subset of overall server shares */ + error = smb_browse(ctx, 1); + if (error) /* user cancel or other error? */ + return (error); + /* + * A share was selected, authenticate button was pressed, + * or anon-authentication failed getting browse list. + */ + } + if ((ctx->ct_secblob == NULL) && (ctx->ct_flags & SMBCF_AUTHREQ || + (ssn->ioc_password[0] == '\0' && + !(ctx->ct_flags & SMBCF_NOPWD)))) { +reauth: + /* + * This function is implemented in both + * ui-apple.c and ui-sun.c so let's try to + * keep the same interface. Not sure why + * they didn't just pass ssn here. + */ + error = smb_get_authentication( + ssn->ioc_workgroup, sizeof (ssn->ioc_workgroup) - 1, + ssn->ioc_user, sizeof (ssn->ioc_user) - 1, + ssn->ioc_password, sizeof (ssn->ioc_password) - 1, + ssn->ioc_srvname, ctx); + if (error) + return (error); + } + /* + * if we have a session it is either anonymous + * or from a stale authentication. re-negotiating + * gets us ready for a fresh session + */ + if (ctx->ct_flags & SMBCF_SSNACTIVE || renego) { + renego = 0; + /* don't clobber workgroup name, pass null arg */ + error = smb_ctx_negotiate(ctx, SMBL_SHARE, SMBLK_CREATE, NULL); + if (error) + return (error); + } + if (browseok && !sh->ioc_share[0]) { + ctx->ct_flags &= ~SMBCF_AUTHREQ; + error = smb_browse(ctx, 0); + if (ctx->ct_flags & SMBCF_KCFOUND && smb_autherr(error)) { + smb_error(dgettext(TEXT_DOMAIN, + "smb_ctx_resolve: bad keychain entry"), 0); + ctx->ct_flags |= SMBCF_KCBAD; + renego = 1; + goto reauth; + } + if (error) /* auth, user cancel, or other error */ + return (error); + /* + * Re-authenticate button was pressed? + */ + if (ctx->ct_flags & SMBCF_AUTHREQ) + goto reauth; + if (!sh->ioc_share[0] && !(ctx->ct_flags & SMBCF_XXX)) { + smb_error(dgettext(TEXT_DOMAIN, + "no share specified for %s@%s"), + 0, ssn->ioc_user, ssn->ioc_srvname); + return (EINVAL); + } + } + ctx->ct_flags |= SMBCF_RESOLVED; + + if (smb_debug) + dump_ctx("after smb_ctx_resolve", ctx); + + return (0); +} + +int +smb_open_driver() +{ + char buf[20]; + int err, fd, i; + uint32_t version; + + /* + * First try to open as clone + */ + fd = open("/dev/"NSMB_NAME, O_RDWR); + if (fd >= 0) + goto opened; + + err = errno; /* from open */ +#ifdef APPLE + /* + * well, no clone capabilities available - we have to scan + * all devices in order to get free one + */ + for (i = 0; i < 1024; i++) { + snprintf(buf, sizeof (buf), "/dev/%s%d", NSMB_NAME, i); + fd = open(buf, O_RDWR); + if (fd >= 0) + goto opened; + if (i && POWEROF2(i+1)) + smb_error(dgettext(TEXT_DOMAIN, + "%d failures to open smb device"), errno, i+1); + } + err = ENOENT; +#endif + smb_error(dgettext(TEXT_DOMAIN, + "failed to open %s"), err, "/dev/" NSMB_NAME); + return (-1); + +opened: + /* + * Check the driver version (paranoia) + * Do this BEFORE any other ioctl calls. + */ + if (ioctl(fd, SMBIOC_GETVERS, &version) < 0) { + err = errno; + smb_error(dgettext(TEXT_DOMAIN, + "failed to get driver version"), err); + close(fd); + return (-1); + } + if (version != NSMB_VERSION) { + smb_error(dgettext(TEXT_DOMAIN, + "incorrect driver version"), 0); + close(fd); + return (-1); + } + + return (fd); +} + +static int +smb_ctx_gethandle(struct smb_ctx *ctx) +{ + int err, fd; + + if (ctx->ct_fd != -1) { + rpc_cleanup_smbctx(ctx); + close(ctx->ct_fd); + ctx->ct_fd = -1; + ctx->ct_flags &= ~SMBCF_SSNACTIVE; + } + + fd = smb_open_driver(); + if (fd < 0) + return (ENODEV); + + ctx->ct_fd = fd; + return (0); +} + +int +smb_ctx_ioctl(struct smb_ctx *ctx, int inum, struct smbioc_lookup *rqp) +{ + size_t siz = DEF_SEC_TOKEN_LEN; + int rc = 0; + struct sockaddr sap1, sap2; + int i; + + if (rqp->ioc_ssn.ioc_outtok) + free(rqp->ioc_ssn.ioc_outtok); + rqp->ioc_ssn.ioc_outtoklen = siz; + rqp->ioc_ssn.ioc_outtok = malloc(siz+1); + if (rqp->ioc_ssn.ioc_outtok == NULL) + return (ENOMEM); + bzero(rqp->ioc_ssn.ioc_outtok, siz+1); + /* Note: No longer put length in outtok[0] */ + /* *((int *)rqp->ioc_ssn.ioc_outtok) = (int)siz; */ + + seteuid(eff_uid); /* restore setuid root briefly */ + if (ioctl(ctx->ct_fd, inum, rqp) == -1) { + rc = errno; + goto out; + } + if (rqp->ioc_ssn.ioc_outtoklen <= siz) + goto out; + + /* + * Operation completed, but our output token wasn't large enough. + * The re-call below only pulls the token from the kernel. + */ + siz = rqp->ioc_ssn.ioc_outtoklen; + free(rqp->ioc_ssn.ioc_outtok); + rqp->ioc_ssn.ioc_outtok = malloc(siz + 1); + if (rqp->ioc_ssn.ioc_outtok == NULL) { + rc = ENOMEM; + goto out; + } + bzero(rqp->ioc_ssn.ioc_outtok, siz+1); + /* Note: No longer put length in outtok[0] */ + /* *((int *)rqp->ioc_ssn.ioc_outtok) = siz; */ + if (ioctl(ctx->ct_fd, inum, rqp) == -1) + rc = errno; +out: + seteuid(real_uid); /* and back to real user */ + return (rc); +} + + +/* + * adds a GSSAPI wrapper + */ +char * +smb_ctx_tkt2gtok(uchar_t *tkt, ulong_t tktlen, + uchar_t **gtokp, ulong_t *gtoklenp) +{ + ulong_t bloblen = tktlen; + ulong_t len; + uchar_t krbapreq[2] = "\x01\x00"; /* see RFC 1964 */ + char *failure; + uchar_t *blob = NULL; /* result */ + uchar_t *b; + + bloblen += sizeof (krbapreq); + bloblen += g_stcMechOIDList[spnego_mech_oid_Kerberos_V5].iLen; + len = bloblen; + bloblen = ASNDerCalcTokenLength(bloblen, bloblen); + failure = dgettext(TEXT_DOMAIN, "smb_ctx_tkt2gtok malloc"); + if (!(blob = malloc(bloblen))) + goto out; + b = blob; + b += ASNDerWriteToken(b, SPNEGO_NEGINIT_APP_CONSTRUCT, NULL, len); + b += ASNDerWriteOID(b, spnego_mech_oid_Kerberos_V5); + memcpy(b, krbapreq, sizeof (krbapreq)); + b += sizeof (krbapreq); + failure = dgettext(TEXT_DOMAIN, "smb_ctx_tkt2gtok insanity check"); + if (b + tktlen != blob + bloblen) + goto out; + memcpy(b, tkt, tktlen); + *gtoklenp = bloblen; + *gtokp = blob; + failure = NULL; +out:; + if (blob && failure) + free(blob); + return (failure); +} + + +/* + * Initialization for Kerberos, pulled out of smb_ctx_principal2tkt. + * This just gets our cached credentials, if we have any. + * Based on the "klist" command. + */ +char * +smb_ctx_krb5init(struct smb_ctx *ctx) +{ + char *failure; + krb5_error_code kerr; + krb5_context kctx = NULL; + krb5_ccache kcc = NULL; + krb5_principal kprin = NULL; + + kerr = krb5_init_context(&kctx); + if (kerr) { + failure = "krb5_init_context"; + goto out; + } + ctx->ct_krb5ctx = kctx; + + /* non-default would instead use krb5_cc_resolve */ + kerr = krb5_cc_default(kctx, &kcc); + if (kerr) { + failure = "krb5_cc_default"; + goto out; + } + ctx->ct_krb5cc = kcc; + + /* + * Get the client principal (ticket), + * or find out if we don't have one. + */ + kerr = krb5_cc_get_principal(kctx, kcc, &kprin); + if (kerr) { + failure = "krb5_cc_get_principal"; + goto out; + } + ctx->ct_krb5cp = kprin; + + if (smb_verbose) { + fprintf(stderr, gettext("Ticket cache: %s:%s\n"), + krb5_cc_get_type(kctx, kcc), + krb5_cc_get_name(kctx, kcc)); + } + failure = NULL; + +out: + return (failure); +} + + +/* + * See "Windows 2000 Kerberos Interoperability" paper by + * Christopher Nebergall. RC4 HMAC is the W2K default but + * Samba support lagged (not due to Samba itself, but due to OS' + * Kerberos implementations.) + * + * Only session enc type should matter, not ticket enc type, + * per Sam Hartman on krbdev. + * + * Preauthentication failure topics in krb-protocol may help here... + * try "John Brezak" and/or "Clifford Neuman" too. + */ +static krb5_enctype kenctypes[] = { + ENCTYPE_ARCFOUR_HMAC, /* defined in Tiger krb5.h */ + ENCTYPE_DES_CBC_MD5, + ENCTYPE_DES_CBC_CRC, + ENCTYPE_NULL +}; + +/* + * Obtain a kerberos ticket... + * (if TLD != "gov" then pray first) + */ +char * +smb_ctx_principal2tkt( + struct smb_ctx *ctx, char *prin, + uchar_t **tktp, ulong_t *tktlenp) +{ + char *failure; + krb5_context kctx = NULL; + krb5_error_code kerr; + krb5_ccache kcc = NULL; + krb5_principal kprin = NULL, cprn = NULL; + krb5_creds kcreds, *kcredsp = NULL; + krb5_auth_context kauth = NULL; + krb5_data kdata, kdata0; + uchar_t *tkt; + + memset((char *)&kcreds, 0, sizeof (kcreds)); + kdata0.length = 0; + + /* These shoud have been done in smb_ctx_krb5init() */ + if (ctx->ct_krb5ctx == NULL || + ctx->ct_krb5cc == NULL || + ctx->ct_krb5cp == NULL) { + failure = "smb_ctx_krb5init"; + goto out; + } + kctx = ctx->ct_krb5ctx; + kcc = ctx->ct_krb5cc; + cprn = ctx->ct_krb5cp; + + failure = "krb5_set_default_tgs_enctypes"; + if ((kerr = krb5_set_default_tgs_enctypes(kctx, kenctypes))) + goto out; + /* + * The following is an unrolling of krb5_mk_req. Something like: + * krb5_mk_req(kctx, &kauth, 0, service(prin), hostname(prin), + * &kdata0, kcc, &kdata);) + * ...except we needed krb5_parse_name not krb5_sname_to_principal. + */ + failure = "krb5_parse_name"; + if ((kerr = krb5_parse_name(kctx, prin, &kprin))) + goto out; + failure = "krb5_copy_principal(server)"; + if ((kerr = krb5_copy_principal(kctx, kprin, &kcreds.server))) + goto out; + failure = "krb5_copy_principal(client)"; + if ((kerr = krb5_copy_principal(kctx, cprn, &kcreds.client))) + goto out; + failure = "krb5_get_credentials"; + if ((kerr = krb5_get_credentials(kctx, 0, kcc, &kcreds, &kcredsp))) + goto out; + failure = "krb5_mk_req_extended"; + if ((kerr = krb5_mk_req_extended(kctx, &kauth, 0, &kdata0, kcredsp, + &kdata))) + goto out; + failure = "malloc"; + if (!(tkt = malloc(kdata.length))) { + krb5_free_data_contents(kctx, &kdata); + goto out; + } + *tktlenp = kdata.length; + memcpy(tkt, kdata.data, kdata.length); + krb5_free_data_contents(kctx, &kdata); + *tktp = tkt; + failure = NULL; +out:; + if (kerr) { + if (!failure) + failure = "smb_ctx_principal2tkt"; + /* + * Avoid logging the typical "No credentials cache found" + */ + if (kerr != KRB5_FCC_NOFILE || + strcmp(failure, "krb5_cc_get_principal")) + com_err(__progname, kerr, failure); + } + if (kauth) + krb5_auth_con_free(kctx, kauth); + if (kcredsp) + krb5_free_creds(kctx, kcredsp); + if (kcreds.server || kcreds.client) + krb5_free_cred_contents(kctx, &kcreds); + if (kprin) + krb5_free_principal(kctx, kprin); + + /* Free kctx in smb_ctx_done */ + + return (failure); +} + +char * +smb_ctx_principal2blob( + struct smb_ctx *ctx, + smbioc_ossn_t *ssn, + char *prin) +{ + int rc = 0; + char *failure; + uchar_t *tkt = NULL; + ulong_t tktlen; + uchar_t *gtok = NULL; /* gssapi token */ + ulong_t gtoklen; /* gssapi token length */ + SPNEGO_TOKEN_HANDLE stok = NULL; /* spnego token */ + void *blob = NULL; /* result */ + ulong_t bloblen; /* result length */ + + if ((failure = smb_ctx_principal2tkt(ctx, prin, &tkt, &tktlen))) + goto out; + if ((failure = smb_ctx_tkt2gtok(tkt, tktlen, >ok, >oklen))) + goto out; + /* + * RFC says to send NegTokenTarg now. So does MS docs. But + * win2k gives ERRbaduid if we do... we must send + * another NegTokenInit now! + */ + failure = "spnegoCreateNegTokenInit"; + if ((rc = spnegoCreateNegTokenInit(spnego_mech_oid_Kerberos_V5_Legacy, + 0, gtok, gtoklen, NULL, 0, &stok))) + goto out; + failure = "spnegoTokenGetBinary(NULL)"; + rc = spnegoTokenGetBinary(stok, NULL, &bloblen); + if (rc != SPNEGO_E_BUFFER_TOO_SMALL) + goto out; + failure = "malloc"; + if (!(blob = malloc((size_t)bloblen))) + goto out; + /* No longer store length at start of blob. */ + /* *blob = bloblen; */ + failure = "spnegoTokenGetBinary"; + if ((rc = spnegoTokenGetBinary(stok, blob, &bloblen))) + goto out; + ssn->ioc_intoklen = bloblen; + ssn->ioc_intok = blob; + failure = NULL; +out:; + if (rc) { + /* XXX better is to embed rc in failure */ + smb_error(dgettext(TEXT_DOMAIN, + "spnego principal2blob error %d"), 0, -rc); + if (!failure) + failure = "spnego"; + } + if (blob && failure) + free(blob); + if (stok) + spnegoFreeData(stok); + if (gtok) + free(gtok); + if (tkt) + free(tkt); + return (failure); +} + + +#if 0 +void +prblob(uchar_t *b, size_t len) +{ + while (len--) + fprintf(stderr, "%02x", *b++); + fprintf(stderr, "\n"); +} +#endif + + +/* + * We navigate the SPNEGO & ASN1 encoding to find a kerberos principal + * Note: driver no longer puts length at start of blob. + */ +char * +smb_ctx_blob2principal( + struct smb_ctx *ctx, + smbioc_ossn_t *ssn, + char **prinp) +{ + uchar_t *blob = ssn->ioc_outtok; + size_t len = ssn->ioc_outtoklen; + int rc = 0; + SPNEGO_TOKEN_HANDLE stok = NULL; + int indx = 0; + char *failure; + uchar_t flags = 0; + unsigned long plen = 0; + uchar_t *prin; + +#if 0 + fprintf(stderr, "blob from negotiate:\n"); + prblob(blob, len); +#endif + + /* Skip the GUID */ + assert(len >= SMB_GUIDLEN); + blob += SMB_GUIDLEN; + len -= SMB_GUIDLEN; + + failure = "spnegoInitFromBinary"; + if ((rc = spnegoInitFromBinary(blob, len, &stok))) + goto out; + /* + * Needn't use new Kerberos OID - the Legacy one is fine. + */ + failure = "spnegoIsMechTypeAvailable"; + if (spnegoIsMechTypeAvailable(stok, spnego_mech_oid_Kerberos_V5_Legacy, + &indx)) + goto out; + /* + * Ignoring optional context flags for now. May want to pass + * them to krb5 layer. XXX + */ + if (!spnegoGetContextFlags(stok, &flags)) + fprintf(stderr, dgettext(TEXT_DOMAIN, + "spnego context flags 0x%x\n"), flags); + failure = "spnegoGetMechListMIC(NULL)"; + rc = spnegoGetMechListMIC(stok, NULL, &plen); + if (rc != SPNEGO_E_BUFFER_TOO_SMALL) + goto out; + failure = "malloc"; + if (!(prin = malloc(plen + 1))) + goto out; + failure = "spnegoGetMechListMIC"; + if ((rc = spnegoGetMechListMIC(stok, prin, &plen))) { + free(prin); + goto out; + } + prin[plen] = '\0'; + *prinp = (char *)prin; + failure = NULL; +out:; + if (stok) + spnegoFreeData(stok); + if (rc) { + /* XXX better is to embed rc in failure */ + smb_error(dgettext(TEXT_DOMAIN, + "spnego blob2principal error %d"), 0, -rc); + if (!failure) + failure = "spnego"; + } + return (failure); +} + + +int +smb_ctx_negotiate(struct smb_ctx *ctx, int level, int flags, char *workgroup) +{ + struct smbioc_lookup rq; + int error = 0; + char *failure = NULL; + char *principal = NULL; + char c; + int i; + ssize_t *outtoklen; + uchar_t *blob; + + /* + * We leave ct_secblob set iff extended security + * negotiation succeeds. + */ + if (ctx->ct_secblob) { + free(ctx->ct_secblob); + ctx->ct_secblob = NULL; + } +#ifdef XXX + if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { + smb_error(dgettext(TEXT_DOMAIN, + "smb_ctx_lookup() data is not resolved"), 0); + return (EINVAL); + } +#endif + if ((error = smb_ctx_gethandle(ctx))) + return (error); + + bzero(&rq, sizeof (rq)); + bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); + bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); + + /* + * Find out if we have a Kerberos ticket, + * and only offer SPNEGO if we have one. + */ + failure = smb_ctx_krb5init(ctx); + if (failure) { + if (smb_verbose) + smb_error(failure, 0); + goto out; + } + + rq.ioc_flags = flags; + rq.ioc_level = level; + rq.ioc_ssn.ioc_opt |= SMBVOPT_EXT_SEC; + error = smb_ctx_ioctl(ctx, SMBIOC_NEGOTIATE, &rq); + if (error) { + failure = dgettext(TEXT_DOMAIN, "negotiate failed"); + smb_error(failure, error); + if (error == ETIMEDOUT) + return (error); + goto out; + } + /* + * If the server capabilities did not include + * SMB_CAP_EXT_SECURITY then the driver clears + * the flag SMBVOPT_EXT_SEC for us. + * XXX: should add the capabilities to ioc_ssn + * XXX: see comment in driver - smb_usr.c + */ + failure = dgettext(TEXT_DOMAIN, "SPNEGO unsupported"); + if ((rq.ioc_ssn.ioc_opt & SMBVOPT_EXT_SEC) == 0) { + if (smb_verbose) + smb_error(failure, 0); + /* + * Do regular (old style) NTLM or NTLMv2 + * Nothing more to do here in negotiate. + */ + return (0); + } + + /* + * Capabilities DO include SMB_CAP_EXT_SECURITY, + * so this should be an SPNEGO security blob. + * Parse the ASN.1/DER, prepare response(s). + * XXX: Handle STATUS_MORE_PROCESSING_REQUIRED? + * XXX: Requires additional session setup calls. + */ + if (rq.ioc_ssn.ioc_outtoklen <= SMB_GUIDLEN) + goto out; + /* some servers send padding junk */ + blob = rq.ioc_ssn.ioc_outtok; + if (blob[0] == 0) + goto out; + + failure = smb_ctx_blob2principal( + ctx, &rq.ioc_ssn, &principal); + if (failure) + goto out; + failure = smb_ctx_principal2blob( + ctx, &rq.ioc_ssn, principal); + if (failure) + goto out; + + /* Success! Save the blob to send next. */ + ctx->ct_secblob = rq.ioc_ssn.ioc_intok; + ctx->ct_secbloblen = rq.ioc_ssn.ioc_intoklen; + rq.ioc_ssn.ioc_intok = NULL; + +out: + if (principal) + free(principal); + if (rq.ioc_ssn.ioc_intok) + free(rq.ioc_ssn.ioc_intok); + if (rq.ioc_ssn.ioc_outtok) + free(rq.ioc_ssn.ioc_outtok); + if (!failure) + return (0); /* Success! */ + + /* + * Negotiate failed with "extended security". + * + * XXX: If we are doing SPNEGO correctly, + * we should never get here unless the user + * supplied invalid authentication data, + * or we saw some kind of protocol error. + * + * XXX: The error message below should be + * XXX: unconditional (remove "if verbose") + * XXX: but not until we have "NTLMSSP" + * Avoid spew for anticipated failure modes + * but enable this with the verbose flag + */ + if (smb_verbose) { + smb_error(dgettext(TEXT_DOMAIN, + "%s (extended security negotiate)"), error, failure); + } + + /* + * XXX: Try again using NTLM (or NTLMv2) + * XXX: Normal clients don't do this. + * XXX: Should just return an error, but + * keep the fall-back to NTLM for now. + * + * Start over with a new connection. + */ + if ((error = smb_ctx_gethandle(ctx))) + return (error); + bzero(&rq, sizeof (rq)); + bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); + bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); + rq.ioc_flags = flags; + rq.ioc_level = level; + /* Note: NO SMBVOPT_EXT_SEC */ + error = smb_ctx_ioctl(ctx, SMBIOC_NEGOTIATE, &rq); + if (error) { + failure = dgettext(TEXT_DOMAIN, "negotiate failed"); + smb_error(failure, error); + rpc_cleanup_smbctx(ctx); + close(ctx->ct_fd); + ctx->ct_fd = -1; + return (error); + } + + /* + * Used to copy the workgroup out of the SMB_NEGOTIATE response + * here, to default our domain name to be the same as the server. + * Not a good idea: Unnecessary at best, and sometimes wrong, i.e. + * when our account is in a trusted domain. + */ + + return (error); +} + + +int +smb_ctx_tdis(struct smb_ctx *ctx) +{ + struct smbioc_lookup rq; /* XXX may be used, someday */ + int error = 0; + + if (ctx->ct_fd < 0) { + smb_error(dgettext(TEXT_DOMAIN, + "tree disconnect without handle?!"), 0); + return (EINVAL); + } + if (!(ctx->ct_flags & SMBCF_SSNACTIVE)) { + smb_error(dgettext(TEXT_DOMAIN, + "tree disconnect without session?!"), 0); + return (EINVAL); + } + bzero(&rq, sizeof (rq)); + bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); + bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); + if (ioctl(ctx->ct_fd, SMBIOC_TDIS, &rq) == -1) { + error = errno; + smb_error(dgettext(TEXT_DOMAIN, + "tree disconnect failed"), error); + } + return (error); +} + + +int +smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags) +{ + struct smbioc_lookup rq; + int error = 0; + char *failure = NULL; + + if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) { + smb_error(dgettext(TEXT_DOMAIN, + "smb_ctx_lookup() data is not resolved"), 0); + return (EINVAL); + } + if (ctx->ct_fd < 0) { + smb_error(dgettext(TEXT_DOMAIN, + "handle from smb_ctx_nego() gone?!"), 0); + return (EINVAL); + } + if (!(flags & SMBLK_CREATE)) + return (0); + bzero(&rq, sizeof (rq)); + bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn)); + bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare)); + rq.ioc_flags = flags; + rq.ioc_level = level; + + /* + * Iff we have a security blob, we're using + * extended security... + */ + if (ctx->ct_secblob) { + rq.ioc_ssn.ioc_opt |= SMBVOPT_EXT_SEC; + if (!(ctx->ct_flags & SMBCF_SSNACTIVE)) { + rq.ioc_ssn.ioc_intok = ctx->ct_secblob; + rq.ioc_ssn.ioc_intoklen = ctx->ct_secbloblen; + error = smb_ctx_ioctl(ctx, SMBIOC_SSNSETUP, &rq); + } + rq.ioc_ssn.ioc_intok = NULL; + if (error) { + failure = dgettext(TEXT_DOMAIN, + "session setup failed"); + } else { + ctx->ct_flags |= SMBCF_SSNACTIVE; + if ((error = smb_ctx_ioctl(ctx, SMBIOC_TCON, &rq))) + failure = dgettext(TEXT_DOMAIN, + "tree connect failed"); + } + if (rq.ioc_ssn.ioc_intok) + free(rq.ioc_ssn.ioc_intok); + if (rq.ioc_ssn.ioc_outtok) + free(rq.ioc_ssn.ioc_outtok); + if (!failure) + return (0); + smb_error(dgettext(TEXT_DOMAIN, + "%s (extended security lookup2)"), error, failure); + /* unwise to failback to NTLM now */ + return (error); + } + + /* + * Otherwise we're doing plain old NTLM + */ + seteuid(eff_uid); /* restore setuid root briefly */ + if ((ctx->ct_flags & SMBCF_SSNACTIVE) == 0) { + /* + * This is the magic that tells the driver to + * copy the password from the keychain, and + * whether to use the system name or the + * account domain to lookup the keychain. + */ + if (ctx->ct_flags & SMBCF_KCFOUND) + rq.ioc_ssn.ioc_opt |= SMBVOPT_USE_KEYCHAIN; + if (ctx->ct_flags & SMBCF_KCDOMAIN) + rq.ioc_ssn.ioc_opt |= SMBVOPT_KC_DOMAIN; + if (ioctl(ctx->ct_fd, SMBIOC_SSNSETUP, &rq) < 0) { + error = errno; + failure = dgettext(TEXT_DOMAIN, "session setup"); + goto out; + } + ctx->ct_flags |= SMBCF_SSNACTIVE; + } + if (ioctl(ctx->ct_fd, SMBIOC_TCON, &rq) == -1) { + error = errno; + failure = dgettext(TEXT_DOMAIN, "tree connect"); + } + +out: + seteuid(real_uid); /* and back to real user */ + if (failure) { + error = errno; + smb_error(dgettext(TEXT_DOMAIN, + "%s phase failed"), error, failure); + } + return (error); +} + +/* + * Return the hflags2 word for an smb_ctx. + */ +int +smb_ctx_flags2(struct smb_ctx *ctx) +{ + uint16_t flags2; + + if (ioctl(ctx->ct_fd, SMBIOC_FLAGS2, &flags2) == -1) { + smb_error(dgettext(TEXT_DOMAIN, + "can't get flags2 for a session"), errno); + return (-1); + } + printf(dgettext(TEXT_DOMAIN, "Flags2 value is %d\n"), flags2); + return (flags2); +} + +/* + * level values: + * 0 - default + * 1 - server + * 2 - server:user + * 3 - server:user:share + */ +static int +smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) +{ + char *p; + int error; + +#ifdef NOT_DEFINED + if (level > 0) { + rc_getstringptr(smb_rc, sname, "charsets", &p); + if (p) { + error = smb_ctx_setcharset(ctx, p); + if (error) + smb_error(dgettext(TEXT_DOMAIN, + "charset specification in the section '%s' ignored"), + error, sname); + } + } +#endif + + if (level <= 1) { + /* Section is: [default] or [server] */ + + rc_getint(smb_rc, sname, "timeout", + &ctx->ct_ssn.ioc_timeout); + +#ifdef NOT_DEFINED + rc_getint(smb_rc, sname, "retry_count", + &ctx->ct_ssn.ioc_retrycount); + rc_getstringptr(smb_rc, sname, "use_negprot_domain", &p); + if (p && strcmp(p, "NO") == 0) + ctx->ct_flags |= SMBCF_NONEGDOM; +#endif + + rc_getstringptr(smb_rc, sname, "minauth", &p); + if (p) { + /* + * "minauth" was set in this section; override + * the current minimum authentication setting. + */ + ctx->ct_ssn.ioc_opt &= ~SMBVOPT_MINAUTH; + if (strcmp(p, "kerberos") == 0) { + /* + * Don't fall back to NTLMv2, NTLMv1, or + * a clear text password. + */ + ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_KERBEROS; + } else if (strcmp(p, "ntlmv2") == 0) { + /* + * Don't fall back to NTLMv1 or a clear + * text password. + */ + ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NTLMV2; + } else if (strcmp(p, "ntlm") == 0) { + /* + * Don't send the LM response over the wire. + */ + ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NTLM; + } else if (strcmp(p, "lm") == 0) { + /* + * Fail if the server doesn't do encrypted + * passwords. + */ + ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_LM; + } else if (strcmp(p, "none") == 0) { + /* + * Anything goes. + * (The following statement should be + * optimized away.) + */ + /* LINTED */ + ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NONE; + } else { + /* + * Unknown minimum authentication level. + */ + smb_error(dgettext(TEXT_DOMAIN, +"invalid minimum authentication level \"%s\" specified in the section %s"), + 0, p, sname); + return (EINVAL); + } + } + + /* + * Domain name. Allow both keywords: + * "workgroup", "domain" + * + * Note: these are NOT marked "from CMD". + * See long comment at smb_ctx_init() + */ + rc_getstringptr(smb_rc, sname, "workgroup", &p); + if (p) { + nls_str_upper(p, p); + error = smb_ctx_setworkgroup(ctx, p, 0); + if (error) + smb_error(dgettext(TEXT_DOMAIN, + "workgroup specification in the " + "section '%s' ignored"), error, sname); + } + rc_getstringptr(smb_rc, sname, "domain", &p); + if (p) { + nls_str_upper(p, p); + error = smb_ctx_setworkgroup(ctx, p, 0); + if (error) + smb_error(dgettext(TEXT_DOMAIN, + "domain specification in the " + "section '%s' ignored"), error, sname); + } + + rc_getstringptr(smb_rc, sname, "user", &p); + if (p) { + error = smb_ctx_setuser(ctx, p, 0); + if (error) + smb_error(dgettext(TEXT_DOMAIN, + "user specification in the " + "section '%s' ignored"), error, sname); + } + } + + if (level == 1) { + /* Section is: [server] */ + rc_getstringptr(smb_rc, sname, "addr", &p); + if (p) { + error = smb_ctx_setsrvaddr(ctx, p); + if (error) { + smb_error(dgettext(TEXT_DOMAIN, + "invalid address specified in section %s"), + 0, sname); + return (error); + } + } + } + + rc_getstringptr(smb_rc, sname, "password", &p); + if (p) { + error = smb_ctx_setpassword(ctx, p, 0); + if (error) + smb_error(dgettext(TEXT_DOMAIN, + "password specification in the section '%s' ignored"), + error, sname); + } + + return (0); +} + +/* + * read rc file as follows: + * 0: read [default] section + * 1: override with [server] section + * 2: override with [server:user] section + * 3: override with [server:user:share] section + * Since absence of rcfile is not fatal, silently ignore this fact. + * smb_rc file should be closed by caller. + */ +int +smb_ctx_readrc(struct smb_ctx *ctx) +{ + char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN + + SMB_MAXSHARENAMELEN + 4]; + + if (smb_open_rcfile(ctx) != 0) + goto done; + + /* + * default parameters (level=0) + */ + smb_ctx_readrcsection(ctx, "default", 0); + nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0); + + /* + * If we don't have a server name, we can't read any of the + * [server...] sections. + */ + if (ctx->ct_ssn.ioc_srvname[0] == 0) + goto done; + + /* + * SERVER parameters. + */ + smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1); + + /* + * If we don't have a user name, we can't read any of the + * [server:user...] sections. + */ + if (ctx->ct_ssn.ioc_user[0] == 0) + goto done; + + /* + * SERVER:USER parameters + */ + snprintf(sname, sizeof (sname), "%s:%s", + ctx->ct_ssn.ioc_srvname, + ctx->ct_ssn.ioc_user); + smb_ctx_readrcsection(ctx, sname, 2); + + /* + * If we don't have a share name, we can't read any of the + * [server:user:share] sections. + */ + if (ctx->ct_sh.ioc_share[0] != 0) { + /* + * SERVER:USER:SHARE parameters + */ + snprintf(sname, sizeof (sname), "%s:%s:%s", + ctx->ct_ssn.ioc_srvname, + ctx->ct_ssn.ioc_user, + ctx->ct_sh.ioc_share); + smb_ctx_readrcsection(ctx, sname, 3); + } + +done: + if (smb_debug) + dump_ctx("after smb_ctx_readrc", ctx); + + return (0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/derparse.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,750 @@ +/* +// Copyright (C) 2002 Microsoft Corporation +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" +// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +// OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY +// AND/OR FITNESS FOR A PARTICULAR PURPOSE. +// +// Date - 10/08/2002 +// Author - Sanj Surati + + +///////////////////////////////////////////////////////////// +// +// DERPARSE.C +// +// SPNEGO Token Handler Source File +// +// Contains implementation of ASN.1 DER read/write functions +// as defined in DERPARSE.H. +// +///////////////////////////////////////////////////////////// + +*/ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <stdio.h> +#include <memory.h> +#include <sys/byteorder.h> +#include "spnego.h" +#include "derparse.h" + +/* +// +// The GSS Mechanism OID enumeration values (SPNEGO_MECH_OID) control which offset in +// the array below, that a mechanism can be found. +// +*/ +#pragma error_messages (off,E_INITIALIZATION_TYPE_MISMATCH) +MECH_OID g_stcMechOIDList [] = +{ + {"\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02", 11, 9, + spnego_mech_oid_Kerberos_V5_Legacy }, // 1.2.840.48018.1.2.2 + {"\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02", 11, 9, + spnego_mech_oid_Kerberos_V5 }, // 1.2.840.113554.1.2.2 + {"\x06\x06\x2b\x06\x01\x05\x05\x02", 8, 6, + spnego_mech_oid_Spnego }, // 1.3.6.1.5.5.2 + {"\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a", 12, 10, + spnego_mech_oid_NTLMSSP }, // 1.3.6.1.4.1.311.2.2.10 + {"", 0, 0, spnego_mech_oid_NotUsed } // Placeholder +}; +#pragma error_messages (default,E_INITIALIZATION_TYPE_MISMATCH) + +/* +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerGetLength +// +// Parameters: +// [in] pbLengthData - DER Length Data +// [in] nBoundaryLength - Length that value must not exceed. +// [out] pnLength - Filled out with length value +// [out] pnNumLengthBytes - Filled out with number of bytes +// consumed by DER length. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Interprets the data at pbLengthData as a DER length. The length must +// fit within the bounds of nBoundary length. We do not currently +// process lengths that take more than 4 bytes. +// +//////////////////////////////////////////////////////////////////////////// +*/ + +int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength, + long* pnNumLengthBytes ) +{ + int nReturn = SPNEGO_E_INVALID_LENGTH; + int nNumLengthBytes = 0; + + // First check if the extended length bit is set + + if ( *pbLengthData & LEN_XTND ) + { + // Lower 7 bits contain the number of trailing bytes that describe the length + nNumLengthBytes = *pbLengthData & LEN_MASK; + + // Check that the number of bytes we are about to read is within our boundary + // constraints + + if ( nNumLengthBytes <= nBoundaryLength - 1 ) + { + + // For now, our handler won't deal with lengths greater than 4 bytes + if ( nNumLengthBytes >= 1 && nNumLengthBytes <= 4 ) + { + // 0 out the initial length + *pnLength = 0L; + + // Bump by 1 byte + pbLengthData++; + + #ifdef _LITTLE_ENDIAN + + // There may be a cleaner way to do this, but for now, this seems to be + // an easy way to do the transformation + switch ( nNumLengthBytes ) + { + case 1: + { + *( ( (unsigned char*) pnLength ) ) = *pbLengthData; + break; + } + + case 2: + { + *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 1); + *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData); + + break; + } + + case 3: + { + *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 2); + *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1); + *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData); + break; + } + + case 4: + { + *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 3); + *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData + 2); + *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1); + *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData); + break; + } + + } // SWITCH ( nNumLengthBytes ) + + #else + // We are Big-Endian, so the length can be copied in from the source + // as is. Ensure that we adjust for the number of bytes we actually + // copy. + + memcpy( ( (unsigned char *) pnLength ) + ( 4 - nNumLengthBytes ), + pbLengthData, nNumLengthBytes ); + #endif + + // Account for the initial length byte + *pnNumLengthBytes = nNumLengthBytes + 1; + nReturn = SPNEGO_E_SUCCESS; + + } // IF Valid Length + + } // IF num bytes to read is within the boundary length + + } // IF xtended length + else + { + + // Extended bit is not set, so the length is in the value and the one + // byte describes the length + *pnLength = *pbLengthData & LEN_MASK; + *pnNumLengthBytes = 1; + nReturn = SPNEGO_E_SUCCESS; + + } + + return nReturn; +} + + +/* +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerCheckToken +// +// Parameters: +// [in] pbTokenData - Token Data +// [in] nToken - Token identifier to check for +// [in] nLengthWithToken - Expected token length (with data) +// [in] nBoundaryLength - Length that value must not exceed. +// [out] pnLength - Filled out with data length +// [out] pnTokenLength - Filled out with number of bytes +// consumed by token identifier and length. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Checks the data pointed to by pbTokenData for the specified token +// identifier and the length that immediately follows. If +// nLengthWithToken is > 0, the calculated length must match. The +// length must also not exceed the specified boundary length . +// +//////////////////////////////////////////////////////////////////////////// +*/ + +int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken, + long nLengthWithToken, long nBoundaryLength, + long* pnLength, long* pnTokenLength ) +{ + + int nReturn = SPNEGO_E_INVALID_LENGTH; + long nNumLengthBytes = 0L; + + // Make sure that we've at least got 2 bytes of room to work with + + if ( nBoundaryLength >= 2 ) + { + // The first byte of the token data MUST match the specified token + if ( *pbTokenData == nToken ) + { + // Next byte indicates the length + pbTokenData++; + + // Get the length described by the token + if ( ( nReturn = ASNDerGetLength( pbTokenData, nBoundaryLength, pnLength, + &nNumLengthBytes ) ) == SPNEGO_E_SUCCESS ) + { + // Verify that the length is LESS THAN the boundary length + // (this should prevent us walking out of our buffer) + if ( ( nBoundaryLength - ( nNumLengthBytes + 1 ) < *pnLength ) ) + { + + nReturn = SPNEGO_E_INVALID_LENGTH; + + } + + // If we were passed a length to check, do so now + if ( nLengthWithToken > 0L ) + { + + // Check that the expected length matches + if ( ( nLengthWithToken - ( nNumLengthBytes + 1 ) ) != *pnLength ) + { + + nReturn = SPNEGO_E_INVALID_LENGTH; + + } + + } // IF need to validate length + + if ( SPNEGO_E_SUCCESS == nReturn ) + { + *pnTokenLength = nNumLengthBytes + 1; + } + + } // IF ASNDerGetLength + + } // IF token matches + else + { + nReturn = SPNEGO_E_TOKEN_NOT_FOUND; + } + + } // IF Boundary Length is at least 2 bytes + + return nReturn; +} + +/* +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerCheckOID +// +// Parameters: +// [in] pbTokenData - Token Data +// [in] nMechOID - OID we are looking for +// [in] nBoundaryLength - Length that value must not exceed. +// [out] pnTokenLength - Filled out with number of bytes +// consumed by token and data. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Checks the data pointed to by pbTokenData for the specified OID. +// +//////////////////////////////////////////////////////////////////////////// +*/ + +int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength, + long* pnTokenLength ) +{ + int nReturn = 0L; + long nLength = 0L; + + // Verify that we have an OID token + if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID, 0L, nBoundaryLength, + &nLength, pnTokenLength ) ) == SPNEGO_E_SUCCESS ) + { + // Add the data length to the Token Length + *pnTokenLength += nLength; + + // Token Lengths plus the actual length must match the length in our OID list element. + // If it doesn't, we're done + if ( *pnTokenLength == g_stcMechOIDList[nMechOID].iLen ) + { + // Memcompare the token and the expected field + if ( memcmp( pbTokenData, g_stcMechOIDList[nMechOID].ucOid, *pnTokenLength ) != 0 ) + { + nReturn = SPNEGO_E_UNEXPECTED_OID; + } + } + else + { + nReturn = SPNEGO_E_UNEXPECTED_OID; + } + + } // IF OID Token CHecks + + return nReturn; +} + +/* +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerCalcNumLengthBytes +// +// Parameters: +// [in] nLength - Length to calculate length bytes for. +// +// Returns: +// int Number of bytes necessary to represent length +// +// Comments : +// Helper function to calculate the number of length bytes necessary to +// represent a length value. For our purposes, a 32-bit value should be +// enough to describea length. +// +//////////////////////////////////////////////////////////////////////////// +*/ + +int ASNDerCalcNumLengthBytes( long nLength ) +{ + if ( nLength <= 0x7F ) + { + // A single byte will be sufficient for describing this length. + // The byte will simply contain the length + return 1; + } + else if ( nLength <= 0xFF ) + { + // Two bytes are necessary, one to say how many following bytes + // describe the length, and one to give the length + return 2; + } + else if ( nLength <= 0xFFFF ) + { + // Three bytes are necessary, one to say how many following bytes + // describe the length, and two to give the length + return 3; + } + else if ( nLength <= 0xFFFFFF ) + { + // Four bytes are necessary, one to say how many following bytes + // describe the length, and three to give the length + return 4; + } + else + { + // Five bytes are necessary, one to say how many following bytes + // describe the length, and four to give the length + return 5; + } +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerCalcTokenLength +// +// Parameters: +// [in] nLength - Length to calculate length bytes for. +// [in] nDataLength - Actual Data length value. +// +// Returns: +// long Number of bytes necessary to represent a token, length and data +// +// Comments : +// Helper function to calculate a token and value size, based on a +// supplied length value, and any binary data that will need to be +// written out. +// +//////////////////////////////////////////////////////////////////////////// + +long ASNDerCalcTokenLength( long nLength, long nDataLength ) +{ + // Add a byte to the length size to account for a single byte to + // hold the token type. + long nTotalLength = ASNDerCalcNumLengthBytes( nLength ) + 1; + + return nTotalLength + nDataLength; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerCalcElementLength +// +// Parameters: +// [in] nDataLength - Length of data. +// [out] pnInternalLength - Filled out with length of element +// without sequence info. +// +// Returns: +// long Number of bytes necessary to represent an element +// +// Comments : +// Helper function to calculate an element length. An element consists +// of a sequence token, a type token and then the data. +// +//////////////////////////////////////////////////////////////////////////// + +long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength ) +{ + // First the type token and the actual data + long nTotalLength = ASNDerCalcTokenLength( nDataLength, nDataLength ); + + // Internal length is the length without the element sequence token + if ( NULL != pnInternalLength ) + { + *pnInternalLength = nTotalLength; + } + + // Next add in the element's sequence token (remember that its + // length is the total length of the type token and data) + nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + return nTotalLength; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerCalcMechListLength +// +// Parameters: +// [in] mechoid - Mech OID to put in list. +// [out] pnInternalLength - Filled out with length of element +// without the primary sequence token. +// +// Returns: +// long Number of bytes necessary to represent a mechList +// +// Comments : +// Helper function to calculate a MechList length. A mechlist consists +// of a NegTokenInit sequence token, a sequence token for the MechList +// and finally a list of OIDs. In our case, we only really have one +// OID. +// +//////////////////////////////////////////////////////////////////////////// + +long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength ) +{ + // First the OID + long nTotalLength = g_stcMechOIDList[mechoid].iLen; + + // Next add in a sequence token + nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + // Internal length is the length without the element sequence token + if ( NULL != pnInternalLength ) + { + *pnInternalLength = nTotalLength; + } + + // Finally add in the element's sequence token + nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + return nTotalLength; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerWriteLength +// +// Parameters: +// [out] pbData - Buffer to write into. +// [in] nLength - Length to write out. +// +// Returns: +// int Number of bytes written out +// +// Comments : +// Helper function to write out a length value following DER rules . +// +//////////////////////////////////////////////////////////////////////////// + +int ASNDerWriteLength( unsigned char* pbData, long nLength ) +{ + int nNumBytesRequired = ASNDerCalcNumLengthBytes( nLength ); + int nNumLengthBytes = nNumBytesRequired - 1; + + + if ( nNumBytesRequired > 1 ) + { + + // Write out the number of bytes following which will be used + *pbData = (unsigned char ) ( LEN_XTND | nNumLengthBytes ); + + // Point to where we'll actually write the length + pbData++; + +#ifdef _LITTLE_ENDIAN + + // There may be a cleaner way to do this, but for now, this seems to be + // an easy way to do the transformation + switch ( nNumLengthBytes ) + { + case 1: + { + // Cast the length to a single byte, since we know that it + // is 0x7F or less (or we wouldn't only need a single byte). + + *pbData = (unsigned char) nLength; + break; + } + + case 2: + { + *pbData = *( ( (unsigned char*) &nLength ) + 1 ); + *( pbData + 1) = *( ( (unsigned char*) &nLength ) ); + break; + } + + case 3: + { + *pbData = *( ( (unsigned char*) &nLength ) + 3 ); + *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 ); + *( pbData + 2) = *( ( (unsigned char*) &nLength ) ); + break; + } + + case 4: + { + *pbData = *( ( (unsigned char*) &nLength ) + 3 ); + *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 ); + *( pbData + 2) = *( ( (unsigned char*) &nLength ) + 1 ); + *( pbData + 3) = *( ( (unsigned char*) &nLength ) ); + break; + } + + } // SWITCH ( nNumLengthBytes ) + +#else + // We are Big-Endian, so the length can be copied in from the source + // as is. Ensure that we adjust for the number of bytes we actually + // copy. + + memcpy( pbData, + ( (unsigned char *) &nLength ) + ( 4 - nNumLengthBytes ), nNumLengthBytes ); +#endif + + } // IF > 1 byte for length + else + { + // Cast the length to a single byte, since we know that it + // is 0x7F or less (or we wouldn't only need a single byte). + + *pbData = (unsigned char) nLength; + } + + return nNumBytesRequired; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerWriteToken +// +// Parameters: +// [out] pbData - Buffer to write into. +// [in] ucType - Token Type +// [in] pbTokenValue - Actual Value +// [in] nLength - Length of Data. +// +// Returns: +// int Number of bytes written out +// +// Comments : +// Helper function to write out a token and any associated data. If +// pbTokenValue is non-NULL, then it is written out in addition to the +// token identifier and the length bytes. +// +//////////////////////////////////////////////////////////////////////////// + +int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType, + unsigned char* pbTokenValue, long nLength ) +{ + int nTotalBytesWrittenOut = 0L; + int nNumLengthBytesWritten = 0L; + + // Write out the type + *pbData = ucType; + + // Wrote 1 byte, and move data pointer + nTotalBytesWrittenOut++; + pbData++; + + // Now write out the length and adjust the number of bytes written out + nNumLengthBytesWritten = ASNDerWriteLength( pbData, nLength ); + + nTotalBytesWrittenOut += nNumLengthBytesWritten; + pbData += nNumLengthBytesWritten; + + // Write out the token value if we got one. The assumption is that the + // nLength value indicates how many bytes are in pbTokenValue. + + if ( NULL != pbTokenValue ) + { + memcpy( pbData, pbTokenValue, nLength ); + nTotalBytesWrittenOut += nLength; + } + + return nTotalBytesWrittenOut; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerWriteOID +// +// Parameters: +// [out] pbData - Buffer to write into. +// [in] eMechOID - OID to write out. +// +// Returns: +// int Number of bytes written out +// +// Comments : +// Helper function to write out an OID. For these we have the raw bytes +// listed in a global structure. The caller simply indicates which OID +// should be written and we will splat out the data. +// +//////////////////////////////////////////////////////////////////////////// + +int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID ) +{ + + memcpy( pbData, g_stcMechOIDList[eMechOID].ucOid, g_stcMechOIDList[eMechOID].iLen ); + + return g_stcMechOIDList[eMechOID].iLen; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerWriteMechList +// +// Parameters: +// [out] pbData - Buffer to write into. +// [in] eMechOID - OID to put in MechList. +// +// Returns: +// int Number of bytes written out +// +// Comments : +// Helper function to write out a MechList. A MechList consists of the +// Init Token Sequence, a sequence token and then the list of OIDs. In +// our case the OID is from a global array of known OIDs. +// +//////////////////////////////////////////////////////////////////////////// + +long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid ) +{ + // First get the length + long nInternalLength = 0L; + long nMechListLength = ASNDerCalcMechListLength( mechoid, &nInternalLength ); + long nTempLength = 0L; + + nTempLength = ASNDerWriteToken( pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES, + NULL, nInternalLength ); + + // Adjust the data pointer + pbData += nTempLength; + + // Now write the Sequence token and the OID (the OID is a BLOB in the global + // structure. + + nTempLength = ASNDerWriteToken( pbData, SPNEGO_CONSTRUCTED_SEQUENCE, + g_stcMechOIDList[mechoid].ucOid, + g_stcMechOIDList[mechoid].iLen ); + + return nMechListLength; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ASNDerWriteElement +// +// Parameters: +// [out] pbData - Buffer to write into. +// [in] ucElementSequence - Sequence Token +// [in] ucType - Token Type +// [in] pbTokenValue - Actual Value +// [in] nLength - Length of Data. +// +// Returns: +// int Number of bytes written out +// +// Comments : +// Helper function to write out a SPNEGO Token element. An element +// consists of a sequence token, a type token and the associated data. +// +//////////////////////////////////////////////////////////////////////////// + +int ASNDerWriteElement( unsigned char* pbData, unsigned char ucElementSequence, + unsigned char ucType, unsigned char* pbTokenValue, long nLength ) +{ + // First get the length + long nInternalLength = 0L; + long nElementLength = ASNDerCalcElementLength( nLength, &nInternalLength ); + long nTempLength = 0L; + + // Write out the sequence byte and the length of the type and data + nTempLength = ASNDerWriteToken( pbData, ucElementSequence, NULL, nInternalLength ); + + // Adjust the data pointer + pbData += nTempLength; + + // Now write the type and the data. + nTempLength = ASNDerWriteToken( pbData, ucType, pbTokenValue, nLength ); + + return nElementLength; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/derparse.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,196 @@ +// Copyright (C) 2002 Microsoft Corporation +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" +// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +// OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY +// AND/OR FITNESS FOR A PARTICULAR PURPOSE. +// +// Date - 10/08/2002 +// Author - Sanj Surati + +///////////////////////////////////////////////////////////// +// +// DERPARSE.H +// +// SPNEGO Token Handler Header File +// +// Contains the definitions required to properly parse the +// SPNEGO DER encoding. +// +///////////////////////////////////////////////////////////// + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef __DERPARSE_H__ +#define __DERPARSE_H__ + +// C++ Specific +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* Identifier Types */ +#define IDENTIFIER_MASK 0xC0 // Bits 7 and 8 +#define IDENTIFIER_UNIVERSAL 0x00 // 00 = universal +#define IDENTIFIER_APPLICATION 0x40 // 01 = application +#define IDENTIFIER_CONTEXT_SPECIFIC 0x80 // 10 = context specific +#define IDENTIFIER_PRIVATE 0xC0 // 11 = Private + +/* Encoding type */ + +#define FORM_MASK 0x20 /* Bit 6 */ +#define PRIMITIVE 0x00 /* 0 = primitive */ +#define CONSTRUCTED 0x20 /* 1 = constructed */ + +/* Universal tags */ + +#define TAG_MASK 0x1F /* Bits 5 - 1 */ +#define BOOLEAN 0x01 /* 1: TRUE or FALSE */ +#define INTEGER 0x02 /* 2: Arbitrary precision integer */ +#define BITSTRING 0x03 /* 2: Sequence of bits */ +#define OCTETSTRING 0x04 /* 4: Sequence of bytes */ +#define NULLTAG 0x05 /* 5: NULL */ +#define OID 0x06 /* 6: Object Identifier (numeric sequence) */ +#define OBJDESCRIPTOR 0x07 /* 7: Object Descriptor (human readable) */ +#define EXTERNAL 0x08 /* 8: External / Instance Of */ +#define REAL 0x09 /* 9: Real (Mantissa * Base^Exponent) */ +#define ENUMERATED 0x0A /* 10: Enumerated */ +#define EMBEDDED_PDV 0x0B /* 11: Embedded Presentation Data Value */ +#define SEQUENCE 0x10 /* 16: Constructed Sequence / Sequence Of */ +#define SET 0x11 /* 17: Constructed Set / Set Of */ +#define NUMERICSTR 0x12 /* 18: Numeric String (digits only) */ +#define PRINTABLESTR 0x13 /* 19: Printable String */ +#define T61STR 0x14 /* 20: T61 String (Teletex) */ +#define VIDEOTEXSTR 0x15 /* 21: Videotex String */ +#define IA5STR 0x16 /* 22: IA5 String */ +#define UTCTIME 0x17 /* 23: UTC Time */ +#define GENERALIZEDTIME 0x18 /* 24: Generalized Time */ +#define GRAPHICSTR 0x19 /* 25: Graphic String */ +#define VISIBLESTR 0x1A /* 26: Visible String (ISO 646) */ +#define GENERALSTR 0x1B /* 27: General String */ +#define UNIVERSALSTR 0x1C /* 28: Universal String */ +#define BMPSTR 0x1E /* 30: Basic Multilingual Plane String */ + +/* Length encoding */ + +#define LEN_XTND 0x80 /* Indefinite or long form */ +#define LEN_MASK 0x7f /* Bits 7 - 1 */ + +#define SEQ_ELM(n) (IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | ((n)&TAG_MASK)) + +// +// SPNEGO Token Parsing Constants +// + + +// Fixed Length of NegTokenInit ReqFlags field +#define SPNEGO_NEGINIT_MAXLEN_REQFLAGS 2 + +// Difference in bits for ReqFlags token +#define SPNEGO_NEGINIT_REQFLAGS_BITDIFF 1 + +// Fixed Length of NegTokenTarg NegResult field +#define SPNEGO_NEGTARG_MAXLEN_NEGRESULT 1 + +// Application Specific Construct - Always at the start of a NegTokenInit +#define SPNEGO_NEGINIT_APP_CONSTRUCT ( IDENTIFIER_APPLICATION | CONSTRUCTED ) // 0x60 + +// Constructed Sequence token - after the actual token identifier token +#define SPNEGO_CONSTRUCTED_SEQUENCE ( SEQUENCE | CONSTRUCTED ) + +// MechList Type Identifier +#define SPNEGO_MECHLIST_TYPE ( SEQUENCE | CONSTRUCTED | OID ) + +// +// NegTokenInit - Token Identifier and Elements +// + +// NegTokenInit - 0xa0 +#define SPNEGO_NEGINIT_TOKEN_IDENTIFIER ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \ + SPNEGO_TOKEN_INIT ) + +// Structure elements for NegTokenInit +#define SPNEGO_NEGINIT_MECHTYPES 0x0 // MechTypes is element 0 +#define SPNEGO_NEGINIT_REQFLAGS 0x1 // ReqFlags is element 1 +#define SPNEGO_NEGINIT_MECHTOKEN 0x2 // MechToken is element 2 +#define SPNEGO_NEGINIT_MECHLISTMIC 0x3 // MechListMIC is element 3 + +// MechTypes element is 0xa0 +#define SPNEGO_NEGINIT_ELEMENT_MECHTYPES SEQ_ELM(SPNEGO_NEGINIT_MECHTYPES) +// ReqFlags element is 0xa1 +#define SPNEGO_NEGINIT_ELEMENT_REQFLAGS SEQ_ELM(SPNEGO_NEGINIT_REQFLAGS) +// MechToken element is 0xa2 +#define SPNEGO_NEGINIT_ELEMENT_MECHTOKEN SEQ_ELM(SPNEGO_NEGINIT_MECHTOKEN) +// MechListMIC element is 0xa3 +#define SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC SEQ_ELM(SPNEGO_NEGINIT_MECHLISTMIC) + +// +// NegTokenTarg - Token Identifier and Elements +// + +// NegTokenTarg - 0xa1 +#define SPNEGO_NEGTARG_TOKEN_IDENTIFIER ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | \ + SPNEGO_TOKEN_TARG ) + +// Structure elements for NegTokenTarg +#define SPNEGO_NEGTARG_NEGRESULT 0x0 // NegResult is element 0 +#define SPNEGO_NEGTARG_SUPPORTEDMECH 0x1 // SupportedMech is element 1 +#define SPNEGO_NEGTARG_RESPONSETOKEN 0x2 // ResponseToken is element 2 +#define SPNEGO_NEGTARG_MECHLISTMIC 0x3 // MechListMIC is element 3 + +// NegResult element is 0xa0 +#define SPNEGO_NEGTARG_ELEMENT_NEGRESULT SEQ_ELM(SPNEGO_NEGTARG_NEGRESULT) +// SupportedMech element is 0xa1 +#define SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH SEQ_ELM(SPNEGO_NEGTARG_SUPPORTEDMECH) +// ResponseToken element is 0xa2 +#define SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN SEQ_ELM(SPNEGO_NEGTARG_RESPONSETOKEN) +// MechListMIC element is 0xa3 +#define SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC SEQ_ELM(SPNEGO_NEGTARG_MECHLISTMIC) + +// +// Defines a GSS Mechanism OID. We keep a single static array +// of these which we'll use for validation/searches/parsing. +// + +typedef struct _mechOID +{ + unsigned char* ucOid; // Byte representation of OID + int iLen; // Length of the OID, length and identifier + int iActualDataLen; // Length of the actual OID + SPNEGO_MECH_OID eMechanismOID; // Which OID is this? +} MECH_OID; + + +// +// ASN Der functions +// + +int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength, + long* pnNumLengthBytes ); +int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken, + long nCheckLength, long nBoundaryLength, long* pnLength, + long* pnTokenLength ); +int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength, + long* pnTokenLength ); +int ASNDerCalcNumLengthBytes( long nLength ); +long ASNDerCalcTokenLength( long nLength, long nDataLength ); +long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength ); +long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength ); +int ASNDerWriteLength( unsigned char* pbData, long nLength ); +int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType, + unsigned char* pbTokenValue, long nLength ); +int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID ); +long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid ); +int ASNDerWriteElement( unsigned char* pbData, unsigned char ucElementSequence, + unsigned char ucType, unsigned char* pbTokenValue, long nLength ); + + + // C++ Specific +#if defined(__cplusplus) +} +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/file.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: file.c,v 1.4 2004/12/13 00:25:21 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/mount.h> +#include <fcntl.h> +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <pwd.h> +#include <grp.h> +#include <unistd.h> + +#include <sys/types.h> +extern uid_t real_uid, eff_uid; + +#include <netsmb/smb_lib.h> +#include <cflib.h> + +int +smb_read(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count, char *dst) +{ + struct smbioc_rw rwrq; + + bzero(&rwrq, sizeof (rwrq)); + rwrq.ioc_fh = fh; + rwrq.ioc_base = dst; + rwrq.ioc_cnt = count; + rwrq.ioc_offset = offset; + seteuid(eff_uid); + if (ioctl(ctx->ct_fd, SMBIOC_READ, &rwrq) == -1) { + seteuid(real_uid); /* and back to real user */ + return (-1); + } + seteuid(real_uid); /* and back to real user */ + return (rwrq.ioc_cnt); +} + +int +smb_write(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count, + const char *src) +{ + struct smbioc_rw rwrq; + + bzero(&rwrq, sizeof (rwrq)); + rwrq.ioc_fh = fh; + rwrq.ioc_base = (char *)src; + rwrq.ioc_cnt = count; + rwrq.ioc_offset = offset; + seteuid(eff_uid); + if (ioctl(ctx->ct_fd, SMBIOC_WRITE, &rwrq) == -1) { + seteuid(real_uid); /* and back to real user */ + return (-1); + } + seteuid(real_uid); /* and back to real user */ + return (rwrq.ioc_cnt); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/keychain.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,199 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * External interface to the libsmbfs/netsmb keychain + * storage mechanism. This interface is consumed by + * the "smbutil" commands: login, logout, ... + * and by the SMBFS PAM module. + */ + +#include <sys/types.h> + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <libintl.h> + +#include <netsmb/smb_dev.h> +#include <netsmb/smb_lib.h> +#include <netsmb/smb_keychain.h> + +#include <cflib.h> + +/* common func. for add/del/chk */ +static int +smbfs_keychain_cmn( + int cmd, + uid_t uid, + const char *dom, + const char *usr, + const char *pass) +{ + smbioc_pk_t pk; + int err, fd; + + memset(&pk, 0, sizeof (pk)); + + pk.pk_uid = uid; + + switch (cmd) { + + case SMBIOC_PK_ADD: + if (pass == NULL) + return (SMB_KEYCHAIN_BADPASSWD); + if (strlcpy(pk.pk_pass, pass, sizeof (pk.pk_pass)) >= + sizeof (pk.pk_pass)) + return (SMB_KEYCHAIN_BADPASSWD); + /* FALLTHROUGH */ + + case SMBIOC_PK_CHK: + case SMBIOC_PK_DEL: + if (dom == NULL) + return (SMB_KEYCHAIN_BADDOMAIN); + if (strlcpy(pk.pk_dom, dom, sizeof (pk.pk_dom)) >= + sizeof (pk.pk_dom)) + return (SMB_KEYCHAIN_BADDOMAIN); + if (usr == NULL) + return (SMB_KEYCHAIN_BADUSER); + if (strlcpy(pk.pk_usr, usr, sizeof (pk.pk_usr)) >= + sizeof (pk.pk_usr)) + return (SMB_KEYCHAIN_BADUSER); + break; + + case SMBIOC_PK_DEL_OWNER: /* all owned by the caller */ + case SMBIOC_PK_DEL_EVERYONE: /* all owned by everyone */ + /* + * These two do not copyin any args, but we'll + * pass &pk here anyway just so we can use the + * common code path below. + */ + break; + + default: + return (SMB_KEYCHAIN_UNKNOWN); + } + + fd = smb_open_driver(); + if (fd < 0) { + err = SMB_KEYCHAIN_NODRIVER; + goto out; + } + + err = 0; + if (ioctl(fd, cmd, &pk) < 0) + err = errno; + + close(fd); +out: + memset(&pk, 0, sizeof (pk)); + return (err); +} + +/* Add a password to the keychain. */ +int +smbfs_keychain_add(uid_t uid, const char *dom, const char *usr, + const char *pass) +{ + return (smbfs_keychain_cmn(SMBIOC_PK_ADD, uid, dom, usr, pass)); +} + +/* Delete a password from the keychain. */ +int +smbfs_keychain_del(uid_t uid, const char *dom, const char *usr) +{ + return (smbfs_keychain_cmn(SMBIOC_PK_DEL, uid, dom, usr, NULL)); +} + +/* + * Check for existence of a keychain entry. + * Returns 0 if it exists, else ENOENT. + */ +int +smbfs_keychain_chk(const char *dom, const char *usr) +{ + return (smbfs_keychain_cmn(SMBIOC_PK_CHK, (uid_t)-1, dom, usr, NULL)); +} + +/* + * Delete all keychain entries owned by the caller. + */ +int +smbfs_keychain_del_owner() +{ + return (smbfs_keychain_cmn(SMBIOC_PK_DEL_OWNER, getuid(), 0, 0, 0)); +} + +/* + * Delete all keychain entries (regardless of onwer). + * Requires super-user privliege. + */ +int +smbfs_keychain_del_everyone() +{ + return (smbfs_keychain_cmn(SMBIOC_PK_DEL_EVERYONE, getuid(), 0, 0, 0)); +} + + +/* + * This is not really part of the keychain library, + * but is typically needed in code that wants to + * provide (editable) defaults for domain/user + * + * Get default domain and user names + * Server name is optional. + */ +int +smbfs_default_dom_usr(const char *home, const char *server, + char *dom, int maxdom, char *usr, int maxusr) +{ + struct smb_ctx sctx, *ctx = &sctx; + int err; + + err = smb_ctx_init(ctx, 0, NULL, SMBL_VC, SMBL_VC, SMB_ST_ANY); + if (err) + return (err); + if (server) + smb_ctx_setserver(ctx, server); + if (home && *home) + ctx->ct_home = (char *)home; + err = smb_ctx_readrc(ctx); + if (err) + return (err); + if (smb_rc) + rc_close(smb_rc); + + if (dom) + strlcpy(dom, ctx->ct_ssn.ioc_workgroup, maxdom); + + if (usr) + strlcpy(usr, ctx->ct_ssn.ioc_user, maxusr); + + return (0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/llib-lsmbfs Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,32 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/*LINTLIBRARY*/ +/*PROTOLIB1*/ + +#include <netsmb/smb_lib.h>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/mapfile-vers Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,72 @@ +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate_1.0 { + global: + dropsuid; + nb_ctx_create; + nb_ctx_done; + nb_ctx_readrcsection; + nb_ctx_resolve; + nb_ctx_setns; + nb_resolvehost_in; + nbns_getnodestatus; + nbns_resolvename; + nls_str_upper; + rc_close; + rc_open; + smb_ctx_done; + smb_ctx_flags2; + smb_ctx_init; + smb_ctx_lookup; + smb_ctx_opt; + smb_ctx_readrc; + smb_ctx_resolve; + smb_ctx_setshare; + smb_ctx_tdis; + smb_debug; + smb_error; + smb_getprogname; + smb_lib_init; + smb_netshareenum; + smb_open_rcfile; + smb_simplecrypt; + smb_simpledecrypt; + smb_strerror; + smb_rc; # data + smb_read; + smb_write; + smb_verbose; + smbfs_default_dom_usr; + smbfs_keychain_add; + smbfs_keychain_chk; + smbfs_keychain_del; + smbfs_keychain_del_everyone; + smbfs_keychain_del_owner; + unpercent; + local: + *; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/mbuf.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2000, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: mbuf.c,v 1.3 2004/12/13 00:25:22 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <libintl.h> + +#include <netsmb/smb.h> +#include <netsmb/smb_lib.h> +#include <netsmb/mchain.h> + +#ifdef APPLE +#define __func__ "" +#define MBERROR(format, args...) \ + printf("%s(%d): "format, __func__, __LINE__, ## args) +#endif + +static int +m_get(size_t len, struct mbuf **mpp) +{ + struct mbuf *m; + + len = M_ALIGN(len); + if (len < M_MINSIZE) + len = M_MINSIZE; + m = malloc(M_BASESIZE + len); + if (m == NULL) + return (ENOMEM); + bzero(m, M_BASESIZE + len); + m->m_maxlen = len; + m->m_data = M_TOP(m); + *mpp = m; + return (0); +} + +static void +m_free(struct mbuf *m) +{ + free(m); +} + +static void +m_freem(struct mbuf *m0) +{ + struct mbuf *m; + + while (m0) { + m = m0->m_next; + m_free(m0); + m0 = m; + } +} + +static size_t +m_totlen(struct mbuf *m0) +{ + struct mbuf *m = m0; + int len = 0; + + while (m) { + len += m->m_len; + m = m->m_next; + } + return (len); +} + +int +m_lineup(struct mbuf *m0, struct mbuf **mpp) +{ + struct mbuf *nm, *m; + char *dp; + size_t len; + int error; + + if (m0->m_next == NULL) { + *mpp = m0; + return (0); + } + if ((error = m_get(m_totlen(m0), &nm)) != 0) + return (error); + dp = mtod(nm, char *); + while (m0) { + len = m0->m_len; + bcopy(m0->m_data, dp, len); + dp += len; + m = m0->m_next; + m_free(m0); + m0 = m; + } + *mpp = nm; + return (0); +} + +int +mb_init(struct mbdata *mbp, size_t size) +{ + struct mbuf *m; + int error; + + if ((error = m_get(size, &m)) != 0) + return (error); + return (mb_initm(mbp, m)); +} + +int +mb_initm(struct mbdata *mbp, struct mbuf *m) +{ + bzero(mbp, sizeof (*mbp)); + mbp->mb_top = mbp->mb_cur = m; + mbp->mb_pos = mtod(m, char *); + return (0); +} + +int +mb_done(struct mbdata *mbp) +{ + if (mbp->mb_top) { + m_freem(mbp->mb_top); + mbp->mb_top = NULL; + } + return (0); +} + +int +m_getm(struct mbuf *top, size_t len, struct mbuf **mpp) +{ + struct mbuf *m, *mp; + int error; + + for (mp = top; ; mp = mp->m_next) { + len -= M_TRAILINGSPACE(mp); + if (mp->m_next == NULL) + break; + + } + if (len > 0) { + if ((error = m_get(len, &m)) != 0) + return (error); + mp->m_next = m; + } + *mpp = top; + return (0); +} + +/* + * Routines to put data in a buffer + */ +#define MB_PUT(t) int error; t *p; \ + if ((error = mb_fit(mbp, sizeof (t), (char **)&p)) != 0) \ + return (error) + +/* + * Check if object of size 'size' fit to the current position and + * allocate new mbuf if not. Advance pointers and increase length of mbuf(s). + * Return pointer to the object placeholder or NULL if any error occured. + */ +int +mb_fit(struct mbdata *mbp, size_t size, char **pp) +{ + struct mbuf *m, *mn; + int error; + + m = mbp->mb_cur; + if (M_TRAILINGSPACE(m) < (int)size) { + if ((error = m_get(size, &mn)) != 0) + return (error); + mbp->mb_pos = mtod(mn, char *); + mbp->mb_cur = m->m_next = mn; + m = mn; + } + m->m_len += size; + *pp = mbp->mb_pos; + mbp->mb_pos += size; + mbp->mb_count += size; + return (0); +} + +int +mb_put_uint8(struct mbdata *mbp, uint8_t x) +{ + MB_PUT(uint8_t); + *p = x; + return (0); +} + +int +mb_put_uint16be(struct mbdata *mbp, uint16_t x) +{ + MB_PUT(uint16_t); + /* LINTED */ + setwbe(p, 0, x); + return (0); +} + +int +mb_put_uint16le(struct mbdata *mbp, uint16_t x) +{ + MB_PUT(uint16_t); + /* LINTED */ + setwle(p, 0, x); + return (0); +} + +int +mb_put_uint32be(struct mbdata *mbp, uint32_t x) +{ + MB_PUT(uint32_t); + /* LINTED */ + setdbe(p, 0, x); + return (0); +} + +int +mb_put_uint32le(struct mbdata *mbp, uint32_t x) +{ + MB_PUT(uint32_t); + /* LINTED */ + setdle(p, 0, x); + return (0); +} + +int +mb_put_uint64be(struct mbdata *mbp, uint64_t x) +{ + MB_PUT(uint64_t); + *p = htobeq(x); + return (0); +} + +int +mb_put_uint64le(struct mbdata *mbp, uint64_t x) +{ + MB_PUT(uint64_t); + *p = htoleq(x); + return (0); +} + +int +mb_put_mem(struct mbdata *mbp, const char *source, size_t size) +{ + struct mbuf *m; + char *dst; + size_t cplen; + int error; + + if (size == 0) + return (0); + m = mbp->mb_cur; + if ((error = m_getm(m, size, &m)) != 0) + return (error); + while (size > 0) { + cplen = M_TRAILINGSPACE(m); + if (cplen == 0) { + m = m->m_next; + continue; + } + if (cplen > size) + cplen = size; + dst = mtod(m, char *) + m->m_len; + if (source) { + bcopy(source, dst, cplen); + source += cplen; + } else + bzero(dst, cplen); + size -= cplen; + m->m_len += cplen; + mbp->mb_count += cplen; + } + mbp->mb_pos = mtod(m, char *) + m->m_len; + mbp->mb_cur = m; + return (0); +} + +int +mb_put_mbuf(struct mbdata *mbp, struct mbuf *m) +{ + mbp->mb_cur->m_next = m; + while (m) { + mbp->mb_count += m->m_len; + if (m->m_next == NULL) + break; + m = m->m_next; + } + mbp->mb_pos = mtod(m, char *) + m->m_len; + mbp->mb_cur = m; + return (0); +} + +int +mb_put_pstring(struct mbdata *mbp, const char *s) +{ + int error, len = strlen(s); + + if (len > 255) { + len = 255; + } + if ((error = mb_put_uint8(mbp, len)) != 0) + return (error); + return (mb_put_mem(mbp, s, len)); +} + +/* + * Routines for fetching data from an mbuf chain + */ +#define mb_left(m, p) (mtod(m, char *) + (m)->m_len - (p)) + +int +mb_get_uint8(struct mbdata *mbp, uint8_t *x) +{ + return (mb_get_mem(mbp, (char *)x, 1)); +} + +int +mb_get_uint16(struct mbdata *mbp, uint16_t *x) +{ + return (mb_get_mem(mbp, (char *)x, 2)); +} + +int +mb_get_uint16le(struct mbdata *mbp, uint16_t *x) +{ + uint16_t v; + int error = mb_get_uint16(mbp, &v); + + if (x != NULL) + *x = letohs(v); + return (error); +} + +int +mb_get_uint16be(struct mbdata *mbp, uint16_t *x) { + uint16_t v; + int error = mb_get_uint16(mbp, &v); + + if (x != NULL) + *x = betohs(v); + return (error); +} + +int +mb_get_uint32(struct mbdata *mbp, uint32_t *x) +{ + return (mb_get_mem(mbp, (char *)x, 4)); +} + +int +mb_get_uint32be(struct mbdata *mbp, uint32_t *x) +{ + uint32_t v; + int error; + + error = mb_get_uint32(mbp, &v); + if (x != NULL) + *x = betohl(v); + return (error); +} + +int +mb_get_uint32le(struct mbdata *mbp, uint32_t *x) +{ + uint32_t v; + int error; + + error = mb_get_uint32(mbp, &v); + if (x != NULL) + *x = letohl(v); + return (error); +} + +int +mb_get_uint64(struct mbdata *mbp, uint64_t *x) +{ + return (mb_get_mem(mbp, (char *)x, 8)); +} + +int +mb_get_uint64be(struct mbdata *mbp, uint64_t *x) +{ + uint64_t v; + int error; + + error = mb_get_uint64(mbp, &v); + if (x != NULL) + *x = betohq(v); + return (error); +} + +int +mb_get_uint64le(struct mbdata *mbp, uint64_t *x) +{ + uint64_t v; + int error; + + error = mb_get_uint64(mbp, &v); + if (x != NULL) + *x = letohq(v); + return (error); +} + +int +mb_get_mem(struct mbdata *mbp, char *target, size_t size) +{ + struct mbuf *m = mbp->mb_cur; + uint_t count; + + while (size > 0) { + if (m == NULL) { +#ifdef DEBUG + printf( + dgettext(TEXT_DOMAIN, "incomplete copy\n")); +#endif +#ifdef APPLE + MBERROR("incomplete copy\n"); +#endif + return (EBADRPC); + } + count = mb_left(m, mbp->mb_pos); + if (count == 0) { + mbp->mb_cur = m = m->m_next; + if (m) + mbp->mb_pos = mtod(m, char *); + continue; + } + if (count > size) + count = size; + size -= count; + if (target) { + if (count == 1) { + *target++ = *mbp->mb_pos; + } else { + bcopy(mbp->mb_pos, target, count); + target += count; + } + } + mbp->mb_pos += count; + } + return (0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/nb.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2000, 2001 Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: nb.c,v 1.1.1.2 2001/07/06 22:38:42 conrad Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/socket.h> + +#include <ctype.h> +#include <netdb.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <stdio.h> +#include <unistd.h> +#include <libintl.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <netsmb/netbios.h> +#include <netsmb/smb_lib.h> +#include <netsmb/nb_lib.h> + +#include <cflib.h> + +int +nb_ctx_create(struct nb_ctx **ctxpp) +{ + struct nb_ctx *ctx; + + ctx = malloc(sizeof (struct nb_ctx)); + if (ctx == NULL) + return (ENOMEM); + bzero(ctx, sizeof (struct nb_ctx)); + ctx->nb_flags = NBCF_NS_ENABLE | NBCF_BC_ENABLE; + *ctxpp = ctx; + return (0); +} + +void +nb_ctx_done(struct nb_ctx *ctx) +{ + if (ctx == NULL) + return; + if (ctx->nb_scope) + free(ctx->nb_scope); + if (ctx) + free(ctx); +} + +static int +nb_ctx_setwins(in_addr_t *ina_p, const char *str) +{ + struct in_addr ina; + struct sockaddr *sap; + int error; + + if (str == NULL || str[0] == 0) + return (EINVAL); + + if (inet_aton(str, &ina)) { + *ina_p = ina.s_addr; + } else { + error = nb_resolvehost_in(str, &sap); + if (error) { + smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"), + error, str); + return (error); + } + if (sap->sa_family != AF_INET) { + smb_error(dgettext(TEXT_DOMAIN, + "unsupported address family %d"), 0, + sap->sa_family); + return (EINVAL); + } + /*LINTED*/ + *ina_p = ((struct sockaddr_in *)sap)->sin_addr.s_addr; + free(sap); + } + + return (0); +} + +/* + * This is called by "smbutil lookup" to handle the + * "-w wins_server" option. Let the semantics of + * this option be: Use specified WINS server only. + * If specified server is the broadcast address, + * set broadcast mode (and no WINS servers). + */ +int +nb_ctx_setns(struct nb_ctx *ctx, const char *addr) +{ + int error; + + error = nb_ctx_setwins(&ctx->nb_wins1, addr); + if (error) + return (error); + ctx->nb_wins2 = 0; + + /* Deal with explicit request for broadcast. */ + if (ctx->nb_wins1 == INADDR_BROADCAST) { + ctx->nb_wins1 = 0; + ctx->nb_flags |= NBCF_BC_ENABLE; + } + return (0); +} + +int +nb_ctx_setscope(struct nb_ctx *ctx, const char *scope) +{ + size_t slen = strlen(scope); + + if (slen >= 128) { + smb_error(dgettext(TEXT_DOMAIN, + "scope '%s' is too long"), 0, scope); + return (ENAMETOOLONG); + } + if (ctx->nb_scope) + free(ctx->nb_scope); + ctx->nb_scope = malloc(slen + 1); + if (ctx->nb_scope == NULL) + return (ENOMEM); + nls_str_upper(ctx->nb_scope, scope); + return (0); +} + +/* + * Now get the WINS server IP addresses directly + * when reading the RC files, so no longer need to + * lookup any names here. + */ +int +nb_ctx_resolve(struct nb_ctx *ctx) +{ + ctx->nb_flags |= NBCF_RESOLVED; + return (0); +} + +/* + * used level values: + * 0 - default + * 1 - server + * + * All of these are normally system-wide settings; + * the checks are in rc_parse() in rcfile.c. + */ +int +nb_ctx_readrcsection(struct rcfile *rcfile, struct nb_ctx *ctx, + const char *sname, int level) +{ + char *p; + int error; + int nbns_enable; + int nbns_broadcast; + + if (level > 1) + return (EINVAL); +#ifdef NOT_DEFINED + rc_getint(rcfile, sname, "nbtimeout", &ctx->nb_timo); + rc_getstringptr(rcfile, sname, "nbscope", &p); + if (p) + nb_ctx_setscope(ctx, p); +#endif + /* "nbns" will be "wins1" some day, and we'll have a "wins2" also */ + rc_getstringptr(rcfile, sname, "nbns", &p); + if (p) { + error = nb_ctx_setwins(&ctx->nb_wins1, p); + if (error) { + smb_error(dgettext(TEXT_DOMAIN, + "invalid address specified in the section %s"), + 0, sname); + return (error); + } + } + error = rc_getbool(rcfile, sname, "nbns_enable", &nbns_enable); + if (error == 0 && nbns_enable == 0) + ctx->nb_flags &= ~NBCF_NS_ENABLE; + error = rc_getbool(rcfile, sname, "nbns_broadcast", &nbns_broadcast); + if (error == 0 && nbns_broadcast == 0) + ctx->nb_flags &= ~NBCF_BC_ENABLE; + return (0); +} + +#ifdef I18N /* never defined, permits xgettext(1) to pick out strings */ +static const char *nb_err_rcode[] = { + gettext("bad request/response format"), + gettext("NBNS server failure"), + gettext("no such name"), + gettext("unsupported request"), + gettext("request rejected"), + gettext("name already registered)" +}; + +static const char *nb_err[] = { + gettext("host not found"), + gettext("too many redirects"), + gettext("invalid response"), + gettext("NETBIOS name too long"), + gettext("no interface to broadcast on and no NBNS server specified") +}; +#else +static const char *nb_err_rcode[] = { + "bad request/response format", + "NBNS server failure", + "no such name", + "unsupported request", + "request rejected", + "name already registered" +}; + +static const char *nb_err[] = { + "host not found", + "too many redirects", + "invalid response", + "NETBIOS name too long", + "no interface to broadcast on and no NBNS server specified" +}; +#endif + +const char * +nb_strerror(int error) +{ + if (error == 0) + return (NULL); + if (error <= NBERR_ACTIVE) + return (nb_err_rcode[error - 1]); + else if (error >= NBERR_HOSTNOTFOUND && error < NBERR_MAX) + return (nb_err[error - NBERR_HOSTNOTFOUND]); + else + return (NULL); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/nb_name.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2000, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: nb_name.c,v 1.11 2004/12/11 05:23:59 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/socket.h> +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <libintl.h> +#include <assert.h> + +#include <netsmb/netbios.h> +#include <netsmb/smb_lib.h> +#include <netsmb/nb_lib.h> +#include <netsmb/mchain.h> + +int +nb_snballoc(int namelen, struct sockaddr_nb **dst) +{ + struct sockaddr_nb *snb; + int slen; + + slen = sizeof (struct sockaddr_nb); + snb = malloc(slen); + if (snb == NULL) + return (ENOMEM); + bzero(snb, slen); + snb->snb_family = AF_NETBIOS; + *dst = snb; + return (0); +} + +void +nb_snbfree(struct sockaddr *snb) +{ + free(snb); +} + +/* + * Create a full NETBIOS address + */ +int +nb_sockaddr(struct sockaddr *peer, struct nb_name *np, + struct sockaddr_nb **dst) + +{ + struct sockaddr_nb *snb; + struct sockaddr_in *sin; + struct hostent *hst; + int nmlen, error; + + if (peer && (peer->sa_family != AF_INET)) + return (EPROTONOSUPPORT); +#if NOT_DEFINED /* moved encoding into kernel */ + nmlen = nb_name_len(np); + if (nmlen < NB_ENCNAMELEN) + return (EINVAL); +#else + nmlen = NB_NAMELEN; +#endif + error = nb_snballoc(nmlen, &snb); + if (error) + return (error); + + /* + * Moved toupper() work to callers. + * + * Moved NetBIOS name encoding into the driver + * so we have readable names right up until the + * point where we marshall them in to a message. + * Just makes debugging easier. + */ +#if NOT_DEFINED + if (nmlen != nb_name_encode(np, snb->snb_name)) + printf(dgettext(TEXT_DOMAIN, + "a bug somewhere in the nb_name* code\n")); + /* XXX */ +#else + /* + * OK, nb_snballoc() did bzero, set snb_family. + * Hacks for "*" moved here from nb_name_encode(), + * but belongs where nn_name is filled in... + * XXX fix later + */ + if (strcmp(np->nn_name, "*") == 0) { + /* Star is special: No blanks, type, etc. */ + snb->snb_name[0] = '*'; + } else { + /* Normal name: pad with blanks, add type. */ + assert(NB_NAMELEN == 16); + snprintf(snb->snb_name, NB_NAMELEN, + "%-15.15s", np->nn_name); + snb->snb_name[15] = (char)np->nn_type; + } +#endif + + if (peer) { + /*LINTED*/ + sin = (struct sockaddr_in *)peer; + snb->snb_ipaddr = sin->sin_addr.s_addr; + } + *dst = snb; + return (0); +} + +int +nb_name_len(struct nb_name *np) +{ + char *name; + int len, sclen; + + len = 1 + NB_ENCNAMELEN; + if (np->nn_scope == NULL) + return (len + 1); + sclen = 0; + for (name = np->nn_scope; *name; name++) { + if (*name == '.') { + sclen = 0; + } else { + if (sclen < NB_MAXLABLEN) { + sclen++; + len++; + } + } + } + return (len + 1); +} + +int +nb_encname_len(const uchar_t *str) +{ + const uchar_t *cp = str; + int len, blen; + + if ((cp[0] & 0xc0) == 0xc0) + return (-1); /* first two bytes are offset to name */ + + len = 1; + for (;;) { + blen = *cp; + if (blen++ == 0) + break; + len += blen; + cp += blen; + } + return (len); +} + +int +nb_name_encode(struct nb_name *np, uchar_t *dst) +{ + char *name; + uchar_t *plen; + uchar_t ch, *cp = dst; + char *p, buf1[NB_NAMELEN+1]; + int i, lblen; + + /* + * XXX: I'd rather see this part moved into + * callers of this function, leaving just + * the pure NB encoding here. -GWR + */ + name = np->nn_name; + if (name[0] == '*') { + /* Star is special: No blanks, type, etc. */ + bzero(buf1, NB_NAMELEN); + buf1[0] = '*'; + } else { + /* Normal name: pad with blanks, add type. */ + assert(NB_NAMELEN == 16); + snprintf(buf1, NB_NAMELEN, + "%-15.15s", name); + buf1[15] = (char)np->nn_type; + } + name = buf1; + + /* + * Do the NetBIOS "first-level encoding" here. + * (RFC1002 explains this wierdness...) + * See similar code in kernel nsmb module: + * uts/common/fs/smbclnt/netsmb/smb_trantcp.c + * + * Here is what we marshall: + * uint8_t NAME_LENGTH (always 32) + * uint8_t ENCODED_NAME[32] + * uint8_t SCOPE_LENGTH + * Scope follows here, then another null. + */ + + /* NAME_LENGTH */ + *cp++ = (2 * NB_NAMELEN); + + /* ENCODED_NAME */ + for (i = 0; i < NB_NAMELEN; i++) { + ch = name[i]; + *cp++ = 'A' + ((ch >> 4) & 0xF); + *cp++ = 'A' + ((ch) & 0xF); + } + + /* + * NetBIOS "scope" sting encoding, + * a.k.a second-level encoding. + * See RFC1002 for the details. + * + * Note: plen points to the length byte at the + * start of each string. This keeps a pointer + * to the location and fills it in after the + * length of the string is determined. + */ +#if NOT_DEFINED /* XXX: not yet */ + if (np->nn_scope) { + plen = cp++; + *plen = 0; /* fill in later */ + lblen = 0; + for (p = np->nn_scope; ; p++) { + if (*p == '.' || *p == 0) { + *plen = lblen; + if (*p == 0) + break; + plen = cp++; + *plen = 0; + lblen = 0; + } else { + if (lblen < NB_MAXLABLEN) { + *cp++ = *p; + lblen++; + } + } + } + } else +#endif /* XXX: not yet */ + { + *cp++ = 0; + } + + return (cp - dst); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/nb_net.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2000, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: nb_net.c,v 1.8 2004/03/19 01:49:47 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/sockio.h> +#include <net/if.h> +#include <ctype.h> +#include <netdb.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <stdio.h> +#include <unistd.h> + +#include <err.h> + +#include <netsmb/netbios.h> +#include <netsmb/smb_lib.h> +#include <netsmb/nb_lib.h> + +int +nb_getlocalname(char *name, size_t maxlen) +{ + char buf[1024], *cp; + + if (gethostname(buf, sizeof (buf)) != 0) + return (errno); + cp = strchr(buf, '.'); + if (cp) + *cp = 0; + strlcpy(name, buf, maxlen); + return (0); +} + +int +nb_resolvehost_in(const char *name, struct sockaddr **dest) +{ + struct hostent *h; + struct sockaddr_in *sinp; + in_addr_t addr; + struct in_addr in; + int len; + char **p; + + + h = gethostbyname(name); + if (!h) { +#ifdef DEBUG + warnx("can't get server address `%s': ", name); +#endif + return (ENETDOWN); + } + if (h->h_addrtype != AF_INET) { +#ifdef DEBUG + warnx("address for `%s' is not in the AF_INET family", name); +#endif + return (EAFNOSUPPORT); + } + if (h->h_length != 4) { +#ifdef DEBUG + warnx("address for `%s' has invalid length", name); +#endif + return (EAFNOSUPPORT); + } + len = sizeof (struct sockaddr_in); + sinp = malloc(len); + if (sinp == NULL) + return (ENOMEM); + bzero(sinp, len); + /* + * There is no sin_len in sockaddr_in structure on Solaris. + * sinp->sin_len = len; + */ + sinp->sin_family = h->h_addrtype; + memcpy(&sinp->sin_addr.s_addr, *h->h_addr_list,\ + sizeof (sinp->sin_addr.s_addr)); + sinp->sin_port = htons(SMB_TCP_PORT); + *dest = (struct sockaddr *)sinp; + return (0); +} + +#ifdef NOT_DEFINED +int +nb_enum_if(struct nb_ifdesc **iflist) { + struct lifconf ifc; + struct lifreq *ifrqp; + struct nb_ifdesc *ifd; + struct in_addr iaddr, imask; + struct lifnum ifn; + char *ifrdata, *iname; + int s, rdlen, ifcnt, error, iflags, i; + + *iflist = NULL; + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s == -1) + return (errno); + + /* Get number of interfaces. */ + ifn.lifn_family = AF_INET; + ifn.lifn_flags = 0; + ifn.lifn_count = 0; + if (ioctl(s, SIOCGLIFNUM, &ifn) != 0) { + error = errno; + goto bad; + } + + rdlen = ifn.lifn_count * sizeof (struct lifreq); + ifrdata = malloc(rdlen); + if (ifrdata == NULL) { + error = ENOMEM; + goto bad; + } + ifc.lifc_flags = 0; + ifc.lifc_family = AF_INET; + ifc.lifc_len = rdlen; + ifc.lifc_buf = ifrdata; + if (ioctl(s, SIOCGLIFCONF, &ifc) != 0) { + error = errno; + goto bad; + } + ifrqp = ifc.lifc_req; + ifcnt = ifc.lifc_len / sizeof (struct lifreq); + error = 0; + for (i = 0; i < ifcnt; i++, ifrqp++) { + /* XXX for now, avoid IP6 broadcast performance costs */ + if (ifrqp->lifr_addr.ss_family != AF_INET) + continue; + if (ioctl(s, SIOCGLIFFLAGS, ifrqp) != 0) + continue; + iflags = ifrqp->lifr_flags; + if ((iflags & IFF_UP) == 0 || (iflags & IFF_BROADCAST) == 0) + continue; + + if (ioctl(s, SIOCGLIFADDR, ifrqp) != 0 || + ifrqp->lifr_addr.ss_family != AF_INET) { + continue; + } + iname = ifrqp->lifr_name; + if (strlen(iname) >= sizeof (ifd->id_name)) + continue; + iaddr = (*(struct sockaddr_in *)&ifrqp->lifr_addr).sin_addr; + + if (ioctl(s, SIOCGLIFNETMASK, ifrqp) != 0) + continue; + imask = ((struct sockaddr_in *)&ifrqp->lifr_addr)->sin_addr; + + ifd = malloc(sizeof (struct nb_ifdesc)); + if (ifd == NULL) + return (ENOMEM); + bzero(ifd, sizeof (struct nb_ifdesc)); + strcpy(ifd->id_name, iname); + ifd->id_flags = iflags; + ifd->id_addr = iaddr; + ifd->id_mask = imask; + ifd->id_next = *iflist; + *iflist = ifd; + } +bad: + free(ifrdata); + close(s); + return (error); +} + +/*ARGSUSED*/ +int +nbns_resolvename(const char *name, struct sockaddr **dest) +{ + printf("NetBIOS name resolver is not included in this distribution.\n"); + printf("Please use '-I' option to specify an IP address of server.\n"); + return (EHOSTUNREACH); +} + +int +nb_hostlookup(struct nb_name *np, const char *server, const char *hint, + struct sockaddr_nb **dst) +{ + struct sockaddr_nb *snb; + int error; + + error = nb_sockaddr(NULL, np, &snb); + if (error) + return (error); + do { + if (hint) { + error = nb_resolvehost_in(host, snb); + if (error) + break; + } else { + error = nb_resolvename(server); + } + } while (0); + if (!error) { + *dst = snb; + } else + nb_snbfree(snb); + return (error); +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/nbns_rq.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2000, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: nbns_rq.c,v 1.9 2005/02/24 02:04:38 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <ctype.h> +#include <netdb.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <stdio.h> +#include <unistd.h> +#include <libintl.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <tsol/label.h> + +#define NB_NEEDRESOLVER +#include <netsmb/netbios.h> +#include <netsmb/smb_lib.h> +#include <netsmb/nb_lib.h> +#include <netsmb/mchain.h> + +static int nbns_rq_create(int opcode, struct nb_ctx *ctx, + struct nbns_rq **rqpp); +static void nbns_rq_done(struct nbns_rq *rqp); +static int nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp); +static int nbns_rq_prepare(struct nbns_rq *rqp); +static int nbns_rq(struct nbns_rq *rqp); + +static struct nb_ifdesc *nb_iflist = NULL; + +int +nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp) +{ + struct nbns_rq *rqp; + struct nb_name nn; + struct nbns_rr rr; + struct sockaddr_in *dest; + int error, rdrcount, len; + + if (strlen(name) > NB_NAMELEN) + return (NBERROR(NBERR_NAMETOOLONG)); + error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp); + if (error) + return (error); + /* + * Pad the name with blanks, but + * leave the "type" byte NULL. + * nb_name_encode adds the type. + */ + bzero(&nn, sizeof (nn)); + snprintf(nn.nn_name, NB_NAMELEN, "%-15.15s", name); + nn.nn_type = NBT_SERVER; + nn.nn_scope = ctx->nb_scope; + rqp->nr_nmflags = NBNS_NMFLAG_RD; + rqp->nr_qdname = &nn; + rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB; + rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN; + rqp->nr_qdcount = 1; + rqp->nr_maxretry = 5; + + error = nbns_rq_prepare(rqp); + if (error) { + nbns_rq_done(rqp); + return (error); + } + rdrcount = NBNS_MAXREDIRECTS; + for (;;) { + error = nbns_rq(rqp); + if (error) + break; + if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) { + /* + * Not an authoritative answer. Query again + * using the NS address in the 2nd record. + */ + if (rdrcount-- == 0) { + error = NBERROR(NBERR_TOOMANYREDIRECTS); + break; + } + error = nbns_rq_getrr(rqp, &rr); + if (error) + break; + error = nbns_rq_getrr(rqp, &rr); + if (error) + break; + bcopy(rr.rr_data, &rqp->nr_dest, 4); + continue; + } + if (rqp->nr_rpancount == 0) { + error = NBERROR(NBERR_HOSTNOTFOUND); + break; + } + error = nbns_rq_getrr(rqp, &rr); + if (error) + break; + len = sizeof (struct sockaddr_in); + dest = malloc(len); + if (dest == NULL) + return (ENOMEM); + bzero(dest, len); + /* + * Solaris sockaddr_in doesn't have this field. + * dest->sin_len = len; + */ + dest->sin_family = AF_INET; + bcopy(rr.rr_data + 2, &dest->sin_addr.s_addr, 4); + dest->sin_port = htons(SMB_TCP_PORT); + *adpp = (struct sockaddr *)dest; + ctx->nb_lastns = rqp->nr_sender; + break; + } + nbns_rq_done(rqp); + return (error); +} + +static char * +smb_optstrncpy(char *d, char *s, unsigned maxlen) +{ + if (d && s) { + strncpy(d, s, maxlen); + d[maxlen] = (char)0; + } + return (d); +} + + +int +nbns_getnodestatus(struct sockaddr *targethost, + struct nb_ctx *ctx, char *system, char *workgroup) +{ + struct nbns_rq *rqp; + struct nbns_rr rr; + struct nb_name nn; + struct nbns_nr *nrp; + char nrtype; + char *cp, *retname = NULL; + struct sockaddr_in *dest; + unsigned char nrcount; + int error, rdrcount, i, foundserver = 0, foundgroup = 0; + + if (targethost->sa_family != AF_INET) + return (EINVAL); + error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp); + if (error) + return (error); + bzero(&nn, sizeof (nn)); + strcpy((char *)nn.nn_name, "*"); + nn.nn_scope = ctx->nb_scope; + nn.nn_type = NBT_WKSTA; + rqp->nr_nmflags = 0; + rqp->nr_qdname = &nn; + rqp->nr_qdtype = NBNS_QUESTION_TYPE_NBSTAT; + rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN; + rqp->nr_qdcount = 1; + rqp->nr_maxretry = 2; + + /* LINTED */ + dest = (struct sockaddr_in *)targethost; + rqp->nr_dest = dest->sin_addr; + + error = nbns_rq_prepare(rqp); + if (error) { + nbns_rq_done(rqp); + return (error); + } + + /* + * Darwin had a loop here, allowing redirect, etc. + * but we only handle point-to-point for node status. + */ + error = nbns_rq(rqp); + if (error) + goto out; + if (rqp->nr_rpancount == 0) { + error = NBERROR(NBERR_HOSTNOTFOUND); + goto out; + } + error = nbns_rq_getrr(rqp, &rr); + if (error) + goto out; + + /* Compiler didn't like cast on lvalue++ */ + nrcount = *((unsigned char *)rr.rr_data); + rr.rr_data++; + /* LINTED */ + for (i = 1, nrp = (struct nbns_nr *)rr.rr_data; + i <= nrcount; ++i, ++nrp) { + nrtype = nrp->ns_name[NB_NAMELEN-1]; + /* Terminate the string: */ + nrp->ns_name[NB_NAMELEN-1] = (char)0; + /* Strip off trailing spaces */ + for (cp = &nrp->ns_name[NB_NAMELEN-2]; + cp >= nrp->ns_name; --cp) { + if (*cp != (char)0x20) + break; + *cp = (char)0; + } + nrp->ns_flags = ntohs(nrp->ns_flags); + if (nrp->ns_flags & NBNS_GROUPFLG) { + if (!foundgroup || + (foundgroup != NBT_WKSTA+1 && + nrtype == NBT_WKSTA)) { + smb_optstrncpy(workgroup, nrp->ns_name, + SMB_MAXUSERNAMELEN); + foundgroup = nrtype+1; + } + } else { + /* + * Track at least ONE name, in case + * no server name is found + */ + retname = nrp->ns_name; + } + if (nrtype == NBT_SERVER) { + smb_optstrncpy(system, nrp->ns_name, + SMB_MAXSRVNAMELEN); + foundserver = 1; + } + } + if (!foundserver) + smb_optstrncpy(system, retname, SMB_MAXSRVNAMELEN); + ctx->nb_lastns = rqp->nr_sender; + +out: + nbns_rq_done(rqp); + return (error); +} + +int +nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp) +{ + struct nbns_rq *rqp; + static uint16_t trnid; + int error; + + if (trnid == 0) + trnid = getpid(); + rqp = malloc(sizeof (*rqp)); + if (rqp == NULL) + return (ENOMEM); + bzero(rqp, sizeof (*rqp)); + error = mb_init(&rqp->nr_rq, NBDG_MAXSIZE); + if (error) { + free(rqp); + return (error); + } + rqp->nr_opcode = opcode; + rqp->nr_nbd = ctx; + rqp->nr_trnid = trnid++; + *rqpp = rqp; + return (0); +} + +void +nbns_rq_done(struct nbns_rq *rqp) +{ + if (rqp == NULL) + return; + if (rqp->nr_fd >= 0) + close(rqp->nr_fd); + mb_done(&rqp->nr_rq); + mb_done(&rqp->nr_rp); + if (rqp->nr_if) + free(rqp->nr_if); + free(rqp); +} + +/* + * Extract resource record from the packet. Assume that there is only + * one mbuf. + */ +int +nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp) +{ + struct mbdata *mbp = &rqp->nr_rp; + uchar_t *cp; + int error, len; + + bzero(rrp, sizeof (*rrp)); + cp = (uchar_t *)mbp->mb_pos; + len = nb_encname_len(cp); + if (len < 1) + return (NBERROR(NBERR_INVALIDRESPONSE)); + rrp->rr_name = cp; + error = mb_get_mem(mbp, NULL, len); + if (error) + return (error); + mb_get_uint16be(mbp, &rrp->rr_type); + mb_get_uint16be(mbp, &rrp->rr_class); + mb_get_uint32be(mbp, &rrp->rr_ttl); + mb_get_uint16be(mbp, &rrp->rr_rdlength); + rrp->rr_data = (uchar_t *)mbp->mb_pos; + error = mb_get_mem(mbp, NULL, rrp->rr_rdlength); + return (error); +} + +int +nbns_rq_prepare(struct nbns_rq *rqp) +{ + struct nb_ctx *ctx = rqp->nr_nbd; + struct mbdata *mbp = &rqp->nr_rq; + uint16_t ofr; /* opcode, flags, rcode */ + uchar_t *cp; + int len, error; + + /* + * Replacing with one argument. + * error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE); + */ + error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE); + if (error) + return (error); + + /* + * When looked into the ethereal trace, 'nmblookup' command sets this + * flag. We will also set. + */ + mb_put_uint16be(mbp, rqp->nr_trnid); + ofr = ((rqp->nr_opcode & 0x1F) << 11) | + ((rqp->nr_nmflags & 0x7F) << 4); /* rcode=0 */ + mb_put_uint16be(mbp, ofr); + mb_put_uint16be(mbp, rqp->nr_qdcount); + mb_put_uint16be(mbp, rqp->nr_ancount); + mb_put_uint16be(mbp, rqp->nr_nscount); + mb_put_uint16be(mbp, rqp->nr_arcount); + if (rqp->nr_qdcount) { + if (rqp->nr_qdcount > 1) + return (EINVAL); + len = nb_name_len(rqp->nr_qdname); + error = mb_fit(mbp, len, (char **)&cp); + if (error) + return (error); + nb_name_encode(rqp->nr_qdname, cp); + mb_put_uint16be(mbp, rqp->nr_qdtype); + mb_put_uint16be(mbp, rqp->nr_qdclass); + } + m_lineup(mbp->mb_top, &mbp->mb_top); + if (ctx->nb_timo == 0) + ctx->nb_timo = 1; /* by default 1 second */ + return (0); +} + +static int +nbns_rq_recv(struct nbns_rq *rqp) +{ + struct mbdata *mbp = &rqp->nr_rp; + void *rpdata = mtod(mbp->mb_top, void *); + fd_set rd, wr, ex; + struct timeval tv; + struct sockaddr_in sender; + int s = rqp->nr_fd; + int n, len; + + FD_ZERO(&rd); + FD_ZERO(&wr); + FD_ZERO(&ex); + FD_SET(s, &rd); + + tv.tv_sec = rqp->nr_nbd->nb_timo; + tv.tv_usec = 0; + + n = select(s + 1, &rd, &wr, &ex, &tv); + if (n == -1) + return (-1); + if (n == 0) + return (ETIMEDOUT); + if (FD_ISSET(s, &rd) == 0) + return (ETIMEDOUT); + len = sizeof (sender); + n = recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0, + (struct sockaddr *)&sender, &len); + if (n < 0) + return (errno); + mbp->mb_top->m_len = mbp->mb_count = n; + rqp->nr_sender = sender; + return (0); +} + +static int +nbns_rq_opensocket(struct nbns_rq *rqp) +{ + struct sockaddr_in locaddr; + int opt = 1, s; + struct nb_ctx *ctx = rqp->nr_nbd; + + s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) + return (errno); + if (ctx->nb_flags & NBCF_BC_ENABLE) { + if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt, + sizeof (opt)) < 0) + return (errno); + } + if (is_system_labeled()) + (void) setsockopt(s, SOL_SOCKET, SO_MAC_EXEMPT, &opt, + sizeof (opt)); + bzero(&locaddr, sizeof (locaddr)); + locaddr.sin_family = AF_INET; + /* locaddr.sin_len = sizeof (locaddr); */ + if (bind(s, (struct sockaddr *)&locaddr, sizeof (locaddr)) < 0) + return (errno); + return (0); +} + +static int +nbns_rq_send(struct nbns_rq *rqp, in_addr_t ina) +{ + struct sockaddr_in dest; + struct mbdata *mbp = &rqp->nr_rq; + int s = rqp->nr_fd; + uint16_t ofr, ofr_save; /* opcode, nmflags, rcode */ + uint16_t *datap; + uint8_t nmflags; + int rc; + + bzero(&dest, sizeof (dest)); + dest.sin_family = AF_INET; + dest.sin_port = htons(NBNS_UDP_PORT); + dest.sin_addr.s_addr = ina; + + if (ina == INADDR_BROADCAST) { + /* Turn on the broadcast bit. */ + nmflags = rqp->nr_nmflags | NBNS_NMFLAG_BCAST; + /*LINTED*/ + datap = mtod(mbp->mb_top, uint16_t *); + ofr = ((rqp->nr_opcode & 0x1F) << 11) | + ((nmflags & 0x7F) << 4); /* rcode=0 */ + ofr_save = datap[1]; + datap[1] = htons(ofr); + } + + rc = sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0, + (struct sockaddr *)&dest, sizeof (dest)); + + if (ina == INADDR_BROADCAST) { + /* Turn the broadcast bit back off. */ + datap[1] = ofr_save; + } + + + if (rc < 0) + return (errno); + + return (0); +} + +int +nbns_rq(struct nbns_rq *rqp) +{ + struct nb_ctx *ctx = rqp->nr_nbd; + struct mbdata *mbp = &rqp->nr_rq; + uint16_t ofr, rpid; + uint8_t nmflags; + int error, tries, maxretry; + + error = nbns_rq_opensocket(rqp); + if (error) + return (error); + + maxretry = rqp->nr_maxretry; + for (tries = 0; tries < maxretry; tries++) { + + /* + * Minor hack: If nr_dest is set, send there only. + * Used by _getnodestatus, _resolvname redirects. + */ + if (rqp->nr_dest.s_addr) { + error = nbns_rq_send(rqp, rqp->nr_dest.s_addr); + if (error) { + smb_error(dgettext(TEXT_DOMAIN, + "nbns error %d sending to %s"), + 0, error, inet_ntoa(rqp->nr_dest)); + } + goto do_recv; + } + + if (ctx->nb_wins1) { + error = nbns_rq_send(rqp, ctx->nb_wins1); + if (error) { + smb_error(dgettext(TEXT_DOMAIN, + "nbns error %d sending to wins1"), + 0, error); + } + } + + if (ctx->nb_wins2 && (tries > 0)) { + error = nbns_rq_send(rqp, ctx->nb_wins2); + if (error) { + smb_error(dgettext(TEXT_DOMAIN, + "nbns error %d sending to wins2"), + 0, error); + } + } + + /* + * If broadcast is enabled, start broadcasting + * only after wins servers fail to respond, or + * immediately if no WINS servers configured. + */ + if ((ctx->nb_flags & NBCF_BC_ENABLE) && + ((tries > 1) || (ctx->nb_wins1 == 0))) { + error = nbns_rq_send(rqp, INADDR_BROADCAST); + if (error) { + smb_error(dgettext(TEXT_DOMAIN, + "nbns error %d sending broadcast"), + 0, error); + } + } + + /* + * Wait for responses from ANY of the above. + */ +do_recv: + error = nbns_rq_recv(rqp); + if (error == ETIMEDOUT) + continue; + if (error) { + smb_error(dgettext(TEXT_DOMAIN, + "nbns recv error %d"), + 0, error); + return (error); + } + + mbp = &rqp->nr_rp; + if (mbp->mb_count < 12) + return (NBERROR(NBERR_INVALIDRESPONSE)); + mb_get_uint16be(mbp, &rpid); + if (rpid != rqp->nr_trnid) + return (NBERROR(NBERR_INVALIDRESPONSE)); + break; + } + + mb_get_uint16be(mbp, &ofr); + rqp->nr_rpnmflags = (ofr >> 4) & 0x7F; + rqp->nr_rprcode = ofr & 0xf; + if (rqp->nr_rprcode) + return (NBERROR(rqp->nr_rprcode)); + mb_get_uint16be(mbp, &rpid); /* QDCOUNT */ + mb_get_uint16be(mbp, &rqp->nr_rpancount); + mb_get_uint16be(mbp, &rqp->nr_rpnscount); + mb_get_uint16be(mbp, &rqp->nr_rparcount); + return (0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/netshareenum.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* BEGIN CSTYLED */ +/* + * @(#)ui.c * + * (c) 2004 Apple Computer, Inc. All Rights Reserved + * + * + * netshareenum.c -- Routines for getting a list of share information + * from a server. + * + * MODIFICATION HISTORY: + * 27-Nov-2004 Guy Harris New today + */ +/* END CSTYLED */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> + +#include <netsmb/mchain.h> +#include <netsmb/smb_lib.h> +#include <netsmb/smb_rap.h> +#include <netsmb/smb_netshareenum.h> +#include "charsets.h" + +#if 0 /* XXX see below */ +#include <dce/exc_handling.h> +#include <attrb.h> +#include "srvsvc.h" +#endif + +/* + * Don't want RPC client-side code in here. + * It's good code; just doesn't belong here. + * + * The API provided by this library should be + * just files and pipes (and not much more). + * It MAY be useful to provide some of the + * RAP (remote API) functions functions like + * rap_netshareenum below... + * + * XXX: Not sure this file belongs here at all. + * smb_rap.h looks like a reasonable API + * for this library to export. + */ +#if 0 /* XXX */ + +static int +rpc_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp, + struct share_info **entries_listp) +{ + char ctx_string[2+16+1]; /* enough for 64-bit pointer, in hex */ + unsigned_char_p_t binding; + unsigned32 binding_status; + rpc_binding_handle_t binding_h; + int error, i, entries; + char *addrstr, *srvnamestr; + unsigned short *usrvnamestr; + unsigned32 level; + SHARE_ENUM_STRUCT share_info; + SHARE_INFO_1_CONTAINER share_info_1_container; + SHARE_INFO_1 *shares, *share; + unsigned32 total_entries; + unsigned32 status, free_status; + struct share_info *entry_list, *elp; + static EXCEPTION rpc_x_connect_rejected; + static int exceptions_initialized; + + sprintf(ctx_string, "%p", ctx); + rpc_string_binding_compose(NULL, "ncacn_np", ctx_string, + "srvsvc", NULL, &binding, &binding_status); + if (binding_status != rpc_s_ok) { + smb_error(dgettext(TEXT_DOMAIN, + "rpc_string_binding_compose failed with %d"), + 0, binding_status); + return (EINVAL); + } + rpc_binding_from_string_binding(binding, &binding_h, &status); + if (binding_status != rpc_s_ok) { + smb_error(dgettext(TEXT_DOMAIN, + "rpc_binding_from_string_binding failed with %d"), 0, + binding_status); + return (EINVAL); + } + level = 1; + share_info.share_union.level = 1; + share_info.share_union.tagged_union.share1 = &share_info_1_container; + share_info_1_container.share_count = 0; + share_info_1_container.shares = NULL; + /* + * Convert the server IP address to a string, and send that as + * the "server name" - that's what Windows appears to do, and + * that avoids problems with NetBIOS names containing + * non-ASCII characters. + */ + addrstr = inet_ntoa(ctx->ct_srvinaddr.sin_addr); + srvnamestr = malloc(strlen(addrstr) + 3); + if (srvnamestr == NULL) { + status = errno; + smb_error(dgettext(TEXT_DOMAIN, + "can't allocate string for server address"), status); + rpc_binding_free(&binding_h, &free_status); + return (status); + } + strcpy(srvnamestr, "\\\\"); + strcat(srvnamestr, addrstr); +#ifdef NOTYETDEFINED + usrvnamestr = convert_utf8_to_leunicode(srvnamestr); +#endif + usrvnamestr = srvnamestr; + if (usrvnamestr == NULL) { + smb_error(dgettext(TEXT_DOMAIN, + "can't convert string for server address to Unicode"), 0); + rpc_binding_free(&binding_h, &free_status); + return (EINVAL); + } + if (!exceptions_initialized) { + EXCEPTION_INIT(rpc_x_connect_rejected); + exc_set_status(&rpc_x_connect_rejected, rpc_s_connect_rejected); + exceptions_initialized = 1; + } + /* printf("Calling NetrShareEnum.."); XXX */ + TRY + status = NetrShareEnum(binding_h, usrvnamestr, &level, + &share_info, 4294967295U, &total_entries, NULL); + if (status != 0) + smb_error(dgettext(TEXT_DOMAIN, + "error from NetrShareEnum call: status = 0x%08x"), + 0, status); + /*CSTYLED*/ + CATCH (rpc_x_connect_rejected) + /* + * This is what we get if we can't open the pipe. + * That's a normal occurrence when we're talking + * to a system that (presumably) doesn't support + * DCE RPC on the server side, such as Windows 95/98/Me, + * so we don't log an error. + */ + /*CSTYLED*/ + status = ENOTSUP; + CATCH_ALL + /* + * XXX - should we handle some exceptions differently, + * returning different errors, and try RAP only for + * ENOTSUP? + */ + smb_error(dgettext(TEXT_DOMAIN, + "error from NetrShareEnum call: exception = %u"), + 0, THIS_CATCH->match.value); + status = ENOTSUP; + ENDTRY + rpc_binding_free(&binding_h, &free_status); + free(srvnamestr); + free(usrvnamestr); + if (status != 0) + return (ENOTSUP); + + /* + * XXX - if the IDL is correct, it's not clear whether the + * unmarshalling code will properly handle the case where + * a packet where "share_count" and the max count for the + * array of shares don't match; a valid DCE RPC implementation + * won't marshal something like that, but there's no guarantee + * that the server we're talking to has a valid implementation + * (which could be a *malicious* implementation!). + */ + entries = share_info.share_union.tagged_union.share1->share_count; + shares = share_info.share_union.tagged_union.share1->shares; + entry_list = calloc(entries, sizeof (struct share_info)); + if (entry_list == NULL) { + error = errno; + goto cleanup_and_return; + } + for (share = shares, elp = entry_list, i = 0; i < entries; + i++, share++) { + elp->type = share->shi1_type; +#ifdef NOTYETDEFINED + elp->netname = convert_unicode_to_utf8(share->shi1_share); +#endif + elp->netname = share->shi1_share; + if (elp->netname == NULL) + goto fail; +#ifdef NOTYETDEFINED + elp->remark = convert_unicode_to_utf8(share->shi1_remark); +#endif + elp->remark = share->shi1_remark; + if (elp->remark == NULL) + goto fail; + elp++; + } + *entriesp = entries; + *totalp = total_entries; + *entries_listp = entry_list; + error = 0; + goto cleanup_and_return; + +fail: + error = errno; + for (elp = entry_list, i = 0; i < entries; i++, elp++) { + /* + * elp->netname is set before elp->remark, so if + * elp->netname is null, elp->remark is also null. + * If either of them is null, we haven't done anything + * to any entries after this one. + */ + if (elp->netname == NULL) + break; + free(elp->netname); + if (elp->remark == NULL) + break; + free(elp->remark); + } + free(entry_list); + +cleanup_and_return: + for (share = shares, i = 0; i < entries; i++, share++) { + free(share->shi1_share); + free(share->shi1_remark); + } + free(shares); + /* + * XXX - "share1" should be a unique pointer, but we haven't + * changed the marshalling code to support non-full pointers + * in unions, so we leave it as a full pointer. + * + * That means that this might, or might not, be changed from + * pointing to "share_info_1_container" to pointing to a + * mallocated structure, according to the DCE RPC 1.1 IDL spec; + * we free it only if it's changed. + */ + if (share_info.share_union.tagged_union.share1 != + &share_info_1_container) + free(share_info.share_union.tagged_union.share1); + return (error); +} +#endif /* XXX */ + +static int +rap_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp, + struct share_info **entries_listp) +{ + int error, bufsize, i, entries, total, nreturned; + struct smb_share_info_1 *rpbuf, *ep; + struct share_info *entry_list, *elp; + char *cp; + int lbound, rbound; + + bufsize = 0xffe0; /* samba notes win2k bug for 65535 */ + rpbuf = malloc(bufsize); + if (rpbuf == NULL) + return (errno); + + error = smb_rap_NetShareEnum(ctx, 1, rpbuf, &bufsize, &entries, &total); + if (error && + error != (SMB_ERROR_MORE_DATA | SMB_RAP_ERROR)) { + free(rpbuf); + return (error); + } + entry_list = malloc(entries * sizeof (struct share_info)); + if (entry_list == NULL) { + error = errno; + free(rpbuf); + return (error); + } + lbound = entries * (sizeof (struct smb_share_info_1)); + rbound = bufsize; + for (ep = rpbuf, elp = entry_list, i = 0, nreturned = 0; i < entries; + i++, ep++) { + elp->type = letohs(ep->shi1_type); + ep->shi1_pad = '\0'; /* ensure null termination */ + elp->netname = strdup(ep->shi1_netname); +#ifdef NOTYETDEFINED + elp->netname = convert_wincs_to_utf8(ep->shi1_netname); +#endif + if (elp->netname == NULL) + continue; /* punt on this entry */ + /* + * Check for validity of offset. + */ + if (ep->shi1_remark >= lbound && ep->shi1_remark < rbound) { + cp = (char *)rpbuf + ep->shi1_remark; + elp->remark = cp; +#ifdef NOTYETDEFINED + elp->remark = nls_str_toloc(cp, cp); +#endif + } else + elp->remark = NULL; + elp++; + nreturned++; + } + *entriesp = nreturned; + *totalp = total; + *entries_listp = entry_list; + free(rpbuf); + return (0); +} + +/* + * First we try the RPC-based NetrShareEnum, and, if that fails, we fall + * back on the RAP-based NetShareEnum. + */ +int +smb_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp, + struct share_info **entry_listp) +{ + int error; + +#ifdef NOTYETDEFINED + /* + * Try getting a list of shares with the SRVSVC RPC service. + */ + error = rpc_netshareenum(ctx, entriesp, totalp, entry_listp); + if (error == 0) + return (0); +#endif + + /* + * OK, that didn't work - try RAP. + * XXX - do so only if it failed because we couldn't open + * the pipe? + */ + return (rap_netshareenum(ctx, entriesp, totalp, entry_listp)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/nls.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2000-2001, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: nls.c,v 1.10 2004/12/13 00:25:22 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <strings.h> +#include <stdlib.h> +#include <locale.h> +#include <errno.h> + +#include <netsmb/smb_lib.h> + +/* + * prototype iconv* functions + */ +typedef void *iconv_t; + +static size_t(*my_iconv)(iconv_t, const char **, size_t *, char **, size_t *); + +u_char nls_lower[256]; +u_char nls_upper[256]; + +static iconv_t nls_toext, nls_toloc; +static int iconv_loaded; + +int +nls_setlocale(const char *name) +{ + int i; + + if (setlocale(LC_CTYPE, name) == NULL) { + fprintf(stdout, dgettext(TEXT_DOMAIN, + "can't set locale '%s'\n"), name); + } + for (i = 0; i < 256; i++) { + nls_lower[i] = tolower(i); + nls_upper[i] = toupper(i); + } + return 0; +} + +int +nls_setrecode(const char *local, const char *external) +{ + return ENOENT; +} + +char * +nls_str_toloc(char *dst, const char *src) +{ + char *p = dst; + size_t inlen, outlen; + + if (!iconv_loaded) + return strcpy(dst, src); + + if (nls_toloc == (iconv_t)0) + return strcpy(dst, src); + inlen = outlen = strlen(src); + my_iconv(nls_toloc, NULL, NULL, &p, &outlen); + my_iconv(nls_toloc, &src, &inlen, &p, &outlen); + *p = 0; + return dst; +} + +char * +nls_str_toext(char *dst, const char *src) +{ + char *p = dst; + size_t inlen, outlen; + + if (!iconv_loaded) + return strcpy(dst, src); + + if (nls_toext == (iconv_t)0) + return strcpy(dst, src); + inlen = outlen = strlen(src); + my_iconv(nls_toext, NULL, NULL, &p, &outlen); + my_iconv(nls_toext, &src, &inlen, &p, &outlen); + *p = 0; + return dst; +} + +void * +nls_mem_toloc(void *dst, const void *src, int size) +{ + char *p = dst; + const char *s = src; + size_t inlen, outlen; + + if (!iconv_loaded) + return memcpy(dst, src, size); + + if (size == 0) + return NULL; + + if (nls_toloc == (iconv_t)0) + return memcpy(dst, src, size); + inlen = outlen = size; + my_iconv(nls_toloc, NULL, NULL, &p, &outlen); + my_iconv(nls_toloc, &s, &inlen, &p, &outlen); + return dst; +} + +void * +nls_mem_toext(void *dst, const void *src, int size) +{ + char *p = dst; + const char *s = src; + size_t inlen, outlen; + + if (size == 0) + return NULL; + + if (!iconv_loaded || nls_toext == (iconv_t)0) + return memcpy(dst, src, size); + + inlen = outlen = size; + my_iconv(nls_toext, NULL, NULL, &p, &outlen); + my_iconv(nls_toext, &s, &inlen, &p, &outlen); + return dst; +} + +char * +nls_str_upper(char *dst, const char *src) +{ + char *p = dst; + + while (*src) + *dst++ = toupper(*src++); + *dst = 0; + return p; +} + +char * +nls_str_lower(char *dst, const char *src) +{ + char *p = dst; + + while (*src) + *dst++ = tolower(*src++); + *dst = 0; + return p; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/print.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2000, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: print.c,v 1.1.1.3 2001/07/06 22:38:43 conrad Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/mount.h> +#include <fcntl.h> +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <pwd.h> +#include <grp.h> +#include <unistd.h> + +#include <netsmb/smb_lib.h> +#include <cflib.h> + +int +smb_smb_open_print_file(struct smb_ctx *ctx, int setuplen, int mode, + const char *ident, smbfh *fhp) +{ + struct smb_rq *rqp; + struct mbdata *mbp; + int error; + + error = smb_rq_init(ctx, SMB_COM_OPEN_PRINT_FILE, 2, &rqp); + if (error) + return (error); + mbp = smb_rq_getrequest(rqp); + mb_put_uint16le(mbp, setuplen); + mb_put_uint16le(mbp, mode); + smb_rq_wend(rqp); + mb_put_uint8(mbp, SMB_DT_ASCII); + smb_rq_dstring(mbp, ident); + error = smb_rq_simple(rqp); + if (!error) { + mbp = smb_rq_getreply(rqp); + mb_get_uint16(mbp, fhp); + } + smb_rq_done(rqp); + return (error); +} + +int +smb_smb_close_print_file(struct smb_ctx *ctx, smbfh fh) +{ + struct smb_rq *rqp; + struct mbdata *mbp; + int error; + + error = smb_rq_init(ctx, SMB_COM_CLOSE_PRINT_FILE, 0, &rqp); + if (error) + return (error); + mbp = smb_rq_getrequest(rqp); + mb_put_mem(mbp, (char *)&fh, 2); + smb_rq_wend(rqp); + error = smb_rq_simple(rqp); + smb_rq_done(rqp); + return (error); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/queue.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This file [used to define] five types of data structures: + * singly-linked lists, ... + * [ all other types of lists removed ] + * + * Using excerpts of FreeBSD 4.5 sys/queue.h here, + * but only temporarily, until rcfile.c is replaced + * by SMF integration code. + * + * Yes we also have queue.h in uts/common/fs/smbclnt + * but don't want to make that part of the exported + * interface to the user-level code. + */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/rap.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2000, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: rap.c,v 1.5 2004/12/13 00:25:23 lindak Exp $ + * + * This is very simple implementation of RAP protocol. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/stat.h> +#include <sys/isa_defs.h> + +#include <ctype.h> +#include <stdio.h> +#include <unistd.h> +#include <strings.h> +#include <stdlib.h> +#include <libintl.h> +#include <sysexits.h> + +#include <netsmb/mchain.h> +#include <netsmb/smb_lib.h> +#include <netsmb/smb_rap.h> + +static int +smb_rap_parserqparam(const char *s, char **next, int *rlen) +{ + char *np; + int len; + + switch (*s++) { + case 'L': + case 'T': + case 'W': + len = 2; + break; + case 'D': + case 'O': + len = 4; + break; + case 'b': + case 'F': + len = 1; + break; + case 'r': + case 's': + len = 0; + break; + default: + return (EINVAL); + } + if (isdigit(*s)) { + len *= strtoul(s, &np, 10); + s = np; + } + *rlen = len; + *(const char **)next = s; + return (0); +} + +static int +smb_rap_parserpparam(const char *s, char **next, int *rlen) +{ + char *np; + int len = 0; + + switch (*s++) { + case 'e': + case 'h': + len = 2; + break; + case 'i': + len = 4; + break; + case 'g': + len = 1; + break; + default: + return (EINVAL); + } + if (isdigit(*s)) { + len *= strtoul(s, &np, 10); + s = np; + } + *rlen = len; + *(const char **)next = s; + return (0); +} + +static int +smb_rap_parserpdata(const char *s, char **next, int *rlen) +{ + char *np; + int len; + + switch (*s++) { + case 'B': + len = 1; + break; + case 'W': + len = 2; + break; + case 'D': + case 'O': + case 'z': + len = 4; + break; + default: + return (EINVAL); + } + if (isdigit(*s)) { + len *= strtoul(s, &np, 10); + s = np; + } + *rlen = len; + *(const char **)next = s; + return (0); +} + +static int +smb_rap_rqparam_z(struct smb_rap *rap, const char *value) +{ + int len = strlen(value) + 1; + + bcopy(value, rap->r_npbuf, len); + rap->r_npbuf += len; + rap->r_plen += len; + return (0); +} + +/* + * Marshal RAP request parameters. + * Note: value is in host order. + */ +static int +smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, int value) +{ + char *p = rap->r_npbuf; + int len = 0; + uint_t uv = (uint_t)value; + + switch (ptype) { + case 'L': + case 'W': + /* LINTED */ + setwle(p, 0, uv); + len = 2; + break; + case 'D': + /* LINTED */ + setdle(p, 0, uv); + len = 4; + break; + case 'b': + memset(p, uv, plen); + len = plen; + default: + return (EINVAL); + } + rap->r_npbuf += len; + rap->r_plen += len; + return (0); +} + +int +smb_rap_create(int fn, const char *param, const char *data, + struct smb_rap **rapp) +{ + struct smb_rap *rap; + char *p; + int plen = 0, len = 0; + int i; + + rap = malloc(sizeof (*rap)); + if (rap == NULL) + return (ENOMEM); + bzero(rap, sizeof (*rap)); + p = rap->r_sparam = rap->r_nparam = strdup(param); + rap->r_sdata = rap->r_ndata = strdup(data); + + /* + * Calculate length of request parameter block + */ + len = 2 + strlen(param) + 1 + strlen(data) + 1; + while (*p) { + if (smb_rap_parserqparam(p, &p, &plen) != 0) + break; + len += plen; + } + rap->r_pbuf = rap->r_npbuf = malloc(len); + smb_rap_rqparam(rap, 'W', 1, fn); + smb_rap_rqparam_z(rap, rap->r_sparam); + smb_rap_rqparam_z(rap, rap->r_sdata); + *rapp = rap; + return (0); +} + +void +smb_rap_done(struct smb_rap *rap) +{ + if (rap->r_sparam) + free(rap->r_sparam); + if (rap->r_sdata) + free(rap->r_sdata); + if (rap->r_pbuf) + free(rap->r_pbuf); +#ifdef NOTYETDEFINED + if (rap->r_npbuf) + free(rap->r_npbuf); + if (rap->r_dbuf) + free(rap->r_dbuf); + if (rap->r_rcvbuf) + free(rap->r_rcvbuf); +#endif + free(rap); +} + +int +smb_rap_setNparam(struct smb_rap *rap, int value) +{ + char *p = rap->r_nparam; + char ptype = *p; + int error, plen; + + error = smb_rap_parserqparam(p, &p, &plen); + if (error) + return (error); + switch (ptype) { + case 'L': + rap->r_rcvbuflen = value; + /* FALLTHROUGH */ + case 'W': + case 'D': + case 'b': + error = smb_rap_rqparam(rap, ptype, plen, value); + break; + default: + return (EINVAL); + } + rap->r_nparam = p; + return (0); +} + +int +smb_rap_setPparam(struct smb_rap *rap, void *value) +{ + char *p = rap->r_nparam; + char ptype = *p; + int error, plen; + + error = smb_rap_parserqparam(p, &p, &plen); + if (error) + return (error); + switch (ptype) { + case 'r': + rap->r_rcvbuf = value; + break; + default: + return (EINVAL); + } + rap->r_nparam = p; + return (0); +} + +static int +smb_rap_getNparam(struct smb_rap *rap, long *value) +{ + char *p = rap->r_nparam; + char ptype = *p; + int error, plen; + uint16_t *te; + + error = smb_rap_parserpparam(p, &p, &plen); + if (error) + return (error); + switch (ptype) { + case 'h': + /* LINTED */ + te = (uint16_t *)rap->r_npbuf; + *value = letohs(*te); + break; + default: + return (EINVAL); + } + rap->r_npbuf += plen; + rap->r_nparam = p; + return (0); +} + +int +smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx) +{ + uint16_t *rp, conv, *tmp; + uint32_t *p32, ps1; + char *dp, *p = rap->r_nparam; + char ptype; + int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow, i; + + rdatacnt = rap->r_rcvbuflen; + rparamcnt = rap->r_plen; + error = smb_t2_request(ctx, 0, NULL, "\\PIPE\\LANMAN", + rap->r_plen, rap->r_pbuf, /* int tparamcnt,void *tparam */ + 0, NULL, /* int tdatacnt, void *tdata */ + &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */ + &rdatacnt, rap->r_rcvbuf, /* int *rdatacnt, void *rdata */ + &buffer_oflow); + if (error) + return (error); + + /* LINTED */ + rp = (uint16_t *)rap->r_pbuf; + + /* + * Note: First is a "LanMan API" error code. + * See: usr/src/uts/common/smbsrv/lmerr.h + */ + if (rparamcnt < 2) + return (EBADRPC); + rap->r_result = letohs(*rp); + rp++; rparamcnt -= 2; + + if (rap->r_result != 0) { + /* + * Could also return zero and let the caller + * come get r_result via smb_rap_error(), + * but in case they dont... + */ + return (rap->r_result | SMB_RAP_ERROR); + } + + if (rparamcnt < 2) + return (EBADRPC); + conv = letohs(*rp); + rp++; rparamcnt -= 2; + + rap->r_npbuf = (char *)rp; + rap->r_entries = entries = 0; + /* Save the returned data length */ + rap->r_rcvbuflen = rdatacnt; + done = 0; + + while (!done && *p) { + ptype = *p; + switch (ptype) { + case 'e': + if (rparamcnt < 2) + return (EBADRPC); + /* LINTED */ + tmp = (uint16_t *)rap->r_npbuf; + rap->r_entries = entries = letohs(*tmp); + rap->r_npbuf += 2; + rparamcnt -= 2; + p++; + break; + default: + done = 1; + } +#if 0 /* commented out in Darwin. Why? */ + error = smb_rap_parserpparam(p, &p, &plen); + if (error) { + smb_error(dgettext(TEXT_DOMAIN, + "reply parameter mismatch %s"), 0, p); + return (EBADRPC); + } +#endif + } + rap->r_nparam = p; + /* + * In general, unpacking entries we may need to relocate + * entries for proper aligning. For now use them as is. + */ + dp = rap->r_rcvbuf; + while (entries--) { + p = rap->r_sdata; + while (*p) { + ptype = *p; + error = smb_rap_parserpdata(p, &p, &dlen); + if (error) { + smb_error(dgettext(TEXT_DOMAIN, + "reply data mismatch %s"), 0, p); + return (EBADRPC); + } + if (rdatacnt < dlen) + return (EBADRPC); + switch (ptype) { + case 'z': + /* LINTED */ + p32 = (uint32_t *)dp; + *p32 = (letohl(*p32) & 0xffff) - conv; + break; + } + dp += dlen; + rdatacnt -= dlen; + } + } + return (error); +} + +int +smb_rap_error(struct smb_rap *rap, int error) +{ + if (error) + return (error); + if (rap->r_result == 0) + return (0); + return (rap->r_result | SMB_RAP_ERROR); +} + +/* todo: move this function to libnetapi */ +int +smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer, + int *cbBuffer, int *pcEntriesRead, int *pcTotalAvail) +{ + struct smb_rap *rap; + long lval = -1; + int error; + char *pass; + int i; + + error = smb_rap_create(0, "WrLeh", "B13BWz", &rap); + if (error) + return (error); + smb_rap_setNparam(rap, sLevel); /* W - sLevel */ + smb_rap_setPparam(rap, pbBuffer); /* r - pbBuffer */ + smb_rap_setNparam(rap, *cbBuffer); /* L - cbBuffer */ + error = smb_rap_request(rap, ctx); + if (error == 0) { + *pcEntriesRead = rap->r_entries; + error = smb_rap_getNparam(rap, &lval); + *pcTotalAvail = lval; + /* Copy the data length into the IN/OUT variable. */ + *cbBuffer = rap->r_rcvbuflen; + } + error = smb_rap_error(rap, error); + smb_rap_done(rap); + return (error); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/rcfile.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,644 @@ +/* + * Copyright (c) 2000, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: rcfile.c,v 1.1.1.2 2001/07/06 22:38:43 conrad Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fcntl.h> +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <libintl.h> +#include <pwd.h> +#include <unistd.h> +#include <sys/debug.h> + +#include <cflib.h> +#include "rcfile_priv.h" + +SLIST_HEAD(rcfile_head, rcfile); +static struct rcfile_head pf_head = {NULL}; + +static struct rcfile *rc_cachelookup(const char *filename); +struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname); +static struct rcsection *rc_addsect(struct rcfile *rcp, const char *sectname); +static int rc_freesect(struct rcfile *rcp, struct rcsection *rsp); +struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname); +static struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name, + const char *value); +static void rc_key_free(struct rckey *p); +static void rc_parse(struct rcfile *rcp); + +int insecure_nsmbrc; + +/* + * open rcfile and load its content, if already open - return previous handle + */ +int +rc_open(const char *filename, const char *mode, struct rcfile **rcfile) +{ + struct rcfile *rcp; + FILE *f; + struct stat statbuf; + + rcp = rc_cachelookup(filename); + if (rcp) { + *rcfile = rcp; + return (0); + } + f = fopen(filename, mode); + if (f == NULL) + return (errno); + insecure_nsmbrc = 0; + if (fstat(fileno(f), &statbuf) >= 0 && + (statbuf.st_mode & 077) != 0) + insecure_nsmbrc = 1; + rcp = malloc(sizeof (struct rcfile)); + if (rcp == NULL) { + fclose(f); + return (ENOMEM); + } + bzero(rcp, sizeof (struct rcfile)); + rcp->rf_name = strdup(filename); + rcp->rf_f = f; + SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); + rc_parse(rcp); + *rcfile = rcp; + return (0); +} + +int +rc_merge(const char *filename, struct rcfile **rcfile) +{ + struct rcfile *rcp = *rcfile; + FILE *f, *t; + + insecure_nsmbrc = 0; + if (rcp == NULL) { + return (rc_open(filename, "r", rcfile)); + } + f = fopen(filename, "r"); + if (f == NULL) + return (errno); + t = rcp->rf_f; + rcp->rf_f = f; + rc_parse(rcp); + rcp->rf_f = t; + fclose(f); + return (0); +} + +int +rc_merge_pipe(const char *command, struct rcfile **rcfile) +{ + struct rcfile *rcp = *rcfile; + FILE *f, *t; + + insecure_nsmbrc = 0; + f = popen(command, "r"); + if (f == NULL) + return (errno); + if (rcp == NULL) { + rcp = malloc(sizeof (struct rcfile)); + if (rcp == NULL) { + fclose(f); + return (ENOMEM); + } + *rcfile = rcp; + bzero(rcp, sizeof (struct rcfile)); + rcp->rf_name = strdup(command); + rcp->rf_f = f; + SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); + rc_parse(rcp); + } else { + t = rcp->rf_f; + rcp->rf_f = f; + rc_parse(rcp); + rcp->rf_f = t; + } + fclose(f); + return (0); +} + +int +rc_close(struct rcfile *rcp) +{ + struct rcsection *p, *n; + + fclose(rcp->rf_f); + for (p = SLIST_FIRST(&rcp->rf_sect); p; ) { + n = p; + p = SLIST_NEXT(p, rs_next); + rc_freesect(rcp, n); + } + free(rcp->rf_name); + SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next); + free(rcp); + return (0); +} + +static struct rcfile * +rc_cachelookup(const char *filename) +{ + struct rcfile *p; + + SLIST_FOREACH(p, &pf_head, rf_next) + if (strcmp(filename, p->rf_name) == 0) + return (p); + return (0); +} + +/* static */ struct rcsection * +rc_findsect(struct rcfile *rcp, const char *sectname) +{ + struct rcsection *p; + + SLIST_FOREACH(p, &rcp->rf_sect, rs_next) + if (strcasecmp(p->rs_name, sectname) == 0) + return (p); + return (NULL); +} + +static struct rcsection * +rc_addsect(struct rcfile *rcp, const char *sectname) +{ + struct rcsection *p; + + p = rc_findsect(rcp, sectname); + if (p) + return (p); + p = malloc(sizeof (*p)); + if (!p) + return (NULL); + p->rs_name = strdup(sectname); + SLIST_INIT(&p->rs_keys); + SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next); + return (p); +} + +static int +rc_freesect(struct rcfile *rcp, struct rcsection *rsp) +{ + struct rckey *p, *n; + + SLIST_REMOVE(&rcp->rf_sect, rsp, rcsection, rs_next); + for (p = SLIST_FIRST(&rsp->rs_keys); p; ) { + n = p; + p = SLIST_NEXT(p, rk_next); + rc_key_free(n); + } + free(rsp->rs_name); + free(rsp); + return (0); +} + +/* static */ struct rckey * +rc_sect_findkey(struct rcsection *rsp, const char *keyname) +{ + struct rckey *p; + + SLIST_FOREACH(p, &rsp->rs_keys, rk_next) + if (strcmp(p->rk_name, keyname) == 0) + return (p); + return (NULL); +} + +static struct rckey * +rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value) +{ + struct rckey *p; + + p = rc_sect_findkey(rsp, name); + if (!p) { + p = malloc(sizeof (*p)); + if (!p) + return (NULL); + SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next); + p->rk_name = strdup(name); + p->rk_value = value ? strdup(value) : strdup(""); + } + return (p); +} + +#if 0 +void +rc_sect_delkey(struct rcsection *rsp, struct rckey *p) +{ + + SLIST_REMOVE(&rsp->rs_keys, p, rckey, rk_next); + rc_key_free(p); +} +#endif + +static void +rc_key_free(struct rckey *p) +{ + free(p->rk_value); + free(p->rk_name); + free(p); +} + +enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; + +int home_nsmbrc = 0; + +static char *minauth[] = { + "kerberos", + "ntlmv2", + "ntlm", + "lm", + "none", + NULL +}; + +static int +eval_minauth(char *auth) +{ + int i; + + for (i = 0; minauth[i]; i++) + if (strcmp(auth, minauth[i]) == 0) + break; + return (i); +} + +/* + * Ensure that "minauth" is set to the highest level (lowest array offset) + */ +static void +set_value(struct rcfile *rcp, struct rcsection *rsp, struct rckey *rkp, + char *ptr) +{ + int now, new; + + if (strcmp(rkp->rk_name, "minauth") == 0) { + now = eval_minauth(rkp->rk_value); + new = eval_minauth(ptr); + if (new >= now) { +#ifdef DEBUG + printf("set_value: rejecting %s=%s from %s\n", + rkp->rk_name, ptr, home_nsmbrc ? "user file" : "SMF"); +#endif + return; + } + } +#ifdef DEBUG + printf("set_value: applying %s=%s from %s\n", + rkp->rk_name, ptr, home_nsmbrc ? "user file" : "SMF"); +#endif + rkp->rk_value = strdup(ptr); +} + +static void +rc_parse(struct rcfile *rcp) +{ + FILE *f = rcp->rf_f; + int state = stNewLine, c; + struct rcsection *rsp = NULL; + struct rckey *rkp = NULL; + char buf[2048]; + char *next = buf, *last = &buf[sizeof (buf)-1]; + + while ((c = getc(f)) != EOF) { + if (c == '\r') + continue; + if (state == stNewLine) { + next = buf; + if (isspace(c)) + continue; /* skip leading junk */ + if (c == '[') { + state = stHeader; + rsp = NULL; + continue; + } + if (c == '#' || c == ';') { + state = stSkipToEOL; + } else { /* something meaningfull */ + state = stGetKey; + } + } + /* ignore long lines */ + if (state == stSkipToEOL || next == last) { + if (c == '\n') { + state = stNewLine; + next = buf; + } + continue; + } + if (state == stHeader) { + if (c == ']') { + *next = 0; + next = buf; + rsp = rc_addsect(rcp, buf); + state = stSkipToEOL; + } else + *next++ = c; + continue; + } + if (state == stGetKey) { + /* side effect: 'key name=' */ + if (c == ' ' || c == '\t') + continue; /* become 'keyname=' */ + if (c == '\n') { /* silently ignore ... */ + state = stNewLine; + continue; + } + if (c != '=') { + *next++ = c; + continue; + } + *next = 0; + if (rsp == NULL) { + fprintf(stderr, dgettext(TEXT_DOMAIN, + "Key '%s' defined before section\n"), buf); + state = stSkipToEOL; + continue; + } + if (home_nsmbrc && + (strcmp(buf, "nbns") == 0 || + strcmp(buf, "nbns_enable") == 0 || + strcmp(buf, "nbns_broadcast") == 0)) { + fprintf(stderr, dgettext(TEXT_DOMAIN, + "option %s may not be set " + "in user .nsmbrc file\n"), buf); + next = buf; + state = stNewLine; + continue; + } + if (insecure_nsmbrc && (strcmp(buf, "password") == 0)) { + fprintf(stderr, dgettext(TEXT_DOMAIN, + "Warning: .nsmbrc file not secure, " + "ignoring passwords\n")); + next = buf; + state = stNewLine; + continue; + } + rkp = rc_sect_addkey(rsp, buf, NULL); + next = buf; + state = stGetValue; + continue; + } + /* only stGetValue left */ + if (state != stGetValue) { + fprintf(stderr, dgettext(TEXT_DOMAIN, + "Well, I can't parse file '%s'\n"), rcp->rf_name); + state = stSkipToEOL; + } + if (c != '\n') { + *next++ = c; + continue; + } + *next = 0; + set_value(rcp, rsp, rkp, buf); + state = stNewLine; + rkp = NULL; + } /* while */ + if (c == EOF && state == stGetValue) { + *next = 0; + set_value(rcp, rsp, rkp, buf); + } +} + +int +rc_getstringptr(struct rcfile *rcp, const char *section, const char *key, + char **dest) +{ + struct rcsection *rsp; + struct rckey *rkp; + + *dest = NULL; + rsp = rc_findsect(rcp, section); + if (!rsp) + return (ENOENT); + rkp = rc_sect_findkey(rsp, key); + if (!rkp) + return (ENOENT); + *dest = rkp->rk_value; + return (0); +} + +int +rc_getstring(struct rcfile *rcp, const char *section, const char *key, + size_t maxlen, char *dest) +{ + char *value; + int error; + + error = rc_getstringptr(rcp, section, key, &value); + if (error) + return (error); + if (strlen(value) >= maxlen) { + fprintf(stdout, dgettext(TEXT_DOMAIN, + "line too long for key '%s' in section '%s', max = %d\n"), + key, section, maxlen); + return (EINVAL); + } + strcpy(dest, value); + return (0); +} + +int +rc_getint(struct rcfile *rcp, const char *section, const char *key, int *value) +{ + struct rcsection *rsp; + struct rckey *rkp; + + rsp = rc_findsect(rcp, section); + if (!rsp) + return (ENOENT); + rkp = rc_sect_findkey(rsp, key); + if (!rkp) + return (ENOENT); + errno = 0; + *value = strtol(rkp->rk_value, NULL, 0); + if (errno) { + fprintf(stdout, dgettext(TEXT_DOMAIN, + "invalid int value '%s' for key '%s' in section '%s'\n"), + rkp->rk_value, key, section); + return (errno); + } + return (0); +} + +/* + * 1,yes,true + * 0,no,false + */ +int +rc_getbool(struct rcfile *rcp, const char *section, const char *key, int *value) +{ + struct rcsection *rsp; + struct rckey *rkp; + char *p; + + rsp = rc_findsect(rcp, section); + if (!rsp) + return (ENOENT); + rkp = rc_sect_findkey(rsp, key); + if (!rkp) + return (ENOENT); + p = rkp->rk_value; + while (*p && isspace(*p)) p++; + if (*p == '0' || + strcasecmp(p, "no") == 0 || + strcasecmp(p, "false") == 0) { + *value = 0; + return (0); + } + if (*p == '1' || + strcasecmp(p, "yes") == 0 || + strcasecmp(p, "true") == 0) { + *value = 1; + return (0); + } + fprintf(stderr, dgettext(TEXT_DOMAIN, + "invalid boolean value '%s' for key '%s' in section '%s' \n"), + p, key, section); + return (EINVAL); +} + +/* + * Unified command line/rc file parser + */ +int +opt_args_parse(struct rcfile *rcp, struct opt_args *ap, const char *sect, + opt_callback_t *callback) +{ + int len, error; + + for (; ap->opt; ap++) { + switch (ap->type) { + case OPTARG_STR: + if (rc_getstringptr(rcp, sect, ap->name, &ap->str) != 0) + break; + len = strlen(ap->str); + if (len > ap->ival) { + fprintf(stdout, dgettext(TEXT_DOMAIN, + "rc: argument for option '%c' (%s) too long\n"), + ap->opt, ap->name); + return (EINVAL); + } + callback(ap); + break; + case OPTARG_BOOL: + error = rc_getbool(rcp, sect, ap->name, &ap->ival); + if (error == ENOENT) + break; + if (error) + return (EINVAL); + callback(ap); + break; + case OPTARG_INT: + if (rc_getint(rcp, sect, ap->name, &ap->ival) != 0) + break; + if (((ap->flag & OPTFL_HAVEMIN) && + ap->ival < ap->min) || + ((ap->flag & OPTFL_HAVEMAX) && + ap->ival > ap->max)) { + fprintf(stdout, dgettext(TEXT_DOMAIN, + "rc: argument for option '%c' (%s) " + "should be in [%d-%d] range\n"), + ap->opt, ap->name, ap->min, ap->max); + return (EINVAL); + } + callback(ap); + break; + default: + break; + } + } + return (0); +} + +int +opt_args_parseopt(struct opt_args *ap, int opt, char *arg, + opt_callback_t *callback) +{ + int len; + + for (; ap->opt; ap++) { + if (ap->opt != opt) + continue; + switch (ap->type) { + case OPTARG_STR: + ap->str = arg; + if (arg) { + len = strlen(ap->str); + if (len > ap->ival) { + fprintf(stdout, dgettext(TEXT_DOMAIN, + "opt: Argument for option '%c' (%s) too long\n"), + ap->opt, ap->name); + return (EINVAL); + } + callback(ap); + } + break; + case OPTARG_BOOL: + ap->ival = 0; + callback(ap); + break; + case OPTARG_INT: + errno = 0; + ap->ival = strtol(arg, NULL, 0); + if (errno) { + fprintf(stdout, dgettext(TEXT_DOMAIN, + "opt: Invalid integer value for " + "option '%c' (%s).\n"), + ap->opt, ap->name); + return (EINVAL); + } + if (((ap->flag & OPTFL_HAVEMIN) && + (ap->ival < ap->min)) || + ((ap->flag & OPTFL_HAVEMAX) && + (ap->ival > ap->max))) { + fprintf(stdout, dgettext(TEXT_DOMAIN, + "opt: Argument for option '%c' (%s) " + "should be in [%d-%d] range\n"), + ap->opt, ap->name, ap->min, ap->max); + return (EINVAL); + } + callback(ap); + break; + default: + break; + } + break; + } + return (0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/rcfile_priv.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,21 @@ +#pragma ident "%Z%%M% %I% %E% SMI" + +struct rckey { + SLIST_ENTRY(rckey) rk_next; + char *rk_name; + char *rk_value; +}; + +struct rcsection { + SLIST_ENTRY(rcsection) rs_next; + SLIST_HEAD(rckey_head,rckey) rs_keys; + char *rs_name; +}; + +struct rcfile { + SLIST_ENTRY(rcfile) rf_next; + SLIST_HEAD(rcsec_head, rcsection) rf_sect; + char *rf_name; + FILE *rf_f; +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/rq.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2000, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: rq.c,v 1.4 2004/12/13 00:25:23 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <strings.h> +#include <stdlib.h> +#include <sysexits.h> +#include <libintl.h> + +#include <netsmb/smb_lib.h> + +extern uid_t real_uid, eff_uid; + + +int +smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, size_t rpbufsz, + struct smb_rq **rqpp) +{ + struct smb_rq *rqp; + + rqp = malloc(sizeof (*rqp)); + if (rqp == NULL) + return (ENOMEM); + bzero(rqp, sizeof (*rqp)); + rqp->rq_cmd = cmd; + rqp->rq_ctx = ctx; + mb_init(&rqp->rq_rq, M_MINSIZE); + mb_init(&rqp->rq_rp, rpbufsz); + *rqpp = rqp; + return (0); +} + +void +smb_rq_done(struct smb_rq *rqp) +{ + mb_done(&rqp->rq_rp); + mb_done(&rqp->rq_rq); + free(rqp); +} + +void +smb_rq_wend(struct smb_rq *rqp) +{ + if (rqp->rq_rq.mb_count & 1) + smb_error(dgettext(TEXT_DOMAIN, + "smbrq_wend: odd word count\n"), 0); + rqp->rq_wcount = rqp->rq_rq.mb_count / 2; + rqp->rq_rq.mb_count = 0; +} + +int +smb_rq_dmem(struct mbdata *mbp, const char *src, size_t size) +{ + struct mbuf *m; + char *dst; + int cplen, error; + + if (size == 0) + return (0); + m = mbp->mb_cur; + if ((error = m_getm(m, size, &m)) != 0) + return (error); + while (size > 0) { + cplen = M_TRAILINGSPACE(m); + if (cplen == 0) { + m = m->m_next; + continue; + } + if (cplen > (int)size) + cplen = size; + dst = mtod(m, char *) + m->m_len; + nls_mem_toext(dst, src, cplen); + size -= cplen; + src += cplen; + m->m_len += cplen; + mbp->mb_count += cplen; + } + mbp->mb_pos = mtod(m, char *) + m->m_len; + mbp->mb_cur = m; + return (0); +} + +int +smb_rq_dstring(struct mbdata *mbp, const char *s) +{ + return (smb_rq_dmem(mbp, s, strlen(s) + 1)); +} + +int +smb_rq_simple(struct smb_rq *rqp) +{ + struct smbioc_rq krq; + struct mbdata *mbp; + char *data; + int i; + + mbp = smb_rq_getrequest(rqp); + m_lineup(mbp->mb_top, &mbp->mb_top); + data = mtod(mbp->mb_top, char *); + bzero(&krq, sizeof (krq)); + krq.ioc_cmd = rqp->rq_cmd; + krq.ioc_twc = rqp->rq_wcount; + krq.ioc_twords = data; + krq.ioc_tbc = mbp->mb_count; + krq.ioc_tbytes = data + rqp->rq_wcount * 2; + + mbp = smb_rq_getreply(rqp); + krq.ioc_rpbufsz = mbp->mb_top->m_maxlen; + krq.ioc_rpbuf = mtod(mbp->mb_top, char *); + seteuid(eff_uid); + if (ioctl(rqp->rq_ctx->ct_fd, SMBIOC_REQUEST, &krq) == -1) { + seteuid(real_uid); /* and back to real user */ + return (errno); + } + mbp->mb_top->m_len = krq.ioc_rwc * 2 + krq.ioc_rbc; + rqp->rq_wcount = krq.ioc_rwc; + rqp->rq_bcount = krq.ioc_rbc; + seteuid(real_uid); /* and back to real user */ + return (0); +} + + +int +smb_t2_request(struct smb_ctx *ctx, int setupcount, uint16_t *setup, + const char *name, + int tparamcnt, void *tparam, + int tdatacnt, void *tdata, + int *rparamcnt, void *rparam, + int *rdatacnt, void *rdata, + int *buffer_oflow) +{ + smbioc_t2rq_t *krq; + int i; + char *pass; + + + krq = (smbioc_t2rq_t *)malloc(sizeof (smbioc_t2rq_t)); + bzero(krq, sizeof (*krq)); + + if (setupcount < 0 || setupcount >= SMB_MAXSETUPWORDS) { + /* Bogus setup count, or too many setup words */ + return (EINVAL); + } + for (i = 0; i < setupcount; i++) + krq->ioc_setup[i] = setup[i]; + krq->ioc_setupcnt = setupcount; + strcpy(krq->ioc_name, name); + krq->ioc_tparamcnt = tparamcnt; + krq->ioc_tparam = tparam; + krq->ioc_tdatacnt = tdatacnt; + krq->ioc_tdata = tdata; + + krq->ioc_rparamcnt = *rparamcnt; + krq->ioc_rdatacnt = *rdatacnt; + krq->ioc_rparam = rparam; + krq->ioc_rdata = rdata; + + seteuid(eff_uid); + if (ioctl(ctx->ct_fd, SMBIOC_T2RQ, krq) == -1) { + seteuid(real_uid); /* and back to real user */ + return (errno); + } + + *rparamcnt = krq->ioc_rparamcnt; + *rdatacnt = krq->ioc_rdatacnt; + *buffer_oflow = (krq->ioc_rpflags2 & SMB_FLAGS2_ERR_STATUS) && + (krq->ioc_error == NT_STATUS_BUFFER_OVERFLOW); + seteuid(real_uid); /* and back to real user */ + free(krq); + return (0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/spnego.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,797 @@ +// Copyright (C) 2002 Microsoft Corporation +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" +// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +// OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY +// AND/OR FITNESS FOR A PARTICULAR PURPOSE. +// +// Date - 10/08/2002 +// Author - Sanj Surati + +///////////////////////////////////////////////////////////// +// +// SPNEGO.C +// +// SPNEGO Token Handler Source File +// +// Contains implementation of SPNEGO Token Handling API +// as defined in SPNEGO.H. +// +///////////////////////////////////////////////////////////// + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <stdio.h> +#include <memory.h> +#include "spnego.h" +#include "derparse.h" +#include "spnegoparse.h" + +// +// Defined in DERPARSE.C +// + +extern MECH_OID g_stcMechOIDList []; + + +/**********************************************************************/ +/** **/ +/** **/ +/** **/ +/** **/ +/** SPNEGO Token Handler API implementation **/ +/** **/ +/** **/ +/** **/ +/** **/ +/**********************************************************************/ + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoInitFromBinary +// +// Parameters: +// [in] pbTokenData - Binary Token Data +// [in] ulLength - Length of binary Token Data +// [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Initializes a SPNEGO_TOKEN_HANDLE from the supplied +// binary data. Data is copied locally. Returned data structure +// must be freed by calling spnegoFreeData(). +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoInitFromBinary( unsigned char* pbTokenData, unsigned long ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken; + + // Pass off to a handler function that allows tighter control over how the token structure + // is handled. In this case, we want the token data copied and we want the associated buffer + // freed. + nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYDATA, + SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA, pbTokenData, + ulLength, ppSpnegoToken ); + + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoCreateNegTokenInit +// +// Parameters: +// [in] MechType - MechType to specify in MechTypeList element +// [in] ucContextFlags - Context Flags element value +// [in] pbMechToken - Pointer to binary MechToken Data +// [in] ulMechTokenLen - Length of MechToken Data +// [in] pbMechListMIC - Pointer to binary MechListMIC Data +// [in] ulMechListMICLen - Length of MechListMIC Data +// [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenInit type +// from the supplied parameters. ucContextFlags may be 0 or must be +// a valid flag combination. MechToken data can be NULL - if not, it +// must correspond to the MechType. MechListMIC can also be NULL. +// Returned data structure must be freed by calling spnegoFreeData(). +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType, + unsigned char ucContextFlags, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, + unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + long nTokenLength = 0L; + long nInternalTokenLength = 0L; + unsigned char* pbTokenData = NULL; + SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken; + + if ( NULL != ppSpnegoToken && + IsValidMechOid( MechType ) && + IsValidContextFlags( ucContextFlags ) ) + { + // Get the actual token size + + if ( ( nReturn = CalculateMinSpnegoInitTokenSize( ulMechTokenLen, ulMechListMICLen, + MechType, ( ucContextFlags != 0L ), + &nTokenLength, &nInternalTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Allocate a buffer to hold the data. + pbTokenData = calloc( 1, nTokenLength ); + + if ( NULL != pbTokenData ) + { + + // Now write the token + if ( ( nReturn = CreateSpnegoInitToken( MechType, + ucContextFlags, pbMechToken, + ulMechTokenLen, pbMechListMIC, + ulMechListMICLen, pbTokenData, + nTokenLength, nInternalTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + + // This will copy our allocated pointer, and ensure that the sructure cleans + // up the data later + nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYPTR, + SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA, + pbTokenData, nTokenLength, ppSpnegoToken ); + + } + + // Cleanup on failure + if ( SPNEGO_E_SUCCESS != nReturn ) + { + free( pbTokenData ); + } + + } // IF alloc succeeded + else + { + nReturn = SPNEGO_E_OUT_OF_MEMORY; + } + + } // If calculated token size + + } // IF Valid Parameters + + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoCreateNegTokenTarg +// +// Parameters: +// [in] MechType - MechType to specify in supported MechType element +// [in] spnegoNegResult - NegResult value +// [in] pbMechToken - Pointer to response MechToken Data +// [in] ulMechTokenLen - Length of MechToken Data +// [in] pbMechListMIC - Pointer to binary MechListMIC Data +// [in] ulMechListMICLen - Length of MechListMIC Data +// [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenTarg type +// from the supplied parameters. MechToken data can be NULL - if not, +// it must correspond to the MechType. MechListMIC can also be NULL. +// Returned data structure must be freed by calling spnegoFreeData(). +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoCreateNegTokenTarg( SPNEGO_MECH_OID MechType, + SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, + unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + long nTokenLength = 0L; + long nInternalTokenLength = 0L; + unsigned char* pbTokenData = NULL; + SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken; + + // + // spnego_mech_oid_NotUsed and spnego_negresult_NotUsed + // are okay here, however a valid MechOid is required + // if spnego_negresult_success or spnego_negresult_incomplete + // is specified. + // + + if ( NULL != ppSpnegoToken && + + ( IsValidMechOid( MechType ) || + spnego_mech_oid_NotUsed == MechType ) && + + ( IsValidNegResult( spnegoNegResult ) || + spnego_negresult_NotUsed == spnegoNegResult ) && + + !( !IsValidMechOid( MechType ) && + ( spnego_negresult_success == spnegoNegResult || + spnego_negresult_incomplete == spnegoNegResult ) ) ) + { + + // Get the actual token size + + if ( ( nReturn = CalculateMinSpnegoTargTokenSize( MechType, spnegoNegResult, ulMechTokenLen, + ulMechListMICLen, &nTokenLength, + &nInternalTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Allocate a buffer to hold the data. + pbTokenData = calloc( 1, nTokenLength ); + + if ( NULL != pbTokenData ) + { + + // Now write the token + if ( ( nReturn = CreateSpnegoTargToken( MechType, + spnegoNegResult, pbMechToken, + ulMechTokenLen, pbMechListMIC, + ulMechListMICLen, pbTokenData, + nTokenLength, nInternalTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + + // This will copy our allocated pointer, and ensure that the sructure cleans + // up the data later + nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYPTR, + SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA, + pbTokenData, nTokenLength, ppSpnegoToken ); + + } + + // Cleanup on failure + if ( SPNEGO_E_SUCCESS != nReturn ) + { + free( pbTokenData ); + } + + } // IF alloc succeeded + else + { + nReturn = SPNEGO_E_OUT_OF_MEMORY; + } + + } // If calculated token size + + } // IF Valid Parameters + + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoTokenGetBinary +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [out] pbTokenData - Buffer to copy token into +// [in/out] pulDataLen - Length of pbTokenData buffer, filled out +// with actual size used upon function return. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Copies binary SPNEGO token data from hSpnegoToken into the user +// supplied buffer. If pbTokenData is NULL, or the value in pulDataLen +// is too small, the function will return SPNEGO_E_BUFFER_TOO_SMALL and +// fill out pulDataLen with the minimum required buffer size. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoTokenGetBinary( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, + unsigned long * pulDataLen ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + + // Check parameters - pbTokenData is optional + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != pulDataLen ) + { + + // Check for Buffer too small conditions + if ( NULL == pbTokenData || + pSpnegoToken->ulBinaryDataLen > *pulDataLen ) + { + *pulDataLen = pSpnegoToken->ulBinaryDataLen; + nReturn = SPNEGO_E_BUFFER_TOO_SMALL; + } + else + { + memcpy( pbTokenData, pSpnegoToken->pbBinaryData, pSpnegoToken->ulBinaryDataLen ); + *pulDataLen = pSpnegoToken->ulBinaryDataLen; + nReturn = SPNEGO_E_SUCCESS; + } + + } // IF parameters OK + + return nReturn;; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoFreeData +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// +// Returns: +// void +// +// Comments : +// Frees up resources consumed by hSpnegoToken. The supplied data +// pointer is invalidated by this function. +// +//////////////////////////////////////////////////////////////////////////// + +void spnegoFreeData( SPNEGO_TOKEN_HANDLE hSpnegoToken ) +{ + FreeSpnegoToken( (SPNEGO_TOKEN*) hSpnegoToken); + return; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoGetTokenType +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [out] piTokenType - Filled out with token type value. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// The function will analyze hSpnegoToken and return the appropriate +// type in piTokenType. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoGetTokenType( SPNEGO_TOKEN_HANDLE hSpnegoToken, int * piTokenType ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + + // Check parameters + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != piTokenType && + pSpnegoToken) + { + + // Check that the type in the structure makes sense + if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType || + SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType ) + { + *piTokenType = pSpnegoToken->ucTokenType; + nReturn = SPNEGO_E_SUCCESS; + } + + } // IF parameters OK + + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoIsMechTypeAvailable +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [in] MechOID - MechOID to search MechTypeList for +// [out] piMechTypeIndex - Filled out with index in MechTypeList +// element if MechOID is found. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// hSpnegoToken must reference a token of type NegTokenInit. The +// function will search the MechTypeList element for an OID corresponding +// to the specified MechOID. If one is found, the index (0 based) will +// be passed into the piMechTypeIndex parameter. +// +//////////////////////////////////////////////////////////////////////////// + +// Returns the Initial Mech Type in the MechList element in the NegInitToken. +int spnegoIsMechTypeAvailable( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int * piMechTypeIndex ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + + // Check parameters + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != piMechTypeIndex && + IsValidMechOid( MechOID ) && + SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) + { + + // Check if MechList is available + if ( pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT].iElementPresent + == SPNEGO_TOKEN_ELEMENT_AVAILABLE ) + { + // Locate the MechOID in the list element + nReturn = FindMechOIDInMechList( + &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT], + MechOID, piMechTypeIndex ); + } + else + { + nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; + } + + } // IF parameters OK + + return nReturn;; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoGetContextFlags +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [out] pucContextFlags - Filled out with ContextFlags value. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// hSpnegoToken must reference a token of type NegTokenInit. The +// function will copy data from the ContextFlags element into the +// location pucContextFlags points to. Note that the function will +// fail if the actual ContextFlags data appears invalid. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoGetContextFlags( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + + // Check parameters + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != pucContextFlags && + SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) + { + + // Check if ContextFlags is available + if ( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].iElementPresent + == SPNEGO_TOKEN_ELEMENT_AVAILABLE ) + { + // The length should be two, the value should show a 1 bit difference in the difference byte, and + // the value must be valid + if ( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].nDatalength == SPNEGO_NEGINIT_MAXLEN_REQFLAGS && + pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[0] == SPNEGO_NEGINIT_REQFLAGS_BITDIFF && + IsValidContextFlags( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[1] ) ) + { + *pucContextFlags = pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[1]; + nReturn = SPNEGO_E_SUCCESS; + } + else + { + nReturn = SPNEGO_E_INVALID_ELEMENT; + } + + } + else + { + nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; + } + + } // IF parameters OK + + return nReturn;; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoGetNegotiationResult +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [out] pnegResult - Filled out with NegResult value. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// hSpnegoToken must reference a token of type NegTokenTarg. The +// function will copy data from the NegResult element into the +// location pointed to by pnegResult. Note that the function will +// fail if the actual NegResult data appears invalid. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoGetNegotiationResult( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + + // Check parameters + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != pnegResult && + SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType ) + { + + // Check if NegResult is available + if ( pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].iElementPresent + == SPNEGO_TOKEN_ELEMENT_AVAILABLE ) + { + // Must be 1 byte long and a valid value + if ( pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].nDatalength == SPNEGO_NEGTARG_MAXLEN_NEGRESULT && + IsValidNegResult( *pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData ) ) + { + *pnegResult = *pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData; + nReturn = SPNEGO_E_SUCCESS; + } + else + { + nReturn = SPNEGO_E_INVALID_ELEMENT; + } + } + else + { + nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; + } + + } // IF parameters OK + + return nReturn;; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoGetSupportedMechType +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [out] pMechOID - Filled out with Supported MechType value. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// hSpnegoToken must reference a token of type NegTokenTarg. The +// function will check the Supported MechType element, and if it +// corresponds to a supported MechType ( spnego_mech_oid_Kerberos_V5_Legacy +// or spnego_mech_oid_Kerberos_V5 ), will set the location pointed +// to by pMechOID equal to the appropriate value. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoGetSupportedMechType( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + int nCtr = 0L; + long nLength = 0L; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + + // Check parameters + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != pMechOID && + SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType ) + { + + // Check if MechList is available + if ( pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].iElementPresent + == SPNEGO_TOKEN_ELEMENT_AVAILABLE ) + { + + for ( nCtr = 0; + nReturn != SPNEGO_E_SUCCESS && + g_stcMechOIDList[nCtr].eMechanismOID != spnego_mech_oid_NotUsed; + nCtr++ ) + { + + if ( ( nReturn = ASNDerCheckOID( + pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].pbData, + nCtr, + pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].nDatalength, + &nLength ) ) == SPNEGO_E_SUCCESS ) + { + *pMechOID = nCtr; + } + + } // For enum MechOIDs + + + } + else + { + nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; + } + + } // IF parameters OK + + return nReturn;; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoTokenGetMechToken +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [out] pbTokenData - Buffer to copy MechToken into +// [in/out] pulDataLen - Length of pbTokenData buffer, filled out +// with actual size used upon function return. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token. +// The function will copy the MechToken (the initial MechToken if +// NegTokenInit, the response MechToken if NegTokenTarg) from the +// underlying token into the buffer pointed to by pbTokenData. If +// pbTokenData is NULL, or the value in pulDataLen is too small, the +// function will return SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen +// with the minimum required buffer size. The token can then be passed +// to a GSS-API function for processing. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoGetMechToken( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned long* pulDataLen ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + SPNEGO_ELEMENT* pSpnegoElement = NULL; + + // Check parameters + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != pulDataLen ) + { + + // Point at the proper Element + if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) + { + pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTOKEN_ELEMENT]; + } + else + { + pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_TARG_RESPTOKEN_ELEMENT]; + } + + // Check if MechType is available + if ( SPNEGO_TOKEN_ELEMENT_AVAILABLE == pSpnegoElement->iElementPresent ) + { + // Check for Buffer too small conditions + if ( NULL == pbTokenData || + pSpnegoElement->nDatalength > *pulDataLen ) + { + *pulDataLen = pSpnegoElement->nDatalength; + nReturn = SPNEGO_E_BUFFER_TOO_SMALL; + } + else + { + // Copy Memory + memcpy( pbTokenData, pSpnegoElement->pbData, pSpnegoElement->nDatalength ); + *pulDataLen = pSpnegoElement->nDatalength; + nReturn = SPNEGO_E_SUCCESS; + } + } + else + { + nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; + } + + } // IF parameters OK + + return nReturn;; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// spnegoTokenGetMechListMIC +// +// Parameters: +// [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE +// [out] pbTokenData - Buffer to copy MechListMIC data into +// [in/out] pulDataLen - Length of pbTokenData buffer, filled out +// with actual size used upon function return. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token. +// The function will copy the MechListMIC data from the underlying token +// into the buffer pointed to by pbTokenData. If pbTokenData is NULL, +// or the value in pulDataLen is too small, the function will return +// SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen with the minimum +// required buffer size. +// +//////////////////////////////////////////////////////////////////////////// + +int spnegoGetMechListMIC( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned long* pulDataLen ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken; + SPNEGO_ELEMENT* pSpnegoElement = NULL; + + // Check parameters + if ( IsValidSpnegoToken( pSpnegoToken ) && + NULL != pulDataLen ) + { + + // Point at the proper Element + if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) + { + pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHLISTMIC_ELEMENT]; + } + else + { + pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_TARG_MECHLISTMIC_ELEMENT]; + } + + // Check if MechType is available + if ( SPNEGO_TOKEN_ELEMENT_AVAILABLE == pSpnegoElement->iElementPresent ) + { + // Check for Buffer too small conditions + if ( NULL == pbMICData || + pSpnegoElement->nDatalength > *pulDataLen ) + { + *pulDataLen = pSpnegoElement->nDatalength; + nReturn = SPNEGO_E_BUFFER_TOO_SMALL; + } + else + { + // Copy Memory + memcpy( pbMICData, pSpnegoElement->pbData, pSpnegoElement->nDatalength ); + *pulDataLen = pSpnegoElement->nDatalength; + nReturn = SPNEGO_E_SUCCESS; + } + } + else + { + nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE; + } + + } // IF parameters OK + + return nReturn;; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/spnego.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,244 @@ +// Copyright (C) 2002 Microsoft Corporation +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" +// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +// OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY +// AND/OR FITNESS FOR A PARTICULAR PURPOSE. +// +// Date - 10/08/2002 +// Author - Sanj Surati + +///////////////////////////////////////////////////////////// +// +// SPNEGO.H +// +// SPNEGO Token Handler Header File +// +// Contains the definitions required to interpret and create +// SPNEGO tokens so that Kerberos GSS tokens can be +// Unpackaged/packaged. +// +///////////////////////////////////////////////////////////// + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef __SPNEGO_H__ +#define __SPNEGO_H__ + +// C++ Specific +#if defined(__cplusplus) +extern "C" +{ +#endif + +// Type Definitions + +// +// Users of SPNEGO Token Handler API will request +// these as well as free them, +// +typedef void* SPNEGO_TOKEN_HANDLE; + +// +// Defines the element types that are found +// in each of the tokens. +// + +typedef enum spnego_element_type +{ + spnego_element_min, // Lower bound + + // Init token elements + spnego_init_mechtypes, + spnego_init_reqFlags, + spnego_init_mechToken, + spnego_init_mechListMIC, + + // Targ token elements + spnego_targ_negResult, + spnego_targ_supportedMech, + spnego_targ_responseToken, + spnego_targ_mechListMIC, + + spnego_element_max // Upper bound + +} SPNEGO_ELEMENT_TYPE; + +// +// Token Element Availability. Elements in both +// token types are optional. Since there are only +// 4 elements in each Token, we will allocate space +// to hold the information, but we need a way to +// indicate whether or not an element is available +// + +#define SPNEGO_TOKEN_ELEMENT_UNAVAILABLE 0 +#define SPNEGO_TOKEN_ELEMENT_AVAILABLE 1 + +// +// Token type values. SPNEGO has 2 token types: +// NegTokenInit and NegTokenTarg +// + +#define SPNEGO_TOKEN_INIT 0 +#define SPNEGO_TOKEN_TARG 1 + +// +// GSS Mechanism OID enumeration. We only really handle +// 3 different OIDs. These are stored in an array structure +// defined in the parsing code. +// + +typedef enum spnego_mech_oid +{ + // Init token elements + spnego_mech_oid_Kerberos_V5_Legacy, // Really V5, but OID off by 1 bit + spnego_mech_oid_Kerberos_V5, + spnego_mech_oid_Spnego, + spnego_mech_oid_NTLMSSP, + spnego_mech_oid_NotUsed = -1 + +} SPNEGO_MECH_OID; + +// +// Defines the negResult values. +// + +typedef enum spnego_negResult +{ + spnego_negresult_success, + spnego_negresult_incomplete, + spnego_negresult_rejected, + spnego_negresult_NotUsed = -1 +} SPNEGO_NEGRESULT; + +// +// Context Flags in NegTokenInit +// + +// +// ContextFlags values MUST be zero or a combination +// of the below +// + +#define SPNEGO_NEGINIT_CONTEXT_DELEG_FLAG 0x80 +#define SPNEGO_NEGINIT_CONTEXT_MUTUAL_FLAG 0x40 +#define SPNEGO_NEGINIT_CONTEXT_REPLAY_FLAG 0x20 +#define SPNEGO_NEGINIT_CONTEXT_SEQUENCE_FLAG 0x10 +#define SPNEGO_NEGINIT_CONTEXT_ANON_FLAG 0x8 +#define SPNEGO_NEGINIT_CONTEXT_CONF_FLAG 0x4 +#define SPNEGO_NEGINIT_CONTEXT_INTEG_FLAG 0x2 + +// +// Mask to retrieve valid values. +// + +#define SPNEGO_NEGINIT_CONTEXT_MASK 0xFE // Logical combination of above flags + +// +// SPNEGO API return codes. +// + +// API function was successful +#define SPNEGO_E_SUCCESS 0 + +// The supplied Token was invalid +#define SPNEGO_E_INVALID_TOKEN -1 + +// An invalid length was encountered +#define SPNEGO_E_INVALID_LENGTH -2 + +// The Token Parse failed +#define SPNEGO_E_PARSE_FAILED -3 + +// The requested value was not found +#define SPNEGO_E_NOT_FOUND -4 + +// The requested element is not available +#define SPNEGO_E_ELEMENT_UNAVAILABLE -5 + +// Out of Memory +#define SPNEGO_E_OUT_OF_MEMORY -6 + +// Not Implemented +#define SPNEGO_E_NOT_IMPLEMENTED -7 + +// Invalid Parameter +#define SPNEGO_E_INVALID_PARAMETER -8 + +// Token Handler encountered an unexpected OID +#define SPNEGO_E_UNEXPECTED_OID -9 + +// The requested token was not found +#define SPNEGO_E_TOKEN_NOT_FOUND -10 + +// An unexpected type was encountered in the encoding +#define SPNEGO_E_UNEXPECTED_TYPE -11 + +// The buffer was too small +#define SPNEGO_E_BUFFER_TOO_SMALL -12 + +// A Token Element was invalid (e.g. improper length or value) +#define SPNEGO_E_INVALID_ELEMENT -13 + +/* Miscelaneous API Functions */ + +// Frees opaque data +void spnegoFreeData( SPNEGO_TOKEN_HANDLE hSpnegoToken ); + +// Initializes SPNEGO_TOKEN structure from DER encoded binary data +int spnegoInitFromBinary( unsigned char* pbTokenData, unsigned long ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken ); + +// Initializes SPNEGO_TOKEN structure for a NegTokenInit type using the +// supplied parameters +int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType, + unsigned char ucContextFlags, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechTokenMIC, + unsigned long ulMechTokenMIC, SPNEGO_TOKEN_HANDLE* phSpnegoToken ); + +// Initializes SPNEGO_TOKEN structure for a NegTokenTarg type using the +// supplied parameters +int spnegoCreateNegTokenTarg( SPNEGO_MECH_OID MechType, + SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, + unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken ); + +// Copies binary representation of SPNEGO Data into user supplied buffer +int spnegoTokenGetBinary( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, + unsigned long * pulDataLen ); + +// Returns SPNEGO Token Type +int spnegoGetTokenType( SPNEGO_TOKEN_HANDLE hSpnegoToken, int * piTokenType ); + +/* Reading an Init Token */ + +// Returns the Initial Mech Type in the MechList element in the NegInitToken. +int spnegoIsMechTypeAvailable( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int * piMechTypeIndex ); + +// Returns the value from the context flags element in the NegInitToken as an unsigned long +int spnegoGetContextFlags( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags ); + +/* Reading a Response Token */ + +// Returns the value from the negResult element (Status code of GSS call - 0,1,2) +int spnegoGetNegotiationResult( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult ); + +// Returns the Supported Mech Type from the NegTokenTarg. +int spnegoGetSupportedMechType( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID ); + +/* Reading either Token Type */ + +// Returns the actual Mechanism data from the token (this is what is passed into GSS-API functions +int spnegoGetMechToken( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned long* pulDataLen ); + +// Returns the Message Integrity BLOB in the token +int spnegoGetMechListMIC( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned long* pulDataLen ); + +// C++ Specific +#if defined(__cplusplus) +} +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/spnegoparse.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,1883 @@ +// Copyright (C) 2002 Microsoft Corporation +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" +// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +// OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY +// AND/OR FITNESS FOR A PARTICULAR PURPOSE. +// +// Date - 10/08/2002 +// Author - Sanj Surati + +///////////////////////////////////////////////////////////// +// +// SPNEGOPARSE.C +// +// SPNEGO Token Handler Source File +// +// Contains implementation of SPNEGO Token parsing functions. +// +///////////////////////////////////////////////////////////// + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <stdio.h> +#include <memory.h> +#include "spnego.h" +#include "derparse.h" +#include "spnegoparse.h" + +// +// Defined in DERPARSE.C +// + +extern MECH_OID g_stcMechOIDList []; + +/**********************************************************************/ +/** **/ +/** **/ +/** **/ +/** **/ +/** Local SPNEGO Helper definitions **/ +/** **/ +/** **/ +/** **/ +/** **/ +/**********************************************************************/ + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// CalculateMinSpnegoInitTokenSize +// +// Parameters: +// [in] nMechTokenLength - Length of the MechToken Element +// [in] nMechListMICLength - Length of the MechListMIC Element +// [in] mechOID - OID for MechList +// [in] nReqFlagsAvailable - Is ContextFlags element available +// [out] pnTokenSize - Filled out with total size of token +// [out] pnInternalTokenLength - Filled out with length minus length +// for initial token. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Calculates the required length for a SPNEGO NegTokenInit token based +// on the supplied variable length values and which elements are present. +// Note that because the lengths can be represented by an arbitrary +// number of bytes in DER encodings, we actually calculate the lengths +// backwards, so we always know how many bytes we will potentially be +// writing out. +// +//////////////////////////////////////////////////////////////////////////// + +int CalculateMinSpnegoInitTokenSize( long nMechTokenLength, + long nMechListMICLength, SPNEGO_MECH_OID mechOid, + int nReqFlagsAvailable, long* pnTokenSize, + long* pnInternalTokenLength ) +{ + int nReturn = SPNEGO_E_INVALID_LENGTH; + + // Start at 0. + long nTotalLength = 0; + long nTempLength= 0L; + + // We will calculate this by walking the token backwards + + // Start with MIC Element + if ( nMechListMICLength > 0L ) + { + nTempLength = ASNDerCalcElementLength( nMechListMICLength, NULL ); + + // Check for rollover error + if ( nTempLength < nMechListMICLength ) + { + goto xEndTokenInitLength; + } + + nTotalLength += nTempLength; + } + + // Next is the MechToken + if ( nMechTokenLength > 0L ) + { + nTempLength += ASNDerCalcElementLength( nMechTokenLength, NULL ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenInitLength; + } + + nTotalLength = nTempLength; + } + + // Next is the ReqFlags + if ( nReqFlagsAvailable ) + { + nTempLength += ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, NULL ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenInitLength; + } + + nTotalLength = nTempLength; + } + + // Next is the MechList - This is REQUIRED + nTempLength += ASNDerCalcMechListLength( mechOid, NULL ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenInitLength; + } + + nTotalLength = nTempLength; + + // Following four fields are the basic header tokens + + // Sequence Token + nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenInitLength; + } + + nTotalLength = nTempLength; + + // Neg Token Identifier Token + nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenInitLength; + } + + nTotalLength = nTempLength; + + // SPNEGO OID Token + nTempLength += g_stcMechOIDList[spnego_mech_oid_Spnego].iLen; + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenInitLength; + } + + nTotalLength = nTempLength; + + // App Constructed Token + nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenInitLength; + } + + // The internal length doesn't include the number of bytes + // for the initial token + *pnInternalTokenLength = nTotalLength; + nTotalLength = nTempLength; + + // We're done + *pnTokenSize = nTotalLength; + nReturn = SPNEGO_E_SUCCESS; + +xEndTokenInitLength: + + return nReturn; + +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// CreateSpnegoInitToken +// +// Parameters: +// [in] MechType - OID in MechList +// [in] ucContextFlags - ContextFlags value +// [in] pbMechToken - Mech Token Binary Data +// [in] ulMechTokenLen - Length of Mech Token +// [in] pbMechListMIC - MechListMIC Binary Data +// [in] ulMechListMICn - Length of MechListMIC +// [out] pbTokenData - Buffer to write token into. +// [in] nTokenLength - Length of pbTokenData buffer +// [in] nInternalTokenLength - Length of full token without leading +// token bytes. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Uses DER to fill out pbTokenData with a SPNEGO NegTokenInit Token +// Note that because the lengths can be represented by an arbitrary +// number of bytes in DER encodings, we actually calculate the lengths +// backwards, so we always know how many bytes we will potentially be +// writing out. +// +//////////////////////////////////////////////////////////////////////////// + +int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType, + unsigned char ucContextFlags, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, + unsigned long ulMechListMICLen, unsigned char* pbTokenData, + long nTokenLength, long nInternalTokenLength ) +{ + int nReturn = SPNEGO_E_INVALID_LENGTH; + + // Start at 0. + long nTempLength= 0L; + long nTotalBytesWritten = 0L; + long nInternalLength = 0L; + + unsigned char* pbWriteTokenData = pbTokenData + nTokenLength; + + // Temporary buffer to hold the REQ Flags as BIT String Data + unsigned char abTempReqFlags[SPNEGO_NEGINIT_MAXLEN_REQFLAGS]; + + + // We will write the token out backwards to properly handle the cases + // where the length bytes become adjustable + + // Start with MIC Element + if ( ulMechListMICLen > 0L ) + { + nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC, + OCTETSTRING, pbMechListMIC, ulMechListMICLen ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenInit; + } + + } // IF MechListMIC is present + + // Next is the MechToken + if ( ulMechTokenLen > 0L ) + { + nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHTOKEN, + OCTETSTRING, pbMechToken, ulMechTokenLen ); + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenInit; + } + + } // IF MechToken Length is present + + // Next is the ReqFlags + if ( ucContextFlags > 0L ) + { + + nTempLength = ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, &nInternalLength ); + + // We need a byte that indicates how many bits difference between the number + // of bits used in final octet (we only have one) and the max (8) + + abTempReqFlags[0] = SPNEGO_NEGINIT_REQFLAGS_BITDIFF; + abTempReqFlags[1] = ucContextFlags; + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_REQFLAGS, + BITSTRING, abTempReqFlags, SPNEGO_NEGINIT_MAXLEN_REQFLAGS ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenInit; + } + + } // IF ContextFlags + + // Next is the MechList - This is REQUIRED + nTempLength = ASNDerCalcMechListLength( MechType, &nInternalLength ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteMechList( pbWriteTokenData, MechType ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenInit; + } + + // The next tokens we're writing out reflect the total number of bytes + // we have actually written out. + + // Sequence Token + nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, + NULL, nTotalBytesWritten ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenInit; + } + + // Neg Init Token Identifier Token + nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER, + NULL, nTotalBytesWritten ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenInit; + } + + // SPNEGO OID Token + nTempLength = g_stcMechOIDList[spnego_mech_oid_Spnego].iLen; + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteOID( pbWriteTokenData, spnego_mech_oid_Spnego ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenInit; + } + + // App Constructed Token + nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT, + NULL, nTotalBytesWritten ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + + // Don't adjust the internal token length here, it doesn't account + // the initial bytes written out (we really don't need to keep + // a running count here, but for debugging, it helps to be able + // to see the total number of bytes written out as well as the + // number of bytes left to write). + + if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 && + pbWriteTokenData == pbTokenData ) + { + nReturn = SPNEGO_E_SUCCESS; + } + +xEndWriteNegTokenInit: + + return nReturn; + +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// CalculateMinSpnegoTargTokenSize +// +// Parameters: +// [in] MechType - Supported MechType +// [in] spnegoNegResult - Neg Result +// [in] nMechTokenLength - Length of the MechToken Element +// [in] nMechListMICLength - Length of the MechListMIC Element +// [out] pnTokenSize - Filled out with total size of token +// [out] pnInternalTokenLength - Filled out with length minus length +// for initial token. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Calculates the required length for a SPNEGO NegTokenTarg token based +// on the supplied variable length values and which elements are present. +// Note that because the lengths can be represented by an arbitrary +// number of bytes in DER encodings, we actually calculate the lengths +// backwards, so we always know how many bytes we will potentially be +// writing out. +// +//////////////////////////////////////////////////////////////////////////// + +int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType, + SPNEGO_NEGRESULT spnegoNegResult, long nMechTokenLen, + long nMechListMICLen, long* pnTokenSize, + long* pnInternalTokenLength ) +{ + int nReturn = SPNEGO_E_INVALID_LENGTH; + + // Start at 0. + long nTotalLength = 0; + long nTempLength= 0L; + + // We will calculate this by walking the token backwards + + // Start with MIC Element + if ( nMechListMICLen > 0L ) + { + nTempLength = ASNDerCalcElementLength( nMechListMICLen, NULL ); + + // Check for rollover error + if ( nTempLength < nMechListMICLen ) + { + goto xEndTokenTargLength; + } + + nTotalLength += nTempLength; + } + + // Next is the MechToken + if ( nMechTokenLen > 0L ) + { + nTempLength += ASNDerCalcElementLength( nMechTokenLen, NULL ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenTargLength; + } + + nTotalLength = nTempLength; + } + + // Supported MechType + if ( spnego_mech_oid_NotUsed != MechType ) + { + // Supported MechOID element - we use the token function since + // we already know the size of the OID token and value + nTempLength += ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen, + NULL ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenTargLength; + } + + nTotalLength = nTempLength; + + } // IF MechType is available + + // NegResult Element + if ( spnego_negresult_NotUsed != spnegoNegResult ) + { + nTempLength += ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, NULL ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenTargLength; + } + + nTotalLength = nTempLength; + + } // IF negResult is available + + // Following two fields are the basic header tokens + + // Sequence Token + nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenTargLength; + } + + nTotalLength = nTempLength; + + // Neg Token Identifier Token + nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L ); + + // Check for rollover error + if ( nTempLength < nTotalLength ) + { + goto xEndTokenTargLength; + } + + // The internal length doesn't include the number of bytes + // for the initial token + *pnInternalTokenLength = nTotalLength; + nTotalLength = nTempLength; + + // We're done + *pnTokenSize = nTotalLength; + nReturn = SPNEGO_E_SUCCESS; + +xEndTokenTargLength: + + return nReturn; + +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// CreateSpnegoTargToken +// +// Parameters: +// [in] MechType - Supported MechType +// [in] eNegResult - NegResult value +// [in] pbMechToken - Mech Token Binary Data +// [in] ulMechTokenLen - Length of Mech Token +// [in] pbMechListMIC - MechListMIC Binary Data +// [in] ulMechListMICn - Length of MechListMIC +// [out] pbTokenData - Buffer to write token into. +// [in] nTokenLength - Length of pbTokenData buffer +// [in] nInternalTokenLength - Length of full token without leading +// token bytes. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Uses DER to fill out pbTokenData with a SPNEGO NegTokenTarg Token +// Note that because the lengths can be represented by an arbitrary +// number of bytes in DER encodings, we actually calculate the lengths +// backwards, so we always know how many bytes we will potentially be +// writing out. +// +//////////////////////////////////////////////////////////////////////////// + +int CreateSpnegoTargToken( SPNEGO_MECH_OID MechType, + SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, + unsigned long ulMechListMICLen, unsigned char* pbTokenData, + long nTokenLength, long nInternalTokenLength ) +{ + int nReturn = SPNEGO_E_INVALID_LENGTH; + + // Start at 0. + long nTempLength= 0L; + long nTotalBytesWritten = 0L; + long nInternalLength = 0L; + + unsigned char ucTemp = 0; + + // We will write the token out backwards to properly handle the cases + // where the length bytes become adjustable, so the write location + // is initialized to point *just* past the end of the buffer. + + unsigned char* pbWriteTokenData = pbTokenData + nTokenLength; + + + // Start with MIC Element + if ( ulMechListMICLen > 0L ) + { + nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC, + OCTETSTRING, pbMechListMIC, ulMechListMICLen ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenTarg; + } + + } // IF MechListMIC is present + + // Next is the MechToken + if ( ulMechTokenLen > 0L ) + { + nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN, + OCTETSTRING, pbMechToken, ulMechTokenLen ); + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenTarg; + } + + } // IF MechToken Length is present + + // Supported Mech Type + if ( spnego_mech_oid_NotUsed != MechType ) + { + + nTempLength = ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen, + &nInternalLength ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH, + g_stcMechOIDList[MechType].ucOid, + g_stcMechOIDList[MechType].iLen ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenTarg; + } + + } // IF MechType is present + + // Neg Result + // NegResult Element + if ( spnego_negresult_NotUsed != eNegResult ) + { + ucTemp = (unsigned char) eNegResult; + + nTempLength = ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, &nInternalLength ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_NEGRESULT, + ENUMERATED, &ucTemp, SPNEGO_NEGTARG_MAXLEN_NEGRESULT ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenTarg; + } + + } // If eNegResult is available + + // The next tokens we're writing out reflect the total number of bytes + // we have actually written out. + + // Sequence Token + nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, + NULL, nTotalBytesWritten ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + nInternalTokenLength -= nTempLength; + + if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 ) + { + goto xEndWriteNegTokenTarg; + } + + // Neg Targ Token Identifier Token + nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L ); + + // Decrease the pbWriteTokenData, now we know the length and + // write it out. + pbWriteTokenData -= nTempLength; + nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER, + NULL, nTotalBytesWritten ); + + // Adjust Values and sanity check + nTotalBytesWritten += nTempLength; + + // Don't adjust the internal token length here, it doesn't account + // the initial bytes written out (we really don't need to keep + // a running count here, but for debugging, it helps to be able + // to see the total number of bytes written out as well as the + // number of bytes left to write). + + if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 && + pbWriteTokenData == pbTokenData ) + { + nReturn = SPNEGO_E_SUCCESS; + } + + +xEndWriteNegTokenTarg: + + return nReturn; + + +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// AllocEmptySpnegoToken +// +// Parameters: +// [in] ucCopyData - Flag to copy data or pointer. +// [in] ulFlags - Flags for SPNEGO_TOKEN data member. +// [in] pbTokenData - Binary token data. +// [in] ulTokenSize - Size of pbTokenData. +// +// Returns: +// SPNEGO_TOKEN* Success - Pointer to initialized SPNEGO_TOKEN struct +// Failure - NULL +// +// Comments : +// Allocates a SPNEGO_TOKEN data structure and initializes it. Based on +// the value of ucCopyData, if non-zero, we copy the data into a buffer +// we allocate in this function, otherwise, we copy the data pointer +// direcly. +// +//////////////////////////////////////////////////////////////////////////// + +SPNEGO_TOKEN* AllocEmptySpnegoToken( unsigned char ucCopyData, unsigned long ulFlags, + unsigned char * pbTokenData, unsigned long ulTokenSize ) +{ + SPNEGO_TOKEN* pSpnegoToken = (SPNEGO_TOKEN*) calloc( 1, sizeof(SPNEGO_TOKEN) ); + + if ( NULL != pSpnegoToken ) + { + // Set the token size + pSpnegoToken->nStructSize = SPNEGO_TOKEN_SIZE; + + // Initialize the element array + InitSpnegoTokenElementArray( pSpnegoToken ); + + // Assign the flags value + pSpnegoToken->ulFlags = ulFlags; + + // + // IF ucCopyData is TRUE, we will allocate a buffer and copy data into it. + // Otherwise, we will just copy the pointer and the length. This is so we + // can cut out additional allocations for performance reasons + // + + if ( SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA == ucCopyData ) + { + // Alloc the internal buffer. Cleanup on failure. + pSpnegoToken->pbBinaryData = (unsigned char*) calloc( ulTokenSize, sizeof(unsigned char) ); + + if ( NULL != pSpnegoToken->pbBinaryData ) + { + // We must ALWAYS free this buffer + pSpnegoToken->ulFlags |= SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA; + + // Copy the data locally + memcpy( pSpnegoToken->pbBinaryData, pbTokenData, ulTokenSize ); + pSpnegoToken->ulBinaryDataLen = ulTokenSize; + } + else + { + free( pSpnegoToken ); + pSpnegoToken = NULL; + } + + } // IF ucCopyData + else + { + // Copy the pointer and the length directly - ulFlags will control whether or not + // we are allowed to free the value + + pSpnegoToken->pbBinaryData = pbTokenData; + pSpnegoToken->ulBinaryDataLen = ulTokenSize; + } + + } + + return pSpnegoToken; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// FreeSpnegoToken +// +// Parameters: +// [in] pSpnegoToken - Points to SPNEGO_TOKEN to free. +// +// Returns: +// void +// +// Comments : +// If non-NULL, interprets pSpnegoToken, freeing any internal allocations +// and finally the actual structure. +// +//////////////////////////////////////////////////////////////////////////// + +void FreeSpnegoToken( SPNEGO_TOKEN* pSpnegoToken ) +{ + if ( NULL != pSpnegoToken ) + { + + // Cleanup internal allocation per the flags + if ( pSpnegoToken->ulFlags & SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA && + NULL != pSpnegoToken->pbBinaryData ) + { + free( pSpnegoToken->pbBinaryData ); + pSpnegoToken->pbBinaryData = NULL; + } + + free ( pSpnegoToken ); + } +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// InitSpnegoTokenElementArray +// +// Parameters: +// [in] pSpnegoToken - Points to SPNEGO_TOKEN structure. +// +// Returns: +// void +// +// Comments : +// Initializes the element array data member of a SPNEGO_TOKEN data +// structure. +// +//////////////////////////////////////////////////////////////////////////// + +void InitSpnegoTokenElementArray( SPNEGO_TOKEN* pSpnegoToken ) +{ + int nCtr; + + // Set the number of elemnts + pSpnegoToken->nNumElements = MAX_NUM_TOKEN_ELEMENTS; + + // + // Initially, all elements are unavailable + // + + for ( nCtr = 0; nCtr < MAX_NUM_TOKEN_ELEMENTS; nCtr++ ) + { + // Set the element size as well + pSpnegoToken->aElementArray[ nCtr ].nStructSize = SPNEGO_ELEMENT_SIZE; + pSpnegoToken->aElementArray[ nCtr ].iElementPresent = SPNEGO_TOKEN_ELEMENT_UNAVAILABLE; + } + +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// InitSpnegoTokenType +// +// Parameters: +// [in] pSpnegoToken - Points to SPNEGO_TOKEN structure. +// [out] pnTokenLength - Filled out with total token length +// [out] pnRemainingTokenLength - Filled out with remaining length +// after header is parsed +// [out] ppbFirstElement - Filled out with pointer to first +// element after header info. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Walks the underlying binary data for a SPNEGO_TOKEN data structure +// and determines the type of the underlying token based on token header +// information. +// +//////////////////////////////////////////////////////////////////////////// + +int InitSpnegoTokenType( SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength, + long* pnRemainingTokenLength, unsigned char** ppbFirstElement ) +{ + int nReturn = SPNEGO_E_INVALID_TOKEN; + long nActualTokenLength = 0L; + long nBoundaryLength = pSpnegoToken->ulBinaryDataLen; + unsigned char* pbTokenData = pSpnegoToken->pbBinaryData; + + // + // First byte MUST be either an APP_CONSTRUCT or the NEGTARG_TOKEN_TARG + // + + if ( SPNEGO_NEGINIT_APP_CONSTRUCT == *pbTokenData ) + { + // Validate the above token - this will tell us the actual length of the token + // per the encoding (minus the actual token bytes) + if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT, 0L, nBoundaryLength, + pnTokenLength, &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Initialize the remaining token length value. This will be used + // to tell the caller how much token there is left once we've parsed + // the header (they could calculate it from the other values, but this + // is a bit friendlier) + *pnRemainingTokenLength = *pnTokenLength; + + // Make adjustments to next token + pbTokenData += nActualTokenLength; + nBoundaryLength -= nActualTokenLength; + + // The next token should be an OID + if ( ( nReturn = ASNDerCheckOID( pbTokenData, spnego_mech_oid_Spnego, nBoundaryLength, + &nActualTokenLength ) ) == SPNEGO_E_SUCCESS ) + { + // Make adjustments to next token + pbTokenData += nActualTokenLength; + nBoundaryLength -= nActualTokenLength; + *pnRemainingTokenLength -= nActualTokenLength; + + // The next token should specify the NegTokenInit + if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER, + *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, + &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Make adjustments to next token + pbTokenData += nActualTokenLength; + nBoundaryLength -= nActualTokenLength; + *pnRemainingTokenLength -= nActualTokenLength; + + // The next token should specify the start of a sequence + if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, + *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, + &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // NegTokenInit header is now checked out! + + // Make adjustments to next token + *pnRemainingTokenLength -= nActualTokenLength; + + // Store pointer to first element + *ppbFirstElement = pbTokenData + nActualTokenLength; + pSpnegoToken->ucTokenType = SPNEGO_TOKEN_INIT; + } // IF Check Sequence Token + + } // IF Check NegTokenInit token + + + } // IF Check for SPNEGO OID + + + } // IF check app construct token + + } + else if ( SPNEGO_NEGTARG_TOKEN_IDENTIFIER == *pbTokenData ) + { + + // The next token should specify the NegTokenInit + if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER, + *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, + &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Initialize the remaining token length value. This will be used + // to tell the caller how much token there is left once we've parsed + // the header (they could calculate it from the other values, but this + // is a bit friendlier) + *pnRemainingTokenLength = *pnTokenLength; + + // Make adjustments to next token + pbTokenData += nActualTokenLength; + nBoundaryLength -= nActualTokenLength; + + // The next token should specify the start of a sequence + if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, + *pnRemainingTokenLength, nBoundaryLength, pnTokenLength, + &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // NegTokenInit header is now checked out! + + // Make adjustments to next token + *pnRemainingTokenLength -= nActualTokenLength; + + // Store pointer to first element + *ppbFirstElement = pbTokenData + nActualTokenLength; + pSpnegoToken->ucTokenType = SPNEGO_TOKEN_TARG; + } // IF Check Sequence Token + + } // IF Check NegTokenInit token + + } // ELSE IF it's a NegTokenTarg + + return nReturn; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// GetSpnegoInitTokenMechList +// +// Parameters: +// [in] pbTokenData - Points to binary MechList element +// in NegTokenInit. +// [in] nMechListLength - Length of the MechList +// [out] pSpnegoElement - Filled out with MechList Element +// data. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Checks that pbTokenData is pointing at something that at least +// *looks* like a MechList and then fills out the supplied +// SPNEGO_ELEMENT structure. +// +//////////////////////////////////////////////////////////////////////////// + +int GetSpnegoInitTokenMechList( unsigned char* pbTokenData, int nMechListLength, + SPNEGO_ELEMENT* pSpnegoElement ) +{ + int nReturn = SPNEGO_E_INVALID_TOKEN; + long nLength = 0L; + long nActualTokenLength = 0L; + + // Actual MechList is prepended by a Constructed Sequence Token + if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE, + nMechListLength, nMechListLength, + &nLength, &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Adjust for this token + nMechListLength -= nActualTokenLength; + pbTokenData += nActualTokenLength; + + // Perform simple validation of the actual MechList (i.e. ensure that + // the OIDs in the MechList are reasonable). + + if ( ( nReturn = ValidateMechList( pbTokenData, nLength ) ) == SPNEGO_E_SUCCESS ) + { + // Initialize the element now + pSpnegoElement->eElementType = spnego_init_mechtypes; + pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; + pSpnegoElement->type = SPNEGO_MECHLIST_TYPE; + pSpnegoElement->nDatalength = nLength; + pSpnegoElement->pbData = pbTokenData; + } + + } // IF Check Token + + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// InitSpnegoTokenElementFromBasicType +// +// Parameters: +// [in] pbTokenData - Points to binary element data in +// a SPNEGO token. +// [in] nElementLength - Length of the element +// [in] ucExpectedType - Expected DER type. +// [in] spnegoElementType - Which element is this? +// [out] pSpnegoElement - Filled out with element data. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Checks that pbTokenData is pointing at the specified DER type. If so, +// then we verify that lengths are proper and then fill out the +// SPNEGO_ELEMENT data structure. +// +//////////////////////////////////////////////////////////////////////////// + +int InitSpnegoTokenElementFromBasicType( unsigned char* pbTokenData, int nElementLength, + unsigned char ucExpectedType, + SPNEGO_ELEMENT_TYPE spnegoElementType, + SPNEGO_ELEMENT* pSpnegoElement ) +{ + int nReturn = SPNEGO_E_UNEXPECTED_TYPE; + long nLength = 0L; + long nActualTokenLength = 0L; + + // The type BYTE must match our token data or something is badly wrong + if ( *pbTokenData == ucExpectedType ) + { + + // Check that we are pointing at the specified type + if ( ( nReturn = ASNDerCheckToken( pbTokenData, ucExpectedType, + nElementLength, nElementLength, + &nLength, &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Adjust for this token + nElementLength -= nActualTokenLength; + pbTokenData += nActualTokenLength; + + // Initialize the element now + pSpnegoElement->eElementType = spnegoElementType; + pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; + pSpnegoElement->type = ucExpectedType; + pSpnegoElement->nDatalength = nLength; + pSpnegoElement->pbData = pbTokenData; + } + + } // IF type makes sense + + return nReturn; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// InitSpnegoTokenElementFromOID +// +// Parameters: +// [in] pbTokenData - Points to binary element data in +// a SPNEGO token. +// [in] nElementLength - Length of the element +// [in] spnegoElementType - Which element is this? +// [out] pSpnegoElement - Filled out with element data. +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Initializes a SpnegoElement from an OID - normally, this would have +// used the Basic Type function above, but since we do binary compares +// on the OIDs against the DER information as well as the OID, we need +// to account for that. +// +//////////////////////////////////////////////////////////////////////////// + +int InitSpnegoTokenElementFromOID( unsigned char* pbTokenData, int nElementLength, + SPNEGO_ELEMENT_TYPE spnegoElementType, + SPNEGO_ELEMENT* pSpnegoElement ) +{ + int nReturn = SPNEGO_E_UNEXPECTED_TYPE; + long nLength = 0L; + long nActualTokenLength = 0L; + + // The type BYTE must match our token data or something is badly wrong + if ( *pbTokenData == OID ) + { + + // Check that we are pointing at an OID type + if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID, + nElementLength, nElementLength, + &nLength, &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + // Don't adjust any values for this function + + // Initialize the element now + pSpnegoElement->eElementType = spnegoElementType; + pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE; + pSpnegoElement->type = OID; + pSpnegoElement->nDatalength = nElementLength; + pSpnegoElement->pbData = pbTokenData; + } + + } // IF type makes sense + + return nReturn; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// InitSpnegoTokenElements +// +// Parameters: +// [in] pSpnegoToken - Points to SPNEGO_TOKEN struct +// [in] pbTokenData - Points to initial binary element +// data in a SPNEGO token. +// [in] nRemainingTokenLength - Length remaining past header +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Interprets the data at pbTokenData based on the TokenType in +// pSpnegoToken. Since some elements are optional (technically all are +// but the token becomes quite useless if this is so), we check if +// an element exists before filling out the element in the array. +// +//////////////////////////////////////////////////////////////////////////// + +int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData, + long nRemainingTokenLength ) +{ + // + // The following arrays contain the token identifiers for the elements + // comprising the actual token. All values are optional, and there are + // no defaults. + // + + static unsigned char abNegTokenInitElements[] = + { SPNEGO_NEGINIT_ELEMENT_MECHTYPES, SPNEGO_NEGINIT_ELEMENT_REQFLAGS, + SPNEGO_NEGINIT_ELEMENT_MECHTOKEN, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC }; + + static unsigned char abNegTokenTargElements[] = + { SPNEGO_NEGTARG_ELEMENT_NEGRESULT, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH, + SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC }; + + int nReturn = SPNEGO_E_SUCCESS; + int nCtr = 0L; + long nElementLength = 0L; + long nActualTokenLength = 0L; + unsigned char* pbElements = NULL; + unsigned char * ptok; + long tlen, elen, len; + + // Point to the correct array + switch( pSpnegoToken->ucTokenType ) + { + case SPNEGO_TOKEN_INIT: + { + pbElements = abNegTokenInitElements; + } + break; + + case SPNEGO_TOKEN_TARG: + { + pbElements = abNegTokenTargElements; + } + break; + + } // SWITCH tokentype + + // + // Enumerate the element arrays and look for the tokens at our current location + // + + for ( nCtr = 0L; + SPNEGO_E_SUCCESS == nReturn && + nCtr < MAX_NUM_TOKEN_ELEMENTS && + nRemainingTokenLength > 0L; + nCtr++ ) + { + + // Check if the token exists + if ( ( nReturn = ASNDerCheckToken( pbTokenData, pbElements[nCtr], + 0L, nRemainingTokenLength, + &nElementLength, &nActualTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + + // Token data should skip over the sequence token and then + // call the appropriate function to initialize the element + pbTokenData += nActualTokenLength; + + // Lengths in the elements should NOT go beyond the element + // length + + // Different tokens mean different elements + if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) + { + + // Handle each element as appropriate + switch( pbElements[nCtr] ) + { + + case SPNEGO_NEGINIT_ELEMENT_MECHTYPES: + { + // + // This is a Mech List that specifies which OIDs the + // originator of the Init Token supports. + // + + nReturn = GetSpnegoInitTokenMechList( pbTokenData, nElementLength, + &pSpnegoToken->aElementArray[nCtr] ); + + } + break; + + case SPNEGO_NEGINIT_ELEMENT_REQFLAGS: + { + // + // This is a BITSTRING which specifies the flags that the receiver + // pass to the gss_accept_sec_context() function. + // + + nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, + BITSTRING, spnego_init_reqFlags, + &pSpnegoToken->aElementArray[nCtr] ); + } + break; + + case SPNEGO_NEGINIT_ELEMENT_MECHTOKEN: + { + // + // This is an OCTETSTRING which contains a GSSAPI token corresponding + // to the first OID in the MechList. + // + + nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, + OCTETSTRING, spnego_init_mechToken, + &pSpnegoToken->aElementArray[nCtr] ); + } + break; + + case SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC: + { + // + // This is an OCTETSTRING which contains a message integrity BLOB. + // + + nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, + OCTETSTRING, spnego_init_mechListMIC, + &pSpnegoToken->aElementArray[nCtr] ); + /* + * don't believe everything you read in RFCs (and MS + * sample code)... win2k is sending not an octet string, + * but a "general string", wrapped in a sequence. + */ + if (nReturn != SPNEGO_E_UNEXPECTED_TYPE) + break; + ptok = pbTokenData; + elen = nElementLength; + if ((nReturn = ASNDerCheckToken(ptok, SPNEGO_CONSTRUCTED_SEQUENCE, elen, elen, &len, &tlen)) != SPNEGO_E_SUCCESS) + break; + elen -= tlen; + ptok += tlen; + + if ((nReturn = ASNDerCheckToken(ptok, SEQ_ELM(0), elen, elen, &len, &tlen)) != SPNEGO_E_SUCCESS) + break; + elen -= tlen; + ptok += tlen; + nReturn = InitSpnegoTokenElementFromBasicType(ptok, elen, GENERALSTR, spnego_init_mechListMIC, &pSpnegoToken->aElementArray[nCtr]); + } + break; + + } // SWITCH Element + } + else + { + + switch( pbElements[nCtr] ) + { + + case SPNEGO_NEGTARG_ELEMENT_NEGRESULT: + { + // + // This is an ENUMERATION which specifies result of the last GSS + // token negotiation call. + // + + nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, + ENUMERATED, spnego_targ_negResult, + &pSpnegoToken->aElementArray[nCtr] ); + } + break; + + case SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH: + { + // + // This is an OID which specifies a supported mechanism. + // + + nReturn = InitSpnegoTokenElementFromOID( pbTokenData, nElementLength, + spnego_targ_mechListMIC, + &pSpnegoToken->aElementArray[nCtr] ); + } + break; + + case SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN: + { + // + // This is an OCTETSTRING which specifies results of the last GSS + // token negotiation call. + // + + nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, + OCTETSTRING, spnego_targ_responseToken, + &pSpnegoToken->aElementArray[nCtr] ); + } + break; + + case SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC: + { + // + // This is an OCTETSTRING which specifies a message integrity BLOB. + // + + nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength, + OCTETSTRING, spnego_targ_mechListMIC, + &pSpnegoToken->aElementArray[nCtr] ); + } + break; + + } // SWITCH Element + + } // ELSE !NegTokenInit + + // Account for the entire token and following data + nRemainingTokenLength -= ( nActualTokenLength + nElementLength ); + + // Token data should skip past the element length now + pbTokenData += nElementLength; + + } // IF Token found + else if ( SPNEGO_E_TOKEN_NOT_FOUND == nReturn ) + { + // For now, this is a benign error (remember, all elements are optional, so + // if we don't find one, it's okay). + + nReturn = SPNEGO_E_SUCCESS; + } + + } // FOR enum elements + + // + // We should always run down to 0 remaining bytes in the token. If not, we've got + // a bad token. + // + + if ( SPNEGO_E_SUCCESS == nReturn && nRemainingTokenLength != 0L ) + { + nReturn = SPNEGO_E_INVALID_TOKEN; + } + + return nReturn; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// FindMechOIDInMechList +// +// Parameters: +// [in] pSpnegoElement - SPNEGO_ELEMENT for MechList +// [in] MechOID - OID we're looking for. +// [out] piMechTypeIndex - Index in the list where OID was +// found +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Walks the MechList for MechOID. When it is found, the index in the +// list is written to piMechTypeIndex. +// +//////////////////////////////////////////////////////////////////////////// + +int FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID, + int * piMechTypeIndex ) +{ + int nReturn = SPNEGO_E_NOT_FOUND; + int nCtr = 0; + long nLength = 0L; + long nBoundaryLength = pSpnegoElement->nDatalength; + unsigned char* pbMechListData = pSpnegoElement->pbData; + + while( SPNEGO_E_SUCCESS != nReturn && nBoundaryLength > 0L ) + { + + // Use the helper function to check the OID + if ( ( nReturn = ASNDerCheckOID( pbMechListData, MechOID, nBoundaryLength, &nLength ) ) + == SPNEGO_E_SUCCESS ) + { + *piMechTypeIndex = nCtr; + } + + // Adjust for the current OID + pbMechListData += nLength; + nBoundaryLength -= nLength; + nCtr++; + + } // WHILE enuming OIDs + + return nReturn; + +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// ValidateMechList +// +// Parameters: +// [in] pbMechListData - Pointer to binary MechList data +// [in] nBoundaryLength - Length we must not exceed +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Checks the data at pbMechListData to see if it looks like a MechList. +// As part of this, we walk the list and ensure that none of the OIDs +// have a length that takes us outside of nBoundaryLength. +// +//////////////////////////////////////////////////////////////////////////// + +int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength ) +{ + int nReturn = SPNEGO_E_SUCCESS; + long nLength = 0L; + long nTokenLength = 0L; + + while( SPNEGO_E_SUCCESS == nReturn && nBoundaryLength > 0L ) + { + // Verify that we have something that at least *looks* like an OID - in other + // words it has an OID identifier and specifies a length that doesn't go beyond + // the size of the list. + nReturn = ASNDerCheckToken( pbMechListData, OID, 0L, nBoundaryLength, + &nLength, &nTokenLength ); + + // Adjust for the current OID + pbMechListData += ( nLength + nTokenLength ); + nBoundaryLength -= ( nLength + nTokenLength ); + + } // WHILE enuming OIDs + + return nReturn; + +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// IsValidMechOid +// +// Parameters: +// [in] mechOid - mechOID id enumeration +// +// Returns: +// int Success - 1 +// Failure - 0 +// +// Comments : +// Checks for a valid mechOid value. +// +//////////////////////////////////////////////////////////////////////////// + +int IsValidMechOid( SPNEGO_MECH_OID mechOid ) +{ + return ( mechOid >= spnego_mech_oid_Kerberos_V5_Legacy && + mechOid <= spnego_mech_oid_Spnego ); +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// IsValidContextFlags +// +// Parameters: +// [in] ucContextFlags - ContextFlags value +// +// Returns: +// int Success - 1 +// Failure - 0 +// +// Comments : +// Checks for a valid ContextFlags value. +// +//////////////////////////////////////////////////////////////////////////// + +int IsValidContextFlags( unsigned char ucContextFlags ) +{ + // Mask out our valid bits. If there is anything leftover, this + // is not a valid value for Context Flags + return ( ( ucContextFlags & ~SPNEGO_NEGINIT_CONTEXT_MASK ) == 0 ); +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// IsValidNegResult +// +// Parameters: +// [in] negResult - NegResult value +// +// Returns: +// int Success - 1 +// Failure - 0 +// +// Comments : +// Checks for a valid NegResult value. +// +//////////////////////////////////////////////////////////////////////////// + +int IsValidNegResult( SPNEGO_NEGRESULT negResult ) +{ + return ( negResult >= spnego_negresult_success && + negResult <= spnego_negresult_rejected ); +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// IsValidSpnegoToken +// +// Parameters: +// [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure +// +// Returns: +// int Success - 1 +// Failure - 0 +// +// Comments : +// Performs simple heuristic on location pointed to by pSpnegoToken. +// +//////////////////////////////////////////////////////////////////////////// + +int IsValidSpnegoToken( SPNEGO_TOKEN* pSpnegoToken ) +{ + int nReturn = 0; + + // Parameter should be non-NULL + if ( NULL != pSpnegoToken ) + { + // Length should be at least the size defined in the header + if ( pSpnegoToken->nStructSize >= SPNEGO_TOKEN_SIZE ) + { + // Number of elements should be >= our maximum - if it's greater, that's + // okay, since we'll only be accessing the elements up to MAX_NUM_TOKEN_ELEMENTS + if ( pSpnegoToken->nNumElements >= MAX_NUM_TOKEN_ELEMENTS ) + { + // Check for proper token type + if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType || + SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType ) + { + nReturn = 1; + } + } + + } // IF struct size makes sense + + } // IF non-NULL spnego Token + + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// IsValidSpnegoElement +// +// Parameters: +// [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure +// [in] spnegoElement - spnegoElement Type from enumeration +// +// Returns: +// int Success - 1 +// Failure - 0 +// +// Comments : +// Checks that spnegoElement has a valid value and is appropriate for +// the SPNEGO token encapsulated by pSpnegoToken. +// +//////////////////////////////////////////////////////////////////////////// + +int IsValidSpnegoElement( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement ) +{ + int nReturn = 0; + + // Check boundaries + if ( spnegoElement > spnego_element_min && + spnegoElement < spnego_element_max ) + { + + // Check for appropriateness to token type + if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) + { + nReturn = ( spnegoElement >= spnego_init_mechtypes && + spnegoElement <= spnego_init_mechListMIC ); + } + else + { + nReturn = ( spnegoElement >= spnego_targ_negResult && + spnegoElement <= spnego_targ_mechListMIC ); + } + + } // IF boundary conditions are met + + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// CalculateElementArrayIndex +// +// Parameters: +// [in] pSpnegoToken - Points to SPNEGO_TOKEN data structure +// [in] spnegoElement - spnegoElement Type from enumeration +// +// Returns: +// int index in the SPNEGO_TOKEN element array that the element can +// can be found +// +// Comments : +// Based on the Token Type, calculates the index in the element array +// at which the specified element can be found. +// +//////////////////////////////////////////////////////////////////////////// + +int CalculateElementArrayIndex( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement ) +{ + int nReturn = 0; + + // Offset is difference between value and initial element identifier + // (these differ based on ucTokenType) + + if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ) + { + nReturn = spnegoElement - spnego_init_mechtypes; + } + else + { + nReturn = spnegoElement - spnego_targ_negResult; + } + + return nReturn; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Function: +// InitTokenFromBinary +// +// Parameters: +// [in] ucCopyData - Flag indicating if data should be copied +// [in] ulFlags - Flags value for structure +// [in] pnTokenData - Binary Token Data +// [in] ulLength - Length of the data +// [out] ppSpnegoToken - Pointer to call allocated SPNEGO Token +// data structure +// +// Returns: +// int Success - SPNEGO_E_SUCCESS +// Failure - SPNEGO API Error code +// +// Comments : +// Allocates a SPNEGO_TOKEN data structure and fills it out as +// appropriate based in the flags passed into the function. +// +//////////////////////////////////////////////////////////////////////////// + + +// Initializes SPNEGO_TOKEN structure from DER encoded binary data +int InitTokenFromBinary( unsigned char ucCopyData, unsigned long ulFlags, + unsigned char* pbTokenData, unsigned long ulLength, + SPNEGO_TOKEN** ppSpnegoToken ) +{ + int nReturn = SPNEGO_E_INVALID_PARAMETER; + SPNEGO_TOKEN* pSpnegoToken = NULL; + unsigned char* pbFirstElement = NULL; + long nTokenLength = 0L; + long nRemainingTokenLength = 0L; + + // Basic Parameter Validation + + if ( NULL != pbTokenData && + NULL != ppSpnegoToken && + 0L != ulLength ) + { + + // + // Allocate the empty token, then initialize the data structure. + // + + pSpnegoToken = AllocEmptySpnegoToken( ucCopyData, ulFlags, pbTokenData, ulLength ); + + if ( NULL != pSpnegoToken ) + { + + // Copy the binary data locally + + + // Initialize the token type + if ( ( nReturn = InitSpnegoTokenType( pSpnegoToken, &nTokenLength, + &nRemainingTokenLength, &pbFirstElement ) ) + == SPNEGO_E_SUCCESS ) + { + + // Initialize the element array + if ( ( nReturn = InitSpnegoTokenElements( pSpnegoToken, pbFirstElement, + nRemainingTokenLength ) ) + == SPNEGO_E_SUCCESS ) + { + *ppSpnegoToken = pSpnegoToken; + } + + } // IF Init Token Type + + // Cleanup on error condition + if ( SPNEGO_E_SUCCESS != nReturn ) + { + spnegoFreeData( pSpnegoToken ); + } + + } + else + { + nReturn = SPNEGO_E_OUT_OF_MEMORY; + } + + } // IF Valid parameters + + + return nReturn; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/spnegoparse.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,170 @@ +// Copyright (C) 2002 Microsoft Corporation +// All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" +// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +// OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY +// AND/OR FITNESS FOR A PARTICULAR PURPOSE. +// +// Date - 10/08/2002 +// Author - Sanj Surati + +///////////////////////////////////////////////////////////// +// +// SPNEGOPARSE.H +// +// SPNEGO Token Parser Header File +// +// Contains the definitions required to properly parse a +// SPNEGO token using ASN.1 DER helpers. +// +///////////////////////////////////////////////////////////// + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef __SPNEGOPARSE_H__ +#define __SPNEGOPARSE_H__ + +// C++ Specific +#if defined(__cplusplus) +extern "C" +{ +#endif + +// Indicates if we copy data when creating a SPNEGO_TOKEN structure or not +#define SPNEGO_TOKEN_INTERNAL_COPYPTR 0 +#define SPNEGO_TOKEN_INTERNAL_COPYDATA 0x1 + +// Internal flag dictates whether or not we will free the binary data when +// the SPNEG_TOKEN structure is destroyed +#define SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA 0x1 + + // +// Each SPNEGO Token Type can be broken down into a +// maximum of 4 separate elements. +// + +#define MAX_NUM_TOKEN_ELEMENTS 4 + +// +// Element offsets in the array +// + +// INIT elements +#define SPNEGO_INIT_MECHTYPES_ELEMENT 0 +#define SPNEGO_INIT_REQFLAGS_ELEMENT 1 +#define SPNEGO_INIT_MECHTOKEN_ELEMENT 2 +#define SPNEGO_INIT_MECHLISTMIC_ELEMENT 3 + +// Response elements +#define SPNEGO_TARG_NEGRESULT_ELEMENT 0 +#define SPNEGO_TARG_SUPPMECH_ELEMENT 1 +#define SPNEGO_TARG_RESPTOKEN_ELEMENT 2 +#define SPNEGO_TARG_MECHLISTMIC_ELEMENT 3 + +// +// Defines an individual SPNEGO Token Element. +// + +typedef struct SpnegoElement +{ + size_t nStructSize; // Size of the element structure + int iElementPresent; // Is the field present? Must be either + // SPNEGO_TOKEN_ELEMENT_UNAVAILABLE or + // SPNEGO_TOKEN_ELEMENT_AVAILABLE + + SPNEGO_ELEMENT_TYPE eElementType; // The Element Type + + unsigned char type; // Data Type + + unsigned char* pbData; // Points to actual Data + + unsigned long nDatalength; // Actual Data Length + +} SPNEGO_ELEMENT; + +// Structure size in case we later choose to extend the structure +#define SPNEGO_ELEMENT_SIZE sizeof(SPNEGO_ELEMENT) + +// +// Packages a SPNEGO Token Encoding. There are two types of +// encodings: NegTokenInit and NegTokenTarg. Each encoding can +// contain up to four distinct, optional elements. +// + +typedef struct SpnegoToken +{ + size_t nStructSize; // Size of the Token structure + unsigned long ulFlags; // Internal Structure Flags - Reserved! + int ucTokenType; // Token Type - Must be + // SPNEGO_TOKEN_INIT or + // SPNEGO_TOKEN_TARG + + unsigned char* pbBinaryData; // Points to binary token data + + unsigned long ulBinaryDataLen; // Length of the actual binary data + int nNumElements; // Number of elements + SPNEGO_ELEMENT aElementArray [MAX_NUM_TOKEN_ELEMENTS]; // Holds the elements for the token +} SPNEGO_TOKEN; + +// Structure size in case we later choose to extend the structure +#define SPNEGO_TOKEN_SIZE sizeof(SPNEGO_TOKEN) + +// +// Function definitions +// + +SPNEGO_TOKEN* AllocEmptySpnegoToken( unsigned char ucCopyData, unsigned long ulFlags, + unsigned char * pbTokenData, unsigned long ulTokenSize ); +void FreeSpnegoToken( SPNEGO_TOKEN* pSpnegoToken ); +void InitSpnegoTokenElementArray( SPNEGO_TOKEN* pSpnegoToken ); +int InitSpnegoTokenType( SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength, + long* pnRemainingTokenLength, unsigned char** ppbFirstElement ); +int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData, + long nRemainingTokenLength ); +int GetSpnegoInitTokenMechList( unsigned char* pbTokenData, int nMechListLength, + SPNEGO_ELEMENT* pSpnegoElement ); +int InitSpnegoTokenElementFromBasicType( unsigned char* pbTokenData, int nElementLength, + unsigned char ucExpectedType, + SPNEGO_ELEMENT_TYPE spnegoElementType, + SPNEGO_ELEMENT* pSpnegoElement ); +int InitSpnegoTokenElementFromOID( unsigned char* pbTokenData, int nElementLength, + SPNEGO_ELEMENT_TYPE spnegoElementType, + SPNEGO_ELEMENT* pSpnegoElement ); +int FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID, + int * piMechTypeIndex ); +int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength ); +int CalculateMinSpnegoInitTokenSize( long nMechTokenLength, long nMechListMICLength, + SPNEGO_MECH_OID mechOid, int nReqFlagsAvailable, + long* plTokenSize, long* plInternalLength ); +int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType, SPNEGO_NEGRESULT spnegoNegResult, + long nMechTokenLen, + long nMechTokenMIC, long* pnTokenSize, + long* pnInternalTokenLength ); +int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType, + unsigned char ucContextFlags, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, + unsigned long ulMechListMICLen, unsigned char* pbTokenData, + long nTokenLength, long nInternalTokenLength ); +int CreateSpnegoTargToken( SPNEGO_MECH_OID MechType, + SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken, + unsigned long ulMechTokenLen, unsigned char* pbMechListMIC, + unsigned long ulMechListMICLen, unsigned char* pbTokenData, + long nTokenLength, long nInternalTokenLength ); +int IsValidMechOid( SPNEGO_MECH_OID mechOid ); +int IsValidContextFlags( unsigned char ucContextFlags ); +int IsValidNegResult( SPNEGO_NEGRESULT negResult ); +int IsValidSpnegoToken( SPNEGO_TOKEN* pSpnegoToken ); +int IsValidSpnegoElement( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement ); +int CalculateElementArrayIndex( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement ); +int InitTokenFromBinary( unsigned char ucCopyData, unsigned long ulFlags, + unsigned char* pbTokenData, unsigned long ulLength, + SPNEGO_TOKEN** ppSpnegoToken ); + + // C++ Specific +#if defined(__cplusplus) +} +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/subr.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2000, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: subr.c,v 1.19 2005/02/09 00:23:45 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/syscall.h> +#include <sys/wait.h> +#include <sys/debug.h> + +#include <unistd.h> +#include <ctype.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <errno.h> +#include <sysexits.h> +#include <libintl.h> + +#include <netsmb/netbios.h> +#include <netsmb/smb_lib.h> +#include <netsmb/nb_lib.h> +#include <cflib.h> +#include <err.h> + +uid_t real_uid, eff_uid; + +static int smblib_initialized; + +struct rcfile *smb_rc; + +int +smb_lib_init(void) +{ + int error; + + if (smblib_initialized) + return (0); + if ((error = nls_setlocale("")) != 0) { + fprintf(stdout, dgettext(TEXT_DOMAIN, + "%s: can't initialise locale\n"), __progname); + return (error); + } + smblib_initialized++; + return (0); +} + +/* + * Private version of strerror(3C) that + * knows our special error codes. + */ +char * +smb_strerror(int err) +{ + char *msg; + + switch (err) { + case EBADRPC: + msg = dgettext(TEXT_DOMAIN, + "remote call failed"); + break; + case EAUTH: + msg = dgettext(TEXT_DOMAIN, + "authentication failed"); + break; + default: + msg = strerror(err); + break; + } + + return (msg); +} + +/* + * Print a (descriptive) error message + * error values: + * 0 - no specific error code available; + * 1..32767 - system error + */ +void +smb_error(const char *fmt, int error, ...) { + va_list ap; + const char *cp; + int errtype; + + fprintf(stderr, "%s: ", __progname); + va_start(ap, error); + vfprintf(stderr, fmt, ap); + va_end(ap); + if (error == -1) { + error = errno; + errtype = SMB_SYS_ERROR; + } else { + errtype = error & SMB_ERRTYPE_MASK; + error &= ~SMB_ERRTYPE_MASK; + } + switch (errtype) { + case SMB_SYS_ERROR: + if (error) + fprintf(stderr, ": syserr = %s\n", smb_strerror(error)); + else + fprintf(stderr, "\n"); + break; + case SMB_RAP_ERROR: + fprintf(stderr, ": raperr = %d (0x%04x)\n", error, error); + break; + case SMB_NB_ERROR: + cp = nb_strerror(error); + if (cp == NULL) + fprintf(stderr, ": nberr = unknown (0x%04x)\n", error); + else + fprintf(stderr, ": nberr = %s\n", cp); + break; + default: + fprintf(stderr, "\n"); + } +} + +char * +smb_printb(char *dest, int flags, const struct smb_bitname *bnp) { + int first = 1; + + strcpy(dest, "<"); + for (; bnp->bn_bit; bnp++) { + if (flags & bnp->bn_bit) { + strcat(dest, bnp->bn_name); + first = 0; + } + if (!first && (flags & bnp[1].bn_bit)) + strcat(dest, "|"); + } + strcat(dest, ">"); + return (dest); +} + +extern int home_nsmbrc; + +#ifdef DEBUG +#include "queue.h" +#include "rcfile_priv.h" + +struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname); +struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname); + +void +dump_props(char *where) +{ + struct rcsection *rsp = NULL; + struct rckey *rkp = NULL; + + printf("Settings %s\n", where); + SLIST_FOREACH(rsp, &smb_rc->rf_sect, rs_next) { + printf("section=%s\n", rsp->rs_name); + fflush(stdout); + + SLIST_FOREACH(rkp, &rsp->rs_keys, rk_next) { + printf(" key=%s, value=%s\n", + rkp->rk_name, rkp->rk_value); + fflush(stdout); + } + } +} +#endif + +/* + * first read ~/.smbrc, next try to merge SMB_CFG_FILE - if that fails + * because SMB_CFG_FILE doesn't exist, try to merge OLD_SMB_CFG_FILE + */ +int +smb_open_rcfile(struct smb_ctx *ctx) +{ + char *home, *fn; + int error, len; + + smb_rc = NULL; +#ifdef DEPRECATED + fn = SMB_CFG_FILE; + error = rc_merge(fn, &smb_rc); + if (error == ENOENT) { + /* + * OK, try to read a config file in the old location. + */ + fn = OLD_SMB_CFG_FILE; + error = rc_merge(fn, &smb_rc); + } +#endif + fn = "/usr/sbin/sharectl get smbfs"; + error = rc_merge_pipe(fn, &smb_rc); + if (error != 0 && error != ENOENT) + fprintf(stderr, dgettext(TEXT_DOMAIN, + "Can't open %s: %s\n"), fn, smb_strerror(errno)); +#ifdef DEBUG + dump_props("after reading global repository"); +#endif + + home = getenv("HOME"); + if (home == NULL && ctx && ctx->ct_home) + home = ctx->ct_home; + if (home) { + len = strlen(home) + 20; + fn = malloc(len); + snprintf(fn, len, "%s/.nsmbrc", home); + home_nsmbrc = 1; + error = rc_merge(fn, &smb_rc); + if (error != 0 && error != ENOENT) { + fprintf(stderr, dgettext(TEXT_DOMAIN, + "Can't open %s: %s\n"), fn, smb_strerror(errno)); + } + free(fn); + } + home_nsmbrc = 0; +#ifdef DEBUG + dump_props("after reading user settings"); +#endif + if (smb_rc == NULL) { + return (ENOENT); + } + return (0); +} + +void +smb_simplecrypt(char *dst, const char *src) +{ + int ch, pos; + + *dst++ = '$'; + *dst++ = '$'; + *dst++ = '1'; + pos = 27; + while (*src) { + ch = *src++; + if (isascii(ch)) + ch = (isupper(ch) ? ('A' + (ch - 'A' + 13) % 26) : + islower(ch) ? ('a' + (ch - 'a' + 13) % 26) : ch); + ch ^= pos; + pos += 13; + sprintf(dst, "%02x", ch); + dst += 2; + } + *dst = 0; +} + +int +smb_simpledecrypt(char *dst, const char *src) +{ + char *ep, hexval[3]; + int len, ch, pos; + + if (strncmp(src, "$$1", 3) != 0) + return (EINVAL); + src += 3; + len = strlen(src); + if (len & 1) + return (EINVAL); + len /= 2; + hexval[2] = 0; + pos = 27; + while (len--) { + hexval[0] = *src++; + hexval[1] = *src++; + ch = strtoul(hexval, &ep, 16); + if (*ep != 0) + return (EINVAL); + ch ^= pos; + pos += 13; + if (isascii(ch)) + ch = (isupper(ch) ? ('A' + (ch - 'A' + 13) % 26) : + islower(ch) ? ('a' + (ch - 'a' + 13) % 26) : ch); + *dst++ = ch; + } + *dst = 0; + return (0); +} + + +static int +safe_execv(char *args[]) +{ + int pid; + int status; + + pid = fork(); + if (pid == 0) { + (void) execv(args[0], args); + /* Changed from errx() to fprintf(stderr) -Pavan */ + fprintf(stderr, dgettext(TEXT_DOMAIN, + "%s: execv %s failed, %s\n"), __progname, + args[0], smb_strerror(errno)); + } + if (pid == -1) { + fprintf(stderr, dgettext(TEXT_DOMAIN, "%s: fork failed, %s\n"), + __progname, smb_strerror(errno)); + return (1); + } + if (wait4(pid, &status, 0, NULL) != pid) { + fprintf(stderr, dgettext(TEXT_DOMAIN, + "%s: BUG executing %s command\n"), __progname, args[0]); + return (1); + } else if (!WIFEXITED(status)) { + fprintf(stderr, dgettext(TEXT_DOMAIN, + "%s: %s command aborted by signal %d\n"), + __progname, args[0], WTERMSIG(status)); + return (1); + } else if (WEXITSTATUS(status)) { + fprintf(stderr, dgettext(TEXT_DOMAIN, + "%s: %s command failed, exit status %d: %s\n"), + __progname, args[0], WEXITSTATUS(status), + smb_strerror(WEXITSTATUS(status))); + return (1); + } + return (0); +} + + +void +dropsuid() +{ + /* drop setuid root privs asap */ + eff_uid = geteuid(); + real_uid = getuid(); + seteuid(real_uid); +} + + +#define KEXTLOAD_COMMAND "/sbin/kextload" +#define FS_KEXT_DIR "/System/Library/Extensions/smbfs.kext" +#define FULL_KEXTNAME "com.apple.filesystems.smbfs" + + +int +loadsmbvfs() +{ + char *kextargs[] = {KEXTLOAD_COMMAND, FS_KEXT_DIR, NULL}; + int error = 0; + + /* + * temporarily revert to root (required for kextload) + */ + seteuid(eff_uid); + error = safe_execv(kextargs); + seteuid(real_uid); /* and back to real user */ + return (error); +} + +#undef __progname + +char *__progname = NULL; + +char * +smb_getprogname() +{ + char *p; + + if (__progname == NULL) { + __progname = (char *)getexecname(); + if ((p = strrchr(__progname, '/')) != 0) + __progname = p + 1; + } + return (__progname); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/smb/ui-sun.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2001 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines for interacting with the user to get credentials + * (workgroup/domain, username, password, etc.) + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <libintl.h> +#include <ctype.h> + +#include <netsmb/smb_lib.h> +#include <netsmb/smb_keychain.h> + +#define MAXLINE 127 +#define MAXPASSWD 256 /* from libc:getpass */ + +static void +smb_tty_prompt(char *prmpt, + char *buf, size_t buflen) +{ + char temp[MAXLINE+1]; + char *cp; + int ch; + + memset(temp, 0, sizeof (temp)); + + fprintf(stderr, "%s", prmpt); + cp = temp; + while ((ch = getc(stdin)) != EOF) { + if (ch == '\n' || ch == '\r') + break; + if (isspace(ch) || iscntrl(ch)) + continue; + *cp++ = ch; + if (cp == &temp[MAXLINE]) + break; + } + + /* If input empty, accept default. */ + if (cp == temp) + return; + + /* Use input as new value. */ + strncpy(buf, temp, buflen); +} + +int +smb_get_authentication( + char *dom, size_t domlen, + char *usr, size_t usrlen, + char *passwd, size_t passwdlen, + const char *systemname, struct smb_ctx *ctx) +{ + char *npw; + int error, i, kcask, kcerr; + + if (ctx->ct_flags & SMBCF_KCFOUND || ctx->ct_flags & SMBCF_KCBAD) { + ctx->ct_flags &= ~SMBCF_KCFOUND; + } else { + ctx->ct_flags &= ~(SMBCF_KCFOUND | SMBCF_KCDOMAIN); + + /* + * 1st: try lookup using system name + */ + kcerr = smbfs_keychain_chk(systemname, usr); + if (!kcerr) { + /* + * Need passwd to be not empty for existing logic. + * The string here is arbitrary (a debugging hint) + * and will be replaced in the driver by the real + * password from the keychain. + */ + strcpy(passwd, "$KC_SYSTEM"); + ctx->ct_flags |= SMBCF_KCFOUND; + if (smb_debug) { + printf("found keychain entry for" + " server/user: %s/%s\n", + systemname, usr); + } + return (0); + } + + /* + * 2nd: try lookup using domain name + */ + kcerr = smbfs_keychain_chk(dom, usr); + if (!kcerr) { + /* Need passwd to be not empty... (see above) */ + strcpy(passwd, "$KC_DOMAIN"); + ctx->ct_flags |= (SMBCF_KCFOUND | SMBCF_KCDOMAIN); + if (smb_debug) { + printf("found keychain entry for" + " domain/user: %s/%s\n", + dom, usr); + } + return (0); + } + } + + if (isatty(STDIN_FILENO)) { /* need command-line prompting? */ + if (passwd && passwd[0] == '\0') { + npw = getpassphrase(dgettext(TEXT_DOMAIN, "Password:")); + strncpy(passwd, npw, passwdlen); + } + return (0); + } + + /* + * XXX: Ask the user for help, possibly via + * GNOME dbus or some such... (todo). + */ + smb_error(dgettext(TEXT_DOMAIN, + "Cannot prompt for a password when input is redirected."), 0); + + return (ENOTTY); +} + +int +smb_browse(struct smb_ctx *ctx, int anon) +{ + /* + * Let user pick a share. + * Not supported. + */ + return (EINTR); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/sparc/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libsmbfs/sparcv9/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- a/usr/src/lib/pam_modules/Makefile Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/lib/pam_modules/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -45,12 +45,13 @@ rhosts_auth \ roles \ sample \ + smb \ + smbfs \ tsol_acct \ unix_auth \ unix_account \ unix_cred \ - unix_session \ - smb + unix_session $(CLOSED_BUILD)SUBDIRS += \ $(CLOSED)/lib/pam_modules/smartcard
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pam_modules/smbfs/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,60 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../../Makefile.lib + +TEXT_DOMAIN= SUNW_OST_SYSOSPAM +POFILE= smbfs_login.po +MSGFILES= smbfs_login.c + +# BUILDPO runs the sourcefile through the pre-processor +# make sure it can find what it needs. +$(POFILE) := CPPFLAGS += -I$(SRC)/lib/libsmbfs + +SUBDIRS= $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +_msg: $(MSGDOMAINPOFILE) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include $(SRC)/Makefile.msg.targ +include ../../Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pam_modules/smbfs/Makefile.com Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,45 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +LIBRARY= pam_smbfs_login.a +VERS= .1 +OBJECTS= smbfs_login.o + +include ../../Makefile.pam_modules + +LDLIBS += -lpam -lc -lsmbfs +CFLAGS += -I../../../libsmbfs +CFLAGS64 += -I../../../libsmbfs +LINTFLAGS += -I$(SRC)/lib/libsmbfs +LINTFLAGS64 += -I$(SRC)/lib/libsmbfs + +all: $(LIBS) + +lint: lintcheck + +include $(SRC)/lib/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pam_modules/smbfs/amd64/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pam_modules/smbfs/i386/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pam_modules/smbfs/mapfile-vers Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNW_1.1 { + global: + pam_sm_authenticate; + pam_sm_setcred; + local: + *; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pam_modules/smbfs/smbfs_login.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,165 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/varargs.h> +#include <string.h> +#include <syslog.h> +#include <stdlib.h> +#include <unistd.h> +#include <pwd.h> +#include <nss_dbdefs.h> + +#include <security/pam_appl.h> +#include <security/pam_modules.h> +#include <security/pam_impl.h> + +#include <libintl.h> +#include <passwdutil.h> + +#include <errno.h> +#include <netsmb/smb_keychain.h> + +/*ARGSUSED*/ +int +pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + return (PAM_IGNORE); +} + +/*ARGSUSED*/ +int +pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + boolean_t debug = B_FALSE; + char dom[20]; + char *user; + char *pw; + char *service; + struct passwd pwbuf; + char buf[NSS_BUFLEN_PASSWD]; + char *home; + uid_t uid; + int res = PAM_SUCCESS; + int i, mask; + + for (i = 0; i < argc; i++) { + if (strcmp(argv[i], "debug") == 0) + debug = B_TRUE; + } + + /* Since our creds don't time out, ignore a refresh. */ + if ((flags & PAM_REFRESH_CRED) != 0) + return (PAM_IGNORE); + + /* Check for unknown options */ + mask = PAM_ESTABLISH_CRED | PAM_REINITIALIZE_CRED | PAM_DELETE_CRED; + if ((flags & ~mask) != 0) + return (PAM_IGNORE); + + (void) pam_get_item(pamh, PAM_SERVICE, (void **)&service); + (void) pam_get_item(pamh, PAM_USER, (void **)&user); + + if (user == NULL || *user == '\0') { + __pam_log(LOG_AUTH | LOG_ERR, + "pam_smbfs_login: username is empty"); + return (PAM_IGNORE); + } + if (getpwnam_r(user, &pwbuf, buf, sizeof (buf)) == NULL) { + __pam_log(LOG_AUTH | LOG_ERR, + "pam_smbfs_login: username %s can't be found", user); + return (PAM_IGNORE); + } + uid = pwbuf.pw_uid; + home = pwbuf.pw_dir; + + (void) pam_get_item(pamh, PAM_AUTHTOK, (void **)&pw); + if (pw == NULL) { + /* + * A module on the stack has removed PAM_AUTHTOK. + */ + return (PAM_IGNORE); + } + + res = smbfs_default_dom_usr(home, NULL, dom, sizeof (dom), NULL, 0); + if (res != 0) + (void) strcpy(dom, "WORKGROUP"); + + if (debug) + __pam_log(LOG_AUTH | LOG_DEBUG, + "pam_smbfs_login: service %s, dom %s, user %s", + service, dom, user); + + if ((flags & (PAM_ESTABLISH_CRED | PAM_REINITIALIZE_CRED)) != 0) + res = smbfs_keychain_add(uid, dom, user, pw); + + if ((flags & PAM_DELETE_CRED) != 0) + res = smbfs_keychain_del(uid, dom, user); + + /* + * map errors to user messages and PAM return codes. + */ + switch (res) { + case SMB_KEYCHAIN_SUCCESS: + if (debug) + __pam_log(LOG_AUTH | LOG_DEBUG, + "smbfs password successfully stored for %s", user); + break; + + case SMB_KEYCHAIN_BADPASSWD: + __pam_log(LOG_AUTH | LOG_ERR, "smbfs password is invalid"); + break; + + case SMB_KEYCHAIN_BADDOMAIN: + __pam_log(LOG_AUTH | LOG_ERR, + "%s: smbfs domain %s is invalid", service, dom); + break; + + case SMB_KEYCHAIN_BADUSER: + __pam_log(LOG_AUTH | LOG_ERR, "smbfs user %s is invalid", user); + break; + + case SMB_KEYCHAIN_NODRIVER: + __pam_log(LOG_AUTH | LOG_ERR, + "driver open failed (%s), smbfs password not stored", + strerror(errno)); + break; + + case SMB_KEYCHAIN_UNKNOWN: + __pam_log(LOG_AUTH | LOG_ERR, + "Unexpected failure, smbfs password not stored"); + break; + + default: + __pam_log(LOG_AUTH | LOG_ERR, + "driver ioctl failed (%s), smbfs password not stored", + strerror(errno)); + break; + } + + return (PAM_IGNORE); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pam_modules/smbfs/sparc/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pam_modules/smbfs/sparcv9/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- a/usr/src/pkgdefs/Makefile Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/pkgdefs/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -361,6 +361,9 @@ SUNWslpr \ SUNWslpu \ SUNWsmapi \ + SUNWsmbfskr \ + SUNWsmbfsr \ + SUNWsmbfsu \ SUNWsmbskr \ SUNWsmbsr \ SUNWsmbsu \
--- a/usr/src/pkgdefs/SUNW0on/prototype_com Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/pkgdefs/SUNW0on/prototype_com Wed Feb 13 19:51:22 2008 -0800 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -256,6 +256,7 @@ f none usr/lib/help/auths/locale/SmfPowerStates.html 444 root bin f none usr/lib/help/auths/locale/SmfRoutingStates.html 444 root bin f none usr/lib/help/auths/locale/SmfSendmailStates.html 444 root bin +f none usr/lib/help/auths/locale/SmfSMBFSStates.html 444 root bin f none usr/lib/help/auths/locale/SmfSMBStates.html 444 root bin f none usr/lib/help/auths/locale/SmfSshStates.html 444 root bin f none usr/lib/help/auths/locale/SmfSyslogStates.html 444 root bin @@ -342,6 +343,7 @@ f none usr/lib/help/profiles/locale/RtProcManagement.html 444 root bin f none usr/lib/help/profiles/locale/RtRightsDelegate.html 444 root bin f none usr/lib/help/profiles/locale/RtSoftwareInstall.html 444 root bin +f none usr/lib/help/profiles/locale/RtSMBFSMngmnt.html 444 root bin f none usr/lib/help/profiles/locale/RtSMBMngmnt.html 444 root bin f none usr/lib/help/profiles/locale/RtSysEvMngmnt.html 444 root bin f none usr/lib/help/profiles/locale/RtUserMngmnt.html 444 root bin
--- a/usr/src/pkgdefs/SUNWcsu/prototype_com Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/pkgdefs/SUNWcsu/prototype_com Wed Feb 13 19:51:22 2008 -0800 @@ -493,6 +493,7 @@ f none usr/lib/help/auths/locale/C/SmfPowerStates.html 444 root bin f none usr/lib/help/auths/locale/C/SmfRoutingStates.html 444 root bin f none usr/lib/help/auths/locale/C/SmfSendmailStates.html 444 root bin +f none usr/lib/help/auths/locale/C/SmfSMBFSStates.html 444 root bin f none usr/lib/help/auths/locale/C/SmfSMBStates.html 444 root bin f none usr/lib/help/auths/locale/C/SmfSshStates.html 444 root bin f none usr/lib/help/auths/locale/C/SmfSyslogStates.html 444 root bin @@ -561,6 +562,7 @@ f none usr/lib/help/profiles/locale/C/RtProcManagement.html 444 root bin f none usr/lib/help/profiles/locale/C/RtRightsDelegate.html 444 root bin f none usr/lib/help/profiles/locale/C/RtSoftwareInstall.html 444 root bin +f none usr/lib/help/profiles/locale/C/RtSMBFSMngmnt.html 444 root bin f none usr/lib/help/profiles/locale/C/RtSMBMngmnt.html 444 root bin f none usr/lib/help/profiles/locale/C/RtSysEvMngmnt.html 444 root bin f none usr/lib/help/profiles/locale/C/RtUserMngmnt.html 444 root bin
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfskr/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,36 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +.KEEP_STATE: + +all: $(FILES) depend postinstall preremove + +install: all pkg + +include ../Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfskr/depend Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,56 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# <pkg.abbr> see pkginfo(4), PKG parameter +# <name> see pkginfo(4), NAME parameter +# <version> see pkginfo(4), VERSION parameter +# <arch> see pkginfo(4), ARCH parameter +# <type> <pkg.abbr> <name> +# (<arch>)<version> +# (<arch>)<version> +# ... +# <type> <pkg.abbr> <name> +# ... +# + +# normal dependencies from ../common_files +P SUNWcar Core Architecture, (Root) +P SUNWcakr Core Solaris Kernel Architecture (Root) +P SUNWkvm Core Architecture, (Kvm) +P SUNWcsr Core Solaris, (Root) +P SUNWckr Core Solaris Kernel (Root) +P SUNWcnetr Core Solaris Network Infrastructure (Root) +P SUNWcsu Core Solaris, (Usr) +P SUNWcsd Core Solaris Devices +P SUNWcsl Core Solaris Libraries + +# Dependencies specific to this package +P SUNWsmbfsu SMB/CIFS File System client support (Usr)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfskr/pkginfo.tmpl Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,52 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# +PKG="SUNWsmbfskr" +NAME="SMB/CIFS File System client support (Kernel)" +ARCH="ISA" +VERSION="ONVERS,REV=0.0.0" +SUNW_PRODNAME="SunOS" +SUNW_PRODVERS="RELEASE/VERSION" +SUNW_PKGTYPE="root" +MAXINST="1000" +CATEGORY="system" +DESC="SMB/CIFS File System client support (Kernel)" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +CLASSES="none" +BASEDIR=/ +SUNW_PKGVERS="1.0" +SUNW_PKG_ALLZONES="true" +SUNW_PKG_HOLLOW="true" +SUNW_PKG_THISZONE="false"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfskr/postinstall Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,72 @@ +#! /bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# Install Drivers +PATH="/usr/bin:/usr/sbin:${PATH}" +export PATH + +PKG_NAME=SUNWsmbfskr +DRV=nsmb +DRVPERM='* 0666 root sys' + +ADD_DRV=/usr/sbin/add_drv + +# +# Check if the BASEDIR option is needed +# +if [ "${BASEDIR:=/}" = "/" ]; then + ADD_DRV_FLAGS="" + NAME_TO_MAJOR="/etc/name_to_major" + DEVLINK_TAB="/etc/devlink.tab" +else + ADD_DRV_FLAGS="-b ${BASEDIR}" + NAME_TO_MAJOR="${BASEDIR}/etc/name_to_major" + DEVLINK_TAB="${BASEDIR}/etc/devlink.tab" +fi + +# +# Make sure add_drv has not been previously executed before attempting +# to add the driver +# +grep "^${DRV} " ${NAME_TO_MAJOR} > /dev/null 2>&1 +if [ $? -ne 0 ]; then + ${ADD_DRV} ${ADD_DRV_FLAGS} -m "${DRVPERM}" ${DRV} + if [ $? -ne 0 ]; then + echo "${PKG_NAME}: add_drv ${DRV} failed." >&2 + exit 1 + fi +fi + +# Add entry to /etc/devlink.tab if not there already +# Note: the tab after ${DRV} here is important. +grep "^type=ddi_pseudo;name=${DRV} " ${DEVLINK_TAB} >/dev/null 2>&1 +if [ $? -ne 0 ]; then + echo 'type=ddi_pseudo;name=nsmb\t\\D' >> ${DEVLINK_TAB} +fi + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfskr/preremove Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,58 @@ +#! /bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# Remove Drivers +PATH="/usr/bin:/usr/sbin:${PATH}" +export PATH + +DRV=nsmb + +REM_DRV=/usr/sbin/rem_drv + +# +# Check if the BASEDIR option is needed +# +if [ "${BASEDIR:=/}" = "/" ]; then + REM_DRV_FLAGS="" + DEVLINK_TAB="/etc/devlink.tab" +else + REM_DRV_FLAGS="-b ${BASEDIR}" + DEVLINK_TAB="${BASEDIR}/etc/devlink.tab" +fi + +${REM_DRV} ${REM_DRV_FLAGS} ${DRV} + +# Remove our entry from /etc/devlink.tab +# Note: the tab after ${DRV} here is important. +grep -v "^type=ddi_pseudo;name=${DRV} " ${DEVLINK_TAB} >$TMP.devlink +# Must use 'cp' here in order to preserve the original +# mode, owner and group of devlink.tab +cp $TMP.devlink ${DEVLINK_TAB} +rm -f $TMP.devlink + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfskr/prototype_com Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,50 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. +# + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# packaging files +i pkginfo +i copyright +i depend +i preremove +i postinstall +# +# source locations relative to the prototype file +# +# SUNWsmbfskr +# +d none kernel 755 root sys +d none kernel/kmdb 755 root sys
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfskr/prototype_i386 Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,53 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. +# + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# List files which are i386 specific here +# +# source locations relative to the prototype file +# +# SUNWsmbfskr +# +f none kernel/kmdb/nsmb 555 root sys +f none kernel/kmdb/smbfs 555 root sys +d none kernel/kmdb/amd64 755 root sys +f none kernel/kmdb/amd64/nsmb 555 root sys +f none kernel/kmdb/amd64/smbfs 555 root sys
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfskr/prototype_sparc Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,51 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. +# + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# List files which are SPARC specific here +# +# source locations relative to the prototype file +# +# SUNWsmbfskr +# +d none kernel/kmdb/sparcv9 755 root sys +f none kernel/kmdb/sparcv9/nsmb 555 root sys +f none kernel/kmdb/sparcv9/smbfs 555 root sys
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfsr/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,38 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +DATAFILES += i.manifest r.manifest + +.KEEP_STATE: + +all: $(FILES) depend + +install: all pkg + +include ../Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfsr/depend Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,57 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# <pkg.abbr> see pkginfo(4), PKG parameter +# <name> see pkginfo(4), NAME parameter +# <version> see pkginfo(4), VERSION parameter +# <arch> see pkginfo(4), ARCH parameter +# <type> <pkg.abbr> <name> +# (<arch>)<version> +# (<arch>)<version> +# ... +# <type> <pkg.abbr> <name> +# ... +# + +# normal dependencies from ../common_files +P SUNWcar Core Architecture, (Root) +P SUNWcakr Core Solaris Kernel Architecture (Root) +P SUNWkvm Core Architecture, (Kvm) +P SUNWcsr Core Solaris, (Root) +P SUNWckr Core Solaris Kernel (Root) +P SUNWcnetr Core Solaris Network Infrastructure (Root) +P SUNWcsu Core Solaris, (Usr) +P SUNWcsd Core Solaris Devices +P SUNWcsl Core Solaris Libraries + +# Dependencies specific to this package +P SUNWsmbfsu SMB/CIFS File System client support (Usr) +P SUNWsmbfskr SMB/CIFS File System client support (Kernel)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfsr/pkginfo.tmpl Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,52 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# +PKG="SUNWsmbfsr" +NAME="SMB/CIFS File System client support (Root)" +ARCH="ISA" +VERSION="ONVERS,REV=0.0.0" +SUNW_PRODNAME="SunOS" +SUNW_PRODVERS="RELEASE/VERSION" +SUNW_PKGTYPE="root" +MAXINST="1000" +CATEGORY="system" +DESC="SMB/CIFS File System client support (Root)" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +CLASSES="none manifest" +BASEDIR=/ +SUNW_PKGVERS="1.0" +SUNW_PKG_ALLZONES="true" +SUNW_PKG_HOLLOW="false" +SUNW_PKG_THISZONE="false"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfsr/prototype_com Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,58 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. +# + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# packaging files +i pkginfo +i copyright +i depend +i i.manifest +i r.manifest +# +# source locations relative to the prototype file +# +# SUNWsmbfsr +# +d none var 755 root sys +d none var/svc 755 root sys +d none var/svc/manifest 755 root sys +d none var/svc/manifest/network 755 root sys +d none var/svc/manifest/network/smb 755 root sys +f manifest var/svc/manifest/network/smb/client.xml 444 root sys +d none lib 755 root bin +d none lib/svc 755 root bin +d none lib/svc/method 755 root bin +f none lib/svc/method/smb-client 555 root bin
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfsr/prototype_i386 Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,47 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. +# + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# List files which are i386 specific here +# +# source locations relative to the prototype file +# +# SUNWsmbfsr
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfsr/prototype_sparc Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,47 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. +# + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# List files which are SPARC specific here +# +# source locations relative to the prototype file +# +# SUNWsmbfsr
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfsu/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,36 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +.KEEP_STATE: + +all: $(FILES) depend + +install: all pkg + +include ../Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfsu/depend Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,56 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# <pkg.abbr> see pkginfo(4), PKG parameter +# <name> see pkginfo(4), NAME parameter +# <version> see pkginfo(4), VERSION parameter +# <arch> see pkginfo(4), ARCH parameter +# <type> <pkg.abbr> <name> +# (<arch>)<version> +# (<arch>)<version> +# ... +# <type> <pkg.abbr> <name> +# ... +# + +# normal dependencies from ../common_files +P SUNWcar Core Architecture, (Root) +P SUNWcakr Core Solaris Kernel Architecture (Root) +P SUNWkvm Core Architecture, (Kvm) +P SUNWcsr Core Solaris, (Root) +P SUNWckr Core Solaris Kernel (Root) +P SUNWcnetr Core Solaris Network Infrastructure (Root) +P SUNWcsu Core Solaris, (Usr) +P SUNWcsd Core Solaris Devices +P SUNWcsl Core Solaris Libraries + +# Dependencies specific to this package +P SUNWuiu8 Iconv modules for UTF-8 Locale
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfsu/pkginfo.tmpl Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,52 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# +PKG="SUNWsmbfsu" +NAME="SMB/CIFS File System client support (Usr)" +ARCH="ISA" +VERSION="ONVERS,REV=0.0.0" +SUNW_PRODNAME="SunOS" +SUNW_PRODVERS="RELEASE/VERSION" +SUNW_PKGTYPE="usr" +MAXINST="1000" +CATEGORY="system" +DESC="SMB/CIFS File System client support (Usr)" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +CLASSES="none" +BASEDIR=/ +SUNW_PKGVERS="1.0" +SUNW_PKG_ALLZONES="true" +SUNW_PKG_HOLLOW="false" +SUNW_PKG_THISZONE="false"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfsu/prototype_com Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,67 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# packaging files +i pkginfo +i copyright +i depend +# +# source locations relative to the prototype file +# +# SUNWsmbfsu +# + +d none usr 755 root sys +d none usr/bin 755 root bin +f none usr/bin/smbutil 555 root bin +d none usr/kernel 755 root sys +d none usr/kernel/fs 755 root sys +d none usr/kernel/sys 755 root sys +d none usr/kernel/drv 755 root sys +f none usr/kernel/drv/nsmb.conf 644 root sys +d none usr/lib 755 root bin +d none usr/lib/fs 755 root sys +d none usr/lib/fs/smbfs 755 root sys +f none usr/lib/fs/smbfs/mount 555 root bin +f none usr/lib/fs/smbfs/umount 555 root bin +d none usr/lib/fs/smb 755 root sys +f none usr/lib/fs/smbfs/libshare_smbfs.so.1 755 root bin +f none usr/lib/libsmbfs.so.1 755 root bin +d none usr/lib/mdb 755 root sys +d none usr/lib/mdb/kvm 755 root sys +d none usr/lib/security 755 root bin +f none usr/lib/security/pam_smbfs_login.so.1 755 root bin +s none usr/lib/security/pam_smbfs_login.so=pam_smbfs_login.so.1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfsu/prototype_i386 Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,70 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# List files which are i386 specific here +# +# source locations relative to the prototype file +# +# SUNWsmbfsu +# + +f none usr/kernel/fs/smbfs 755 root sys +l none usr/kernel/sys/smbfs=../../kernel/fs/smbfs +d none usr/kernel/fs/amd64 755 root sys +f none usr/kernel/fs/amd64/smbfs 755 root sys +d none usr/kernel/sys/amd64 755 root sys +l none usr/kernel/sys/amd64/smbfs=../../../kernel/fs/amd64/smbfs +f none usr/kernel/drv/nsmb 755 root sys +d none usr/kernel/drv/amd64 755 root sys +f none usr/kernel/drv/amd64/nsmb 755 root sys + +d none usr/lib/amd64 755 root bin +f none usr/lib/amd64/libsmbfs.so.1 755 root bin +d none usr/lib/fs/smbfs/amd64 755 root sys +f none usr/lib/fs/smbfs/amd64/libshare_smbfs.so.1 755 root bin +f none usr/lib/mdb/kvm/nsmb.so 555 root bin +f none usr/lib/mdb/kvm/smbfs.so 555 root bin +d none usr/lib/mdb/kvm/amd64 755 root sys +f none usr/lib/mdb/kvm/amd64/nsmb.so 555 root bin +f none usr/lib/mdb/kvm/amd64/smbfs.so 555 root bin +d none usr/lib/security/amd64 755 root bin +f none usr/lib/security/amd64/pam_smbfs_login.so.1 755 root bin +s none usr/lib/security/amd64/pam_smbfs_login.so=pam_smbfs_login.so.1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkgdefs/SUNWsmbfsu/prototype_sparc Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,65 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# List files which are SPARC specific here +# +# source locations relative to the prototype file +# +# SUNWsmbfsu +# + +d none usr/kernel/fs/sparcv9 755 root sys +f none usr/kernel/fs/sparcv9/smbfs 755 root sys +d none usr/kernel/sys/sparcv9 755 root sys +l none usr/kernel/sys/sparcv9/smbfs=../../../kernel/fs/sparcv9/smbfs +d none usr/kernel/drv/sparcv9 755 root sys +f none usr/kernel/drv/sparcv9/nsmb 755 root sys + +d none usr/lib/sparcv9 755 root bin +f none usr/lib/sparcv9/libsmbfs.so.1 755 root bin +d none usr/lib/fs/smbfs/sparcv9 755 root sys +f none usr/lib/fs/smbfs/sparcv9/libshare_smbfs.so.1 755 root bin +d none usr/lib/mdb/kvm/sparcv9 755 root sys +f none usr/lib/mdb/kvm/sparcv9/nsmb.so 555 root bin +f none usr/lib/mdb/kvm/sparcv9/smbfs.so 555 root bin +d none usr/lib/security/sparcv9 755 root bin +f none usr/lib/security/sparcv9/pam_smbfs_login.so.1 755 root bin +s none usr/lib/security/sparcv9/pam_smbfs_login.so=pam_smbfs_login.so.1
--- a/usr/src/pkgdefs/common_files/i.minorperm_i386 Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/pkgdefs/common_files/i.minorperm_i386 Wed Feb 13 19:51:22 2008 -0800 @@ -318,6 +318,7 @@ battery:* smbsrv:* vscan:* +nsmb:* EOF }
--- a/usr/src/pkgdefs/common_files/i.minorperm_sparc Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/pkgdefs/common_files/i.minorperm_sparc Wed Feb 13 19:51:22 2008 -0800 @@ -335,6 +335,7 @@ physmem:* smbsrv:* vscan:* +nsmb:* EOF }
--- a/usr/src/pkgdefs/etc/exception_list_i386 Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/pkgdefs/etc/exception_list_i386 Wed Feb 13 19:51:22 2008 -0800 @@ -870,6 +870,8 @@ usr/lib/fs/nfs/amd64/libshare_nfs.so i386 usr/lib/fs/smb/libshare_smb.so i386 usr/lib/fs/smb/amd64/libshare_smb.so i386 +usr/lib/fs/smbfs/libshare_smbfs.so i386 +usr/lib/fs/smbfs/amd64/libshare_smbfs.so i386 usr/include/libshare_impl.h i386 usr/include/scfutil.h i386 usr/sbin/i86/sharemgr i386 @@ -1041,3 +1043,11 @@ # drivers. There is no usr/ component to this sub-platform, but the # directory is created in the proto area to keep other tools happy. usr/platform/i86hvm i386 +# +# libsmbfs is private +# +usr/lib/libsmbfs.so i386 +usr/lib/amd64/libsmbfs.so i386 +usr/lib/llib-lsmbfs i386 +usr/lib/llib-lsmbfs.ln i386 +usr/lib/amd64/llib-lsmbfs.ln i386
--- a/usr/src/pkgdefs/etc/exception_list_sparc Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/pkgdefs/etc/exception_list_sparc Wed Feb 13 19:51:22 2008 -0800 @@ -947,6 +947,8 @@ usr/lib/fs/nfs/sparcv9/libshare_nfs.so sparc usr/lib/fs/smb/libshare_smb.so sparc usr/lib/fs/smb/sparcv9/libshare_smb.so sparc +usr/lib/fs/smbfs/libshare_smbfs.so sparc +usr/lib/fs/smbfs/sparcv9/libshare_smbfs.so sparc usr/include/libshare_impl.h sparc usr/include/scfutil.h sparc usr/sbin/sparcv9/sharemgr sparc @@ -1121,3 +1123,11 @@ # usr/lib/vscan/llib-lvscan sparc usr/lib/vscan/llib-lvscan.ln sparc +# +# libsmbfs is private +# +usr/lib/libsmbfs.so sparc +usr/lib/sparcv9/libsmbfs.so sparc +usr/lib/llib-lsmbfs sparc +usr/lib/llib-lsmbfs.ln sparc +usr/lib/sparcv9/llib-lsmbfs.ln sparc
--- a/usr/src/tools/findunref/exception_list Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/tools/findunref/exception_list Wed Feb 13 19:51:22 2008 -0800 @@ -20,7 +20,7 @@ # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -42,6 +42,7 @@ */BUGS */COMPATIBILITY */COPYRIGHT +*/CREDITS */ChangeLog */DESIGN */HISTORY
--- a/usr/src/tools/opensolaris/license-list Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/tools/opensolaris/license-list Wed Feb 13 19:51:22 2008 -0800 @@ -126,3 +126,7 @@ usr/src/uts/intel/io/amr/THIRDPARTYLICENSE usr/src/common/crypto/ecc/THIRDPARTYLICENSE usr/src/common/mpi/THIRDPARTYLICENSE +usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple +usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov +usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4 +usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft
--- a/usr/src/tools/scripts/bfu.sh Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/tools/scripts/bfu.sh Wed Feb 13 19:51:22 2008 -0800 @@ -7477,6 +7477,7 @@ mxfe:* mxfe* clone:rtls rtls rtls:* rtls* + nsmb:* nsmb* EOF if [ $target_isa = i386 ] && [[ $rootslice = /dev/rdsk/* || \
--- a/usr/src/uts/common/Makefile.files Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/uts/common/Makefile.files Wed Feb 13 19:51:22 2008 -0800 @@ -1043,6 +1043,14 @@ lufs_log.o lufs_map.o lufs_top.o lufs_debug.o VSCAN_OBJS += vscan_drv.o vscan_svc.o vscan_door.o +NSMB_OBJS += smb_conn.o smb_crypt.o smb_dev.o smb_iod.o \ + smb_rq.o smb_smb.o smb_tran.o smb_trantcp.o \ + smb_usr.o smb_subrs.o subr_mchain.o smb_pass.o + +SMBFS_OBJS += smbfs_vfsops.o smbfs_vnops.o smbfs_node.o \ + smbfs_client.o smbfs_io.o smbfs_smb.o \ + smbfs_subr.o smbfs_subr2.o smbfs_rwlock.o + # # LVM modules #
--- a/usr/src/uts/common/Makefile.rules Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/uts/common/Makefile.rules Wed Feb 13 19:51:22 2008 -0800 @@ -262,6 +262,14 @@ $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(UTSBASE)/common/fs/smbclnt/netsmb/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/common/fs/smbclnt/smbfs/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/common/fs/sockfs/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -1239,6 +1247,18 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/sharefs/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +NSMBLINT = -erroff=E_FUNC_RET_ALWAYS_IGNOR2 -erroff=E_FUNC_RET_MAYBE_IGNORED2 + +$(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/smbclnt/netsmb/%.c + @($(LHEAD) $(LINT.c) $(NSMBLINT) $< $(LTAIL)) + +$(LINTS_DIR)/smbfs_smb.ln: $(UTSBASE)/common/fs/smbclnt/smbfs/smbfs_smb.c + @($(LHEAD) $(LINT.c) $(NSMBLINT) \ + $(UTSBASE)/common/fs/smbclnt/smbfs/smbfs_smb.c $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/smbclnt/smbfs/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/sockfs/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/COPYRIGHT Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,31 @@ +#ident "%Z%%M% %I% %E% SMI" + + 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.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/CREDITS Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,11 @@ +#ident "%Z%%M% %I% %E% SMI" + + In the development process next sources were used: + +Various documents from the Microsoft ftp site. +HTML docs published by Thursby Software. + +Special thanks to the Samba team for permission to use their source +code as reference. + +Author - Boris Popov <bp@butya.kz>, <bp@freebsd.org>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/README Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,49 @@ + + + SMB/CIFS protocol and SMB/CIFS file system implementation + for FreeBSD, version 1.4. + + This is native SMB/CIFS filesystem (smbfs for short) for FreeBSD. +It is a complete, kernel side implementation of SMB requester and filesystem. + + Supportted platforms: + FreeBSD 4.X + + FreeBSD-current kernel module is included in the base source + tree. + + I'm would be very grateful for any feedback, bug reports etc. + + Supported SMB servers: + Samba + Windows 95/98/ME/2000/NT4.0 (SPs 4, 5, 6) + IBM LanManager + NetApp + + An updated versions of this package can be retrieved from ftp server: + + ftp://ftp.butya.kz/pub/smbfs/smbfs.tar.gz + +Author: Boris Popov <bp@freebsd.org> + +================================================================ + +Additional notes from Sun Microsystems: + +This code (the OpenSolaris CIFS client) is derived from the +Apple Darwin project, smb-217.2 code drop. See the file +COPYRIGHT for copyright and redistribution terms. + +The Darwin code was reorganized as follows for Solaris: + +Darwin location: Solaris location: (usr/src/...) +kernel/netsmb uts/common/netsmb (exported headers) +kernel/netsmb uts/common/fs/smbclnt/netsmb +kernel/fs/smbfs uts/common/fs/smbclnt/smbfs +include/netsmb lib/libsmb/netsmb +lib/smb lib/libsmb/smb +mount_smbfs cmd/fs.d/smbclnt/mount +smbutil cmd/fs.d/smbclnt/smbutil +idl_compiler cmd/idlgen + +[ ident "%Z%%M% %I% %E% SMI" ]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/nsmb.conf Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,28 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +name="nsmb" parent="pseudo"; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,134 @@ +\ +\ CDDL HEADER START +\ +\ The contents of this file are subject to the terms of the +\ Common Development and Distribution License (the "License"). +\ You may not use this file except in compliance with the License. +\ +\ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +\ or http://www.opensolaris.org/os/licensing. +\ See the License for the specific language governing permissions +\ and limitations under the License. +\ +\ When distributing Covered Code, include this CDDL HEADER in each +\ file and include the License file at usr/src/OPENSOLARIS.LICENSE. +\ If applicable, add the following below this CDDL HEADER, with the +\ fields enclosed by brackets "[]" replaced with your own identifying +\ information: Portions Copyright [yyyy] [name of copyright owner] +\ +\ CDDL HEADER END +\ +\ +\ Copyright 2007 Sun Microsystems, Inc. All rights reserved. +\ Use is subject to license terms. +\ + +#pragma ident "%Z%%M% %I% %E% SMI" + +\ +\ offsets.in: input file for the ctfstabs program, +\ used to generate ioc_check.h - which verifies +\ invariance of our ioctl data structures across +\ 32-bit and 64-bit ABIs. + +#ifndef _GENASSYM +#define _GENASSYM +#endif + +#include <sys/types.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/socket_impl.h> +#include <netsmb/smb.h> +#include <netsmb/netbios.h> +#include <netsmb/smb_dev.h> + +sockaddr_any SIZEOF_SOCKADDR_ANY + +sockaddr_in SIZEOF_SOCKADDR_IN + +sockaddr_nb SIZEOF_SOCKADDR_NB + +smbioc_ossn SIZEOF_SMBIOC_OSSN + ioc_server + ioc_local + ioc_localcs + ioc_servercs + ioc_srvname + ioc_user + ioc_workgroup + ioc_password IOC_SSN_PASSWD + ioc_opt IOC_SSN_OPT + ioc_timeout + ioc_retrycount + ioc_owner IOC_SSN_OWNER + ioc_group IOC_SSN_GROUP + ioc_mode IOC_SSN_MODE + ioc_rights IOC_SSN_RIGHTS + ioc_intoklen + ioc_outtoklen + _ioc_intok + _ioc_outtok + +smbioc_oshare SIZEOF_SMBIOC_OSHARE + ioc_share + ioc_password IOC_SH_PASSWD + ioc_opt IOC_SH_OPT + ioc_stype + ioc_owner IOC_SH_OWNER + ioc_group IOC_SH_GROUP + ioc_mode IOC_SH_MODE + ioc_rights IOC_SH_RIGHTS + +smbioc_rq SIZEOF_SMBIOC_RQ + ioc_cmd + ioc_twc + ioc_tbc + ioc_rpbufsz + ioc_rwc + ioc_rbc + ioc_errclass IOC_RQ_ERRCLASS + ioc_serror IOC_RQ_SERROR + ioc_error IOC_RQ_ERROR + _ioc_twords + _ioc_tbytes + _ioc_rpbuf + +smbioc_t2rq SIZEOF_SMBIOC_T2RQ + ioc_setup + ioc_setupcnt + ioc_name + ioc_tparamcnt + ioc_tdatacnt + ioc_rparamcnt + ioc_rdatacnt + ioc_errclass IOC_T2_ERRCLASS + ioc_serror IOC_T2_SERROR + ioc_error IOC_T2_ERROR + ioc_rpflags2 + _ioc_tparam + _ioc_tdata + _ioc_rparam + _ioc_rdata + +smbioc_flags SIZEOF_SMBIOC_FLAGS + ioc_level + ioc_mask + ioc_flags + +smbioc_lookup SIZEOF_SMBIOC_LOOKUP + ioc_level IOC_LOOK_LEVEL + ioc_flags IOC_LOOK_FLAGS + ioc_sh + ioc_ssn + +smbioc_rw SIZEOF_SMBIOC_RW + ioc_fh + ioc_cnt + _ioc_offset + _ioc_base + +smbioc_pk SIZEOF_SMBIOC_PK + pk_dom + pk_usr + pk_pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,1294 @@ +/* + * Copyright (c) 2000-2001 Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_conn.c,v 1.27.166.1 2005/05/27 02:35:29 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Connection engine. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kmem.h> +#include <sys/proc.h> +#include <sys/lock.h> +#include <sys/vnode.h> +#include <sys/stream.h> +#include <sys/stropts.h> +#include <sys/socketvar.h> +#include <sys/cred.h> +#include <sys/cred_impl.h> +#include <netinet/in.h> +#include <inet/ip.h> +#include <inet/ip6.h> +#include <sys/cmn_err.h> +#include <sys/thread.h> +#include <sys/atomic.h> + +#ifdef APPLE +#include <sys/smb_apple.h> +#include <sys/smb_iconv.h> +#else +#include <netsmb/smb_osdep.h> +#endif + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> +#include <netsmb/smb_tran.h> +#include <netsmb/smb_pass.h> + +static struct smb_connobj smb_vclist; +static uint_t smb_vcnext = 0; /* next unique id for VC */ + +void smb_co_init(struct smb_connobj *cp, int level, char *objname); +void smb_co_done(struct smb_connobj *cp); +void smb_co_hold(struct smb_connobj *cp); +void smb_co_rele(struct smb_connobj *cp); +void smb_co_kill(struct smb_connobj *cp); + +#ifdef APPLE +static void smb_sm_lockvclist(void); +static void smb_sm_unlockvclist(void); +#endif + +static void smb_vc_free(struct smb_connobj *cp); +static void smb_vc_gone(struct smb_connobj *cp); + +static void smb_share_free(struct smb_connobj *cp); +static void smb_share_gone(struct smb_connobj *cp); + +/* smb_dup_sockaddr moved to smb_tran.c */ + +int +smb_sm_init(void) +{ + smb_co_init(&smb_vclist, SMBL_SM, "smbsm"); + return (0); +} + +int +smb_sm_idle(void) +{ + int error = 0; + SMB_CO_LOCK(&smb_vclist); + if (smb_vclist.co_usecount > 1) { + SMBSDEBUG("%d connections still active\n", + smb_vclist.co_usecount - 1); + error = EBUSY; + } + SMB_CO_UNLOCK(&smb_vclist); + return (error); +} + +void +smb_sm_done(void) +{ + /* + * XXX Q4BP why are we not iterating on smb_vclist here? + * Because the caller has just called smb_sm_idle() to + * make sure we have no VCs before calling this. + */ + smb_co_done(&smb_vclist); +} + +/* + * Find a VC identified by the info in vcspec, + * and return it with a "hold", but not locked. + */ +/*ARGSUSED*/ +static int +smb_sm_lookupvc( + struct smb_vcspec *vcspec, + struct smb_cred *scred, + struct smb_vc **vcpp) +{ + struct smb_connobj *co; + struct smb_vc *vcp; + zoneid_t zoneid = getzoneid(); + + ASSERT(MUTEX_HELD(&smb_vclist.co_lock)); + + /* var, head, next_field */ + SLIST_FOREACH(co, &smb_vclist.co_children, co_next) { + vcp = CPTOVC(co); + + /* + * Some things we can check without + * holding the lock (those that are + * set at creation and never change). + */ + + /* VCs in other zones are invisibile. */ + if (vcp->vc_zoneid != zoneid) + continue; + + /* Also segregate by owner. */ + if (vcp->vc_uid != vcspec->owner) + continue; + + /* XXX: we ignore the group. Remove vc_gid? */ + + /* server */ + if (smb_cmp_sockaddr(vcp->vc_paddr, vcspec->sap)) + continue; + + /* domain+user */ + if (strcmp(vcp->vc_domain, vcspec->domain)) + continue; + if (strcmp(vcp->vc_username, vcspec->username)) + continue; + + SMB_VC_LOCK(vcp); + + /* No new references allowed when _GONE is set */ + if (vcp->vc_flags & SMBV_GONE) + goto unlock_continue; + + if (vcp->vc_vopt & SMBVOPT_PRIVATE) + goto unlock_continue; + + found: + /* + * Success! (Found one we can use) + * Return with it held, unlocked. + * In-line smb_vc_hold here. + */ + co->co_usecount++; + SMB_VC_UNLOCK(vcp); + *vcpp = vcp; + return (0); + + unlock_continue: + SMB_VC_UNLOCK(vcp); + /* keep looking. */ + } + + return (ENOENT); +} + + +int +smb_sm_negotiate( + struct smb_vcspec *vcspec, + struct smb_cred *scred, + struct smb_vc **vcpp) +{ + struct smb_vc *vcp; + clock_t tmo; + int created, error; + +top: + *vcpp = vcp = NULL; + + SMB_CO_LOCK(&smb_vclist); + error = smb_sm_lookupvc(vcspec, scred, &vcp); + if (error) { + /* The VC was not found. Create? */ + if ((vcspec->optflags & SMBVOPT_CREATE) == 0) { + SMB_CO_UNLOCK(&smb_vclist); + return (error); + } + error = smb_vc_create(vcspec, scred, &vcp); + if (error) { + /* Could not create? Unusual. */ + SMB_CO_UNLOCK(&smb_vclist); + return (error); + } + /* Note: co_usecount == 1 */ + created = 1; + } else + created = 0; + SMB_CO_UNLOCK(&smb_vclist); + + if (created) { + /* + * We have a NEW VC, held, but not locked. + */ + + SMBIODEBUG("vc_state=%d\n", vcp->vc_state); + switch (vcp->vc_state) { + + case SMBIOD_ST_NOTCONN: + (void) smb_vc_setup(vcspec, scred, vcp, 0); + vcp->vc_genid++; + /* XXX: Save credentials of caller here? */ + vcp->vc_state = SMBIOD_ST_RECONNECT; + /* FALLTHROUGH */ + + case SMBIOD_ST_RECONNECT: + error = smb_iod_connect(vcp); + if (error) + break; + vcp->vc_state = SMBIOD_ST_TRANACTIVE; + /* FALLTHROUGH */ + + case SMBIOD_ST_TRANACTIVE: + /* XXX: Just pass vcspec instead? */ + vcp->vc_intok = vcspec->tok; + vcp->vc_intoklen = vcspec->toklen; + error = smb_smb_negotiate(vcp, &vcp->vc_scred); + vcp->vc_intok = NULL; + vcp->vc_intoklen = 0; + if (error) + break; + vcp->vc_state = SMBIOD_ST_NEGOACTIVE; + /* FALLTHROUGH */ + + case SMBIOD_ST_NEGOACTIVE: + case SMBIOD_ST_SSNSETUP: + case SMBIOD_ST_VCACTIVE: + /* We can (re)use this VC. */ + error = 0; + break; + + default: + error = EINVAL; + break; + } + + SMB_VC_LOCK(vcp); + cv_broadcast(&vcp->vc_statechg); + SMB_VC_UNLOCK(vcp); + + } else { + /* + * Found an existing VC. Reuse it, but first, + * wait for authentication to finish, etc. + * Note: We hold a reference on the VC. + */ + error = 0; + SMB_VC_LOCK(vcp); + while (vcp->vc_state != SMBIOD_ST_VCACTIVE) { + tmo = lbolt + SEC_TO_TICK(5); + tmo = cv_timedwait_sig(&vcp->vc_statechg, + &vcp->vc_lock, tmo); + if (tmo == 0) { + error = EINTR; + break; + } + if (vcp->vc_flags & SMBV_GONE) + break; + } + SMB_VC_UNLOCK(vcp); + + /* Interrupted? */ + if (error) + goto out; + + /* + * The other guy failed authentication, + * or otherwise gave up on this VC. + * Drop reference, start over. + */ + if (vcp->vc_flags & SMBV_GONE) { + smb_vc_rele(vcp); + goto top; + } + + ASSERT(vcp->vc_state == SMBIOD_ST_VCACTIVE); + /* Success! */ + } + +out: + if (error) { + /* + * Undo the hold from lookupvc, + * or destroy if from vc_create. + */ + smb_vc_rele(vcp); + } else { + /* Return it held. */ + *vcpp = vcp; + } + + return (error); +} + + +int +smb_sm_ssnsetup( + struct smb_vcspec *vcspec, + struct smb_cred *scred, + struct smb_vc *vcp) +{ + int error; + + /* + * We have a VC, held, but not locked. + * + * Code from smb_iod_ssnsetup, + * with lots of rework. + */ + + SMBIODEBUG("vc_state=%d\n", vcp->vc_state); + switch (vcp->vc_state) { + + case SMBIOD_ST_NEGOACTIVE: + /* + * This is the state we normally find. + * Calling _setup AGAIN to update the + * flags, security info, etc. + */ + error = smb_vc_setup(vcspec, scred, vcp, 1); + if (error) + break; + vcp->vc_state = SMBIOD_ST_SSNSETUP; + /* FALLTHROUGH */ + + case SMBIOD_ST_SSNSETUP: + /* XXX: Just pass vcspec instead? */ + vcp->vc_intok = vcspec->tok; + vcp->vc_intoklen = vcspec->toklen; + error = smb_smb_ssnsetup(vcp, &vcp->vc_scred); + vcp->vc_intok = NULL; + vcp->vc_intoklen = 0; + if (error) + break; + /* OK, start the reader thread... */ + error = smb_iod_create(vcp); + if (error) + break; + vcp->vc_state = SMBIOD_ST_VCACTIVE; + /* FALLTHROUGH */ + + case SMBIOD_ST_VCACTIVE: + /* We can (re)use this VC. */ + error = 0; + break; + + default: + error = EINVAL; + break; + } + + SMB_VC_LOCK(vcp); + cv_broadcast(&vcp->vc_statechg); + SMB_VC_UNLOCK(vcp); + + return (error); +} + +int +smb_sm_tcon( + struct smb_sharespec *shspec, + struct smb_cred *scred, + struct smb_vc *vcp, + struct smb_share **sspp) +{ + struct smb_share *ssp; + int error; + + *sspp = ssp = NULL; + + if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { + /* + * The wait for vc_state in smb_sm_negotiate + * _should_ get us a VC in the right state. + */ + SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state); + return (ENOTCONN); + } + + SMB_VC_LOCK(vcp); + error = smb_vc_lookupshare(vcp, shspec, scred, &ssp); + if (error) { + /* The share was not found. Create? */ + if ((shspec->optflags & SMBVOPT_CREATE) == 0) { + SMB_VC_UNLOCK(vcp); + return (error); + } + error = smb_share_create(vcp, shspec, scred, &ssp); + if (error) { + /* Could not create? Unusual. */ + SMB_VC_UNLOCK(vcp); + return (error); + } + /* Note: co_usecount == 1 */ + } + SMB_VC_UNLOCK(vcp); + + /* + * We have a share, held, but not locked. + * Make it connected... + */ + SMB_SS_LOCK(ssp); + if (!smb_share_valid(ssp)) + error = smb_share_tcon(ssp); + SMB_SS_UNLOCK(ssp); + + if (error) { + /* + * Undo hold from lookupshare, + * or destroy if from _create. + */ + smb_share_rele(ssp); + } else { + /* Return it held. */ + *sspp = ssp; + } + + return (error); +} + +/* + * Common code for connection object + */ +/*ARGSUSED*/ +void +smb_co_init(struct smb_connobj *cp, int level, char *objname) +{ + + mutex_init(&cp->co_lock, objname, MUTEX_DRIVER, NULL); + + cp->co_level = level; + cp->co_usecount = 1; + SLIST_INIT(&cp->co_children); +} + +/* + * Called just before free of an object + * of which smb_connobj is a part, i.e. + * _vc_free, _share_free, also sm_done. + */ +void +smb_co_done(struct smb_connobj *cp) +{ + ASSERT(SLIST_EMPTY(&cp->co_children)); + mutex_destroy(&cp->co_lock); +} + +static void +smb_co_addchild( + struct smb_connobj *parent, + struct smb_connobj *child) +{ + + /* + * Set the child's pointer to the parent. + * No references yet, so no need to lock. + */ + ASSERT(child->co_usecount == 1); + child->co_parent = parent; + + /* + * Add the child to the parent's list of + * children, and in-line smb_co_hold + */ + ASSERT(MUTEX_HELD(&parent->co_lock)); + parent->co_usecount++; + SLIST_INSERT_HEAD(&parent->co_children, child, co_next); +} + +void +smb_co_hold(struct smb_connobj *cp) +{ + SMB_CO_LOCK(cp); + cp->co_usecount++; + SMB_CO_UNLOCK(cp); +} + +/* + * Called via smb_vc_rele, smb_share_rele + */ +void +smb_co_rele(struct smb_connobj *co) +{ + struct smb_connobj *parent; + int old_flags; + + SMB_CO_LOCK(co); + if (co->co_usecount > 1) { + co->co_usecount--; + SMB_CO_UNLOCK(co); + return; + } + ASSERT(co->co_usecount == 1); + co->co_usecount = 0; + + /* + * This list of children should be empty now. + * Check this while we're still linked, so + * we have a better chance of debugging. + */ + ASSERT(SLIST_EMPTY(&co->co_children)); + + /* + * OK, this element is going away. + * + * We need to drop the lock on this CO so we can take the + * parent CO lock. The _GONE flag prevents this CO from + * getting new references before we can unlink it from the + * parent list. + * + * The _GONE flag is also used to ensure that the co_gone + * function is called only once. Note that smb_co_kill may + * do this before we get here. If we find that the _GONE + * flag was not already set, then call the co_gone hook + * (smb_share_gone, smb_vc_gone) which will disconnect + * the share or the VC, respectively. + * + * Note the old: smb_co_gone(co, scred); + * is now in-line here. + */ + old_flags = co->co_flags; + co->co_flags |= SMBO_GONE; + SMB_CO_UNLOCK(co); + + if ((old_flags & SMBO_GONE) == 0 && co->co_gone) + co->co_gone(co); + + /* + * If we have a parent (only smb_vclist does not) + * then unlink from parent's list of children. + * We have the only reference to the child. + */ + parent = co->co_parent; + if (parent) { + SMB_CO_LOCK(parent); + ASSERT(SLIST_FIRST(&parent->co_children)); + if (SLIST_FIRST(&parent->co_children)) { + SLIST_REMOVE(&parent->co_children, co, + smb_connobj, co_next); + } + SMB_CO_UNLOCK(parent); + } + + /* + * Now it's safe to free the CO + */ + if (co->co_free) { + co->co_free(co); + } + + /* + * Finally, if the CO had a parent, decrement + * the parent's hold count for the lost child. + */ + if (parent) { + /* + * Recursive call here (easier for debugging). + * Can only go two levels. + */ + smb_co_rele(parent); + } +} + +/* + * Do just the first part of what co_gone does, + * i.e. tree disconnect, or disconnect a VC. + * This is used to forcibly close things. + */ +void +smb_co_kill(struct smb_connobj *co) +{ + int old_flags; + + SMB_CO_LOCK(co); + old_flags = co->co_flags; + co->co_flags |= SMBO_GONE; + SMB_CO_UNLOCK(co); + + /* + * Do the same "call only once" logic here as in + * smb_co_rele, though it's probably not possible + * for this to be called after smb_co_rele. + */ + if ((old_flags & SMBO_GONE) == 0 && co->co_gone) + co->co_gone(co); + + /* XXX: Walk list of children and kill those too? */ +} + + +/* + * Session implementation + */ + +/* + * This sets the fields that are allowed to change + * when doing a reconnect. Many others are set in + * smb_vc_create and never change afterwards. + * Don't want domain or user to change here. + */ +int +smb_vc_setup(struct smb_vcspec *vcspec, struct smb_cred *scred, + struct smb_vc *vcp, int is_ss) +{ + int error, minauth; + + /* Just save all the SMBVOPT_ options. */ + vcp->vc_vopt = vcspec->optflags; + + /* Cleared if nego response shows antique server! */ + vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES; + + /* XXX: Odd place for this. */ + if (vcspec->optflags & SMBVOPT_EXT_SEC) + vcp->vc_hflags2 |= SMB_FLAGS2_EXT_SEC; + + if (is_ss) { + /* Called from smb_sm_ssnsetup */ + + if (vcspec->optflags & SMBVOPT_USE_KEYCHAIN) { + /* + * Get p/w hashes from the keychain. + * The password in vcspec->pass is + * fiction, so don't store it. + */ + error = smb_pkey_getpwh(vcp, scred->vc_ucred); + return (error); + } + + /* + * Note: this can be called more than once + * for a given vcp, so free the old strings. + */ + SMB_STRFREE(vcp->vc_pass); + + /* + * Don't store the cleartext password + * unless the minauth value was changed + * to allow use of cleartext passwords. + * (By default, this is not allowed.) + */ + minauth = vcspec->optflags & SMBVOPT_MINAUTH; + if (minauth == SMBVOPT_MINAUTH_NONE) + vcp->vc_pass = smb_strdup(vcspec->pass); + + /* Compute LM and NTLM hashes. */ + smb_oldlm_hash(vcspec->pass, vcp->vc_lmhash); + smb_ntlmv1hash(vcspec->pass, vcp->vc_nthash); + } + + /* Success! */ + error = 0; + return (error); +} + +/*ARGSUSED*/ +int +smb_vc_create(struct smb_vcspec *vcspec, + struct smb_cred *scred, struct smb_vc **vcpp) +{ + static char objtype[] = "smb_vc"; + struct smb_vc *vcp; + int error = 0; + + ASSERT(MUTEX_HELD(&smb_vclist.co_lock)); + + /* + * Checks for valid uid/gid are now in + * smb_usr_ioc2vcspec, so at this point + * we know the user has right to create + * with the uid/gid in the vcspec. + */ + + vcp = kmem_zalloc(sizeof (struct smb_vc), KM_SLEEP); + + smb_co_init(VCTOCP(vcp), SMBL_VC, objtype); + vcp->vc_co.co_free = smb_vc_free; + vcp->vc_co.co_gone = smb_vc_gone; + + cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL); + sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL); + rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL); + cv_init(&vcp->iod_exit, objtype, CV_DRIVER, NULL); + + vcp->vc_number = atomic_inc_uint_nv(&smb_vcnext); + vcp->vc_state = SMBIOD_ST_NOTCONN; + vcp->vc_timo = SMB_DEFRQTIMO; + /* + * I think SMB_UID_UNKNOWN is not the correct + * initial value for vc_smbuid. See the long + * comment in smb_iod_sendrq() + */ + vcp->vc_smbuid = SMB_UID_UNKNOWN; /* XXX should be zero */ + vcp->vc_tdesc = &smb_tran_nbtcp_desc; + + /* + * These identify the connection. + */ + vcp->vc_zoneid = getzoneid(); + vcp->vc_uid = vcspec->owner; + vcp->vc_grp = vcspec->group; + vcp->vc_mode = vcspec->rights & SMBM_MASK; + + vcp->vc_domain = smb_strdup(vcspec->domain); + vcp->vc_username = smb_strdup(vcspec->username); + vcp->vc_srvname = smb_strdup(vcspec->srvname); + vcp->vc_paddr = smb_dup_sockaddr(vcspec->sap); + vcp->vc_laddr = smb_dup_sockaddr(vcspec->lap); + +#ifdef NOICONVSUPPORT + /* + * REVISIT + */ + error = iconv_open("tolower", vcspec->localcs, &vcp->vc_tolower); + if (error) + goto errout; + + error = iconv_open("toupper", vcspec->localcs, &vcp->vc_toupper); + if (error) + goto errout; + + if (vcspec->servercs[0]) { + + error = iconv_open(vcspec->servercs, vcspec->localcs, + &vcp->vc_toserver); + if (error) + goto errout; + + error = iconv_open(vcspec->localcs, vcspec->servercs, + &vcp->vc_tolocal); + if (error) + goto errout; + } +#endif /* NOICONVSUPPORT */ + + /* This fills in vcp->vc_tdata */ + if ((error = SMB_TRAN_CREATE(vcp, curproc)) != 0) + goto errout; + + /* Success! */ + smb_co_addchild(&smb_vclist, VCTOCP(vcp)); + *vcpp = vcp; + return (0); + +errout: + /* + * This will destroy the new vc. + * See: smb_vc_free + */ + smb_vc_rele(vcp); + return (error); +} + +void +smb_vc_hold(struct smb_vc *vcp) +{ + smb_co_hold(VCTOCP(vcp)); +} + +void +smb_vc_rele(struct smb_vc *vcp) +{ + smb_co_rele(VCTOCP(vcp)); +} + +void +smb_vc_kill(struct smb_vc *vcp) +{ + smb_co_kill(VCTOCP(vcp)); +} + +/* + * Normally called via smb_vc_rele() + * after co_usecount drops to zero. + * Also called via: smb_vc_kill() + * + * Shutdown the VC to this server, + * invalidate shares linked with it. + */ +/*ARGSUSED*/ +static void +smb_vc_gone(struct smb_connobj *cp) +{ + struct smb_vc *vcp = CPTOVC(cp); + + /* + * Was smb_vc_disconnect(vcp); + */ + smb_iod_disconnect(vcp); + + /* Note: smb_iod_destroy in vc_free */ +} + +static void +smb_vc_free(struct smb_connobj *cp) +{ + struct smb_vc *vcp = CPTOVC(cp); + + /* + * The VC has no more references, so + * no locks should be needed here. + * Make sure the IOD is gone. + */ + smb_iod_destroy(vcp); + + if (vcp->vc_tdata) + SMB_TRAN_DONE(vcp, curproc); + + SMB_STRFREE(vcp->vc_username); + SMB_STRFREE(vcp->vc_srvname); + SMB_STRFREE(vcp->vc_pass); + SMB_STRFREE(vcp->vc_domain); + if (vcp->vc_paddr) { + smb_free_sockaddr(vcp->vc_paddr); + vcp->vc_paddr = NULL; + } + if (vcp->vc_laddr) { + smb_free_sockaddr(vcp->vc_laddr); + vcp->vc_laddr = NULL; + } + +/* + * We are not using the iconv routines here. So commenting them for now. + * REVISIT. + */ +#ifdef NOTYETDEFINED + if (vcp->vc_tolower) + iconv_close(vcp->vc_tolower); + if (vcp->vc_toupper) + iconv_close(vcp->vc_toupper); + if (vcp->vc_tolocal) + iconv_close(vcp->vc_tolocal); + if (vcp->vc_toserver) + iconv_close(vcp->vc_toserver); +#endif + if (vcp->vc_intok) + kmem_free(vcp->vc_intok, vcp->vc_intoklen); + if (vcp->vc_outtok) + kmem_free(vcp->vc_outtok, vcp->vc_outtoklen); + if (vcp->vc_negtok) + kmem_free(vcp->vc_negtok, vcp->vc_negtoklen); + + cv_destroy(&vcp->iod_exit); + rw_destroy(&vcp->iod_rqlock); + sema_destroy(&vcp->vc_sendlock); + cv_destroy(&vcp->vc_statechg); + smb_co_done(VCTOCP(vcp)); + kmem_free(vcp, sizeof (*vcp)); +} + + +/* + * Lookup share in the given VC. Share referenced and locked on return. + * VC expected to be locked on entry and will be left locked on exit. + */ +/*ARGSUSED*/ +int +smb_vc_lookupshare(struct smb_vc *vcp, struct smb_sharespec *shspec, + struct smb_cred *scred, struct smb_share **sspp) +{ + struct smb_connobj *co; + struct smb_share *ssp = NULL; + + ASSERT(MUTEX_HELD(&vcp->vc_lock)); + + *sspp = NULL; + + /* var, head, next_field */ + SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) { + ssp = CPTOSS(co); + + /* No new refs if _GONE is set. */ + if (ssp->ss_flags & SMBS_GONE) + continue; + + /* This has a hold, so no need to lock it. */ + if (strcmp(ssp->ss_name, shspec->name) == 0) + goto found; + } + return (ENOENT); + +found: + /* Return it with a hold. */ + smb_share_hold(ssp); + *sspp = ssp; + return (0); +} + + +static char smb_emptypass[] = ""; + +const char * +smb_vc_getpass(struct smb_vc *vcp) +{ + if (vcp->vc_pass) + return (vcp->vc_pass); + return (smb_emptypass); +} + +uint16_t +smb_vc_nextmid(struct smb_vc *vcp) +{ + uint16_t r; + + r = atomic_inc_16_nv(&vcp->vc_mid); + return (r); +} + +/* + * Get a pointer to the IP address suitable for passing to Trusted + * Extensions find_tpc() routine. Used by smbfs_mount_label_policy(). + * Compare this code to nfs_mount_label_policy() if problems arise. + * Without support for direct CIFS-over-TCP, we should always see + * an AF_NETBIOS sockaddr here. + */ +void * +smb_vc_getipaddr(struct smb_vc *vcp, int *ipvers) +{ + switch (vcp->vc_paddr->sa_family) { + case AF_NETBIOS: { + struct sockaddr_nb *snb; + + *ipvers = IPV4_VERSION; + /*LINTED*/ + snb = (struct sockaddr_nb *)vcp->vc_paddr; + return ((void *)&snb->snb_ipaddr); + } + case AF_INET: { + struct sockaddr_in *sin; + + *ipvers = IPV4_VERSION; + /*LINTED*/ + sin = (struct sockaddr_in *)vcp->vc_paddr; + return ((void *)&sin->sin_addr); + } + case AF_INET6: { + struct sockaddr_in6 *sin6; + + *ipvers = IPV6_VERSION; + /*LINTED*/ + sin6 = (struct sockaddr_in6 *)vcp->vc_paddr; + return ((void *)&sin6->sin6_addr); + } + default: + SMBSDEBUG("invalid address family %d\n", + vcp->vc_paddr->sa_family); + *ipvers = 0; + return (NULL); + } +} + +/* + * Share implementation + */ +/* + * Allocate share structure and attach it to the given VC + * Connection expected to be locked on entry. Share will be returned + * in locked state. + */ +/*ARGSUSED*/ +int +smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec, + struct smb_cred *scred, struct smb_share **sspp) +{ + static char objtype[] = "smb_ss"; + struct smb_share *ssp; + + ASSERT(MUTEX_HELD(&vcp->vc_lock)); + + ssp = kmem_zalloc(sizeof (struct smb_share), KM_SLEEP); + smb_co_init(SSTOCP(ssp), SMBL_SHARE, objtype); + ssp->ss_co.co_free = smb_share_free; + ssp->ss_co.co_gone = smb_share_gone; + + ssp->ss_name = smb_strdup(shspec->name); + ssp->ss_mount = NULL; + if (shspec->pass && shspec->pass[0]) + ssp->ss_pass = smb_strdup(shspec->pass); + ssp->ss_type = shspec->stype; + ssp->ss_tid = SMB_TID_UNKNOWN; + ssp->ss_mode = shspec->rights & SMBM_MASK; + ssp->ss_fsname = NULL; + smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp)); + *sspp = ssp; + + return (0); +} + +/* + * Normally called via smb_share_rele() + * after co_usecount drops to zero. + */ +static void +smb_share_free(struct smb_connobj *cp) +{ + struct smb_share *ssp = CPTOSS(cp); + + SMB_STRFREE(ssp->ss_name); + SMB_STRFREE(ssp->ss_pass); + SMB_STRFREE(ssp->ss_fsname); + smb_co_done(SSTOCP(ssp)); + kmem_free(ssp, sizeof (*ssp)); +} + +/* + * Normally called via smb_share_rele() + * after co_usecount drops to zero. + * Also called via: smb_share_kill() + */ +static void +smb_share_gone(struct smb_connobj *cp) +{ + struct smb_cred scred; + struct smb_share *ssp = CPTOSS(cp); + + smb_credinit(&scred, curproc, NULL); + smb_iod_shutdown_share(ssp); + smb_smb_treedisconnect(ssp, &scred); + smb_credrele(&scred); +} + +void +smb_share_hold(struct smb_share *ssp) +{ + smb_co_hold(SSTOCP(ssp)); +} + +void +smb_share_rele(struct smb_share *ssp) +{ + smb_co_rele(SSTOCP(ssp)); +} + +void +smb_share_kill(struct smb_share *ssp) +{ + smb_co_kill(SSTOCP(ssp)); +} + + +void +smb_share_invalidate(struct smb_share *ssp) +{ + ssp->ss_tid = SMB_TID_UNKNOWN; +} + +/* + * Returns NON-zero if the share is valid. + * Called with the share locked. + */ +int +smb_share_valid(struct smb_share *ssp) +{ + struct smb_vc *vcp = SSTOVC(ssp); + + ASSERT(MUTEX_HELD(&ssp->ss_lock)); + + if ((ssp->ss_flags & SMBS_CONNECTED) == 0) + return (0); + + if (ssp->ss_tid == SMB_TID_UNKNOWN) { + SMBIODEBUG("found TID unknown\n"); + ssp->ss_flags &= ~SMBS_CONNECTED; + } + + if (ssp->ss_vcgenid != vcp->vc_genid) { + SMBIODEBUG("wrong genid\n"); + ssp->ss_flags &= ~SMBS_CONNECTED; + } + + return (ssp->ss_flags & SMBS_CONNECTED); +} + +/* + * Connect (or reconnect) a share object. + * Called with the share locked. + */ +int +smb_share_tcon(struct smb_share *ssp) +{ + struct smb_vc *vcp = SSTOVC(ssp); + clock_t tmo; + int error; + + ASSERT(MUTEX_HELD(&ssp->ss_lock)); + + if (ssp->ss_flags & SMBS_CONNECTED) { + SMBIODEBUG("alread connected?"); + return (0); + } + + /* + * Wait for completion of any state changes + * that might be underway. + */ + while (ssp->ss_flags & SMBS_RECONNECTING) { + ssp->ss_conn_waiters++; + tmo = cv_wait_sig(&ssp->ss_conn_done, &ssp->ss_lock); + ssp->ss_conn_waiters--; + if (tmo == 0) { + /* Interrupt! */ + return (EINTR); + } + } + + /* Did someone else do it for us? */ + if (ssp->ss_flags & SMBS_CONNECTED) + return (0); + + /* + * OK, we'll do the work. + */ + ssp->ss_flags |= SMBS_RECONNECTING; + + /* Drop the lock while doing the call. */ + SMB_SS_UNLOCK(ssp); + error = smb_smb_treeconnect(ssp, &vcp->vc_scred); + SMB_SS_LOCK(ssp); + + if (!error) + ssp->ss_flags |= SMBS_CONNECTED; + ssp->ss_flags &= ~SMBS_RECONNECTING; + + /* They can all go ahead! */ + if (ssp->ss_conn_waiters) + cv_broadcast(&ssp->ss_conn_done); + + return (error); +} + +const char * +smb_share_getpass(struct smb_share *ssp) +{ + struct smb_vc *vcp; + + if (ssp->ss_pass) + return (ssp->ss_pass); + vcp = SSTOVC(ssp); + if (vcp->vc_pass) + return (vcp->vc_pass); + return (smb_emptypass); +} + +int +smb_share_count(void) +{ + struct smb_connobj *covc, *coss; + struct smb_vc *vcp; + zoneid_t zoneid = getzoneid(); + int nshares = 0; + + SMB_CO_LOCK(&smb_vclist); + SLIST_FOREACH(covc, &smb_vclist.co_children, co_next) { + vcp = CPTOVC(covc); + + /* VCs in other zones are invisibile. */ + if (vcp->vc_zoneid != zoneid) + continue; + + SMB_VC_LOCK(vcp); + + /* var, head, next_field */ + SLIST_FOREACH(coss, &(VCTOCP(vcp)->co_children), co_next) { + nshares++; + } + + SMB_VC_UNLOCK(vcp); + } + SMB_CO_UNLOCK(&smb_vclist); + + return (nshares); +} + +/* + * Solaris zones support + */ +/*ARGSUSED*/ +void +lingering_vc(struct smb_vc *vc) +{ + /* good place for a breakpoint */ + DEBUG_ENTER("lingering VC"); +} + +/* + * On zone shutdown, kill any IOD threads still running in this zone. + */ +/* ARGSUSED */ +void +nsmb_zone_shutdown(zoneid_t zoneid, void *data) +{ + struct smb_connobj *co; + struct smb_vc *vcp; + + SMB_CO_LOCK(&smb_vclist); + SLIST_FOREACH(co, &smb_vclist.co_children, co_next) { + vcp = CPTOVC(co); + + if (vcp->vc_zoneid != zoneid) + continue; + + /* + * This will close the connection, and + * cause the IOD thread to terminate. + */ + smb_vc_kill(vcp); + } + SMB_CO_UNLOCK(&smb_vclist); +} + +/* + * On zone destroy, kill any IOD threads and free all resources they used. + */ +/* ARGSUSED */ +void +nsmb_zone_destroy(zoneid_t zoneid, void *data) +{ + struct smb_connobj *co; + struct smb_vc *vcp; + + /* + * We will repeat what should have already happened + * in zone_shutdown to make things go away. + * + * There should have been an smb_vc_rele call + * by now for all VCs in the zone. If not, + * there's probably more we needed to do in + * the shutdown call. + */ + + SMB_CO_LOCK(&smb_vclist); + + if (smb_vclist.co_usecount > 1) { + SMBERROR("%d connections still active\n", + smb_vclist.co_usecount - 1); + } + + /* var, head, next_field */ + SLIST_FOREACH(co, &smb_vclist.co_children, co_next) { + vcp = CPTOVC(co); + + if (vcp->vc_zoneid != zoneid) + continue; + + /* Debugging */ + lingering_vc(vcp); + } + + SMB_CO_UNLOCK(&smb_vclist); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2000-2001 Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_conn.h,v 1.32.42.1 2005/05/27 02:35:29 lindak Exp $ + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SMB_CONN_H +#define _SMB_CONN_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/t_lock.h> +#include <sys/queue.h> /* for SLIST below */ +#include <sys/uio.h> +#include <netsmb/smb_dev.h> + +#ifndef _KERNEL +#error "Not _KERNEL?" +#endif + +/* + * Credentials of user/process for processing in the connection procedures + */ +typedef struct smb_cred { + pid_t vc_pid; + cred_t *vc_ucred; +} smb_cred_t; + +/* + * Common object flags + */ +#define SMBO_GONE 0x1000000 + +/* + * Bits in vc_flags (a.k.a. vc_co.co_flags) + * Many of these were duplicates of SMBVOPT_ flags + * and we now keep those too instead of merging + * them into vc_flags. + */ + +#define SMBV_LONGNAMES 0x0004 /* conn configured to use long names */ +#define SMBV_ENCRYPT 0x0008 /* server demands encrypted password */ +#define SMBV_WIN95 0x0010 /* used to apply bugfixes for this OS */ +#define SMBV_NT4 0x0020 /* used when NT4 issues invalid resp */ +#define SMBV_RECONNECTING 0x0040 /* conn in process of reconnection */ +/* 0x0200 unused - was SMBV_FAILED */ +#define SMBV_UNICODE 0x0400 /* conn configured to use Unicode */ +#define SMBV_EXT_SEC 0x0800 /* conn to use extended security */ + +/* + * Note: the common "obj" level uses this GONE flag by + * the name SMBO_GONE. Keep this alias as a reminder. + */ +#define SMBV_GONE SMBO_GONE + +/* + * bits in smb_share ss_flags (a.k.a. ss_co.co_flags) + */ +#define SMBS_RECONNECTING 0x0002 +#define SMBS_CONNECTED 0x0004 +#define SMBS_TCON_WAIT 0x0008 +#define SMBS_1980 0x0010 +/* + * ^ This partition can't handle dates before 1980. It's probably a FAT + * partition but could be some other ancient FS type + */ +#define SMBS_RESUMEKEYS 0x0010 /* must use resume keys */ +/* + * Note: the common "obj" level uses this GONE flag by + * the name SMBO_GONE. Keep this alias as a reminder. + */ +#define SMBS_GONE SMBO_GONE + +/* + * Negotiated protocol parameters + */ +struct smb_sopt { + int sv_proto; + int16_t sv_tz; /* offset in min relative to UTC */ + uint32_t sv_maxtx; /* maximum transmit buf size */ + uchar_t sv_sm; /* security mode */ + uint16_t sv_maxmux; /* max number of outstanding rq's */ + uint16_t sv_maxvcs; /* max number of VCs */ + uint16_t sv_rawmode; + uint32_t sv_maxraw; /* maximum raw-buffer size */ + uint32_t sv_skey; /* session key */ + uint32_t sv_caps; /* capabilites SMB_CAP_ */ +}; +typedef struct smb_sopt smb_sopt_t; + +/* + * network IO daemon states + * really connection states. + */ +enum smbiod_state { + SMBIOD_ST_NOTCONN, /* no connect request was made */ + SMBIOD_ST_RECONNECT, /* a [re]connect attempt is in progress */ + SMBIOD_ST_TRANACTIVE, /* transport level is up */ + SMBIOD_ST_NEGOACTIVE, /* completed negotiation */ + SMBIOD_ST_SSNSETUP, /* started (a) session setup */ + SMBIOD_ST_VCACTIVE, /* session established */ + SMBIOD_ST_DEAD /* connection broken, transport is down */ +}; + + +/* + * Info structures + */ +#define SMB_INFO_NONE 0 +#define SMB_INFO_VC 2 +#define SMB_INFO_SHARE 3 + +struct smb_vc_info { + int itype; + int usecount; + uid_t uid; /* user id of connection */ + gid_t gid; /* group of connection */ + mode_t mode; /* access mode */ + int flags; + enum smbiod_state iodstate; + struct smb_sopt sopt; + char srvname[SMB_MAXSRVNAMELEN+1]; + char vcname[128]; +}; +typedef struct smb_vc_info smb_vc_info_t; + +struct smb_share_info { + int itype; + int usecount; + ushort_t tid; /* TID */ + int type; /* share type */ + uid_t uid; /* user id of connection */ + gid_t gid; /* group of connection */ + mode_t mode; /* access mode */ + int flags; + char sname[128]; +}; +typedef struct smb_share_info smb_share_info_t; + +struct smb_rq; +/* This declares struct smb_rqhead */ +TAILQ_HEAD(smb_rqhead, smb_rq); + +#define SMB_NBTIMO 15 +#define SMB_DEFRQTIMO 30 /* 30 for oplock revoke/writeback */ +#define SMBWRTTIMO 60 +#define SMBSSNSETUPTIMO 60 +#define SMBNOREPLYWAIT (0) + +#define SMB_DIALECT(vcp) ((vcp)->vc_sopt.sv_proto) + +/* + * Connection object + */ + +#define SMB_CO_LOCK(cp) mutex_enter(&(cp)->co_lock) +#define SMB_CO_UNLOCK(cp) mutex_exit(&(cp)->co_lock) + +/* + * Common part of smb_vc, smb_share + * Locking: co_lock protects most + * fields in this struct, except + * as noted below: + */ +struct smb_connobj { + kmutex_t co_lock; + int co_level; /* SMBL_ */ + int co_flags; + int co_usecount; + + /* Note: must lock co_parent before child. */ + struct smb_connobj *co_parent; + + /* this.co_lock protects the co_children list */ + SLIST_HEAD(, smb_connobj) co_children; + + /* + * Linkage in parent's list of children. + * Must hold parent.co_lock to traverse. + */ + SLIST_ENTRY(smb_connobj) co_next; + + /* These two are set only at creation. */ + void (*co_gone)(struct smb_connobj *); + void (*co_free)(struct smb_connobj *); +}; +typedef struct smb_connobj smb_connobj_t; + +/* + * Virtual Circuit (session) to a server. + * This is the most (over)complicated part of SMB protocol. + * For the user security level (usl), each session with different remote + * user name has its own VC. + * It is unclear however, should share security level (ssl) allow additional + * VCs, because user name is not used and can be the same. On other hand, + * multiple VCs allows us to create separate sessions to server on a per + * user basis. + */ + +typedef struct smb_vc { + struct smb_connobj vc_co; + enum smbiod_state vc_state; + kcondvar_t vc_statechg; + ksema_t vc_sendlock; + + zoneid_t vc_zoneid; + char *vc_srvname; + struct sockaddr *vc_paddr; /* server addr */ + struct sockaddr *vc_laddr; /* local addr, if any */ + char *vc_domain; /* domain that defines username */ + char *vc_username; + char *vc_pass; /* password for usl case */ + uchar_t vc_lmhash[SMB_PWH_MAX]; + uchar_t vc_nthash[SMB_PWH_MAX]; + + uint_t vc_timo; /* default request timeout */ + int vc_maxvcs; /* maximum number of VC per conn */ + + void *vc_tolower; /* local charset */ + void *vc_toupper; /* local charset */ + void *vc_toserver; /* local charset to server one */ + void *vc_tolocal; /* server charset to local one */ + int vc_number; /* number of this VC from client side */ + int vc_genid; /* "generation ID" of this VC */ + uid_t vc_uid; /* user id of connection */ + gid_t vc_grp; /* group of connection */ + mode_t vc_mode; /* access mode */ + uint16_t vc_smbuid; /* auth. session ID from server */ + + uint8_t vc_hflags; /* or'ed with flags in the smb header */ + uint16_t vc_hflags2; /* or'ed with flags in the smb header */ + void *vc_tdata; /* transport control block */ + struct smb_tran_desc *vc_tdesc; + int vc_chlen; /* actual challenge length */ + uchar_t vc_challenge[SMB_MAXCHALLENGELEN]; + uint16_t vc_mid; /* multiplex id */ + int vc_vopt; /* local options SMBVOPT_ */ + struct smb_sopt vc_sopt; /* server options */ + struct smb_cred vc_scred; /* used in reconnect procedure */ + int vc_txmax; /* max tx/rx packet size */ + int vc_rxmax; /* max readx data size */ + int vc_wxmax; /* max writex data size */ + + /* Authentication tokens */ + size_t vc_intoklen; + caddr_t vc_intok; + size_t vc_outtoklen; + caddr_t vc_outtok; + size_t vc_negtoklen; + caddr_t vc_negtok; + + /* + * These members used to be in struct smbiod, + * which has been eliminated. + */ + krwlock_t iod_rqlock; /* iod_rqlist */ + struct smb_rqhead iod_rqlist; /* list of outstanding reqs */ + struct _kthread *iod_thr; /* the IOD (reader) thread */ + kcondvar_t iod_exit; /* IOD thread termination */ + int iod_flags; /* see SMBIOD_* below */ + int iod_newrq; /* send needed (iod_rqlock) */ + int iod_muxfull; /* maxmux limit reached */ + uint_t iod_rqwaiting; /* count of waiting requests */ +} smb_vc_t; + +#define vc_lock vc_co.co_lock +#define vc_flags vc_co.co_flags +#define vc_maxmux vc_sopt.sv_maxmux + +#define SMB_VC_LOCK(vcp) mutex_enter(&(vcp)->vc_lock) +#define SMB_VC_UNLOCK(vcp) mutex_exit(&(vcp)->vc_lock) + +#define SMB_UNICODE_STRINGS(vcp) ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) + +/* Bits in iod_flags */ +#define SMBIOD_RUNNING 0x0001 +#define SMBIOD_SHUTDOWN 0x0002 + +/* + * smb_share structure describes connection to the given SMB share (tree). + * Connection to share is always built on top of the VC. + */ + +typedef struct smb_share { + struct smb_connobj ss_co; + kcondvar_t ss_conn_done; /* wait for reconnect */ + int ss_conn_waiters; + char *ss_name; + char *ss_pass; /* share password, can be null */ + char *ss_fsname; + void *ss_mount; /* used for smb up/down */ + uint16_t ss_tid; /* TID */ + int ss_type; /* share type */ + mode_t ss_mode; /* access mode */ + int ss_vcgenid; /* check VC generation ID */ + uint32_t ss_maxfilenamelen; + int ss_sopt; /* local options SMBSOPT_ */ +} smb_share_t; + +#define ss_lock ss_co.co_lock +#define ss_flags ss_co.co_flags + +#define SMB_SS_LOCK(ssp) mutex_enter(&(ssp)->ss_lock) +#define SMB_SS_UNLOCK(ssp) mutex_exit(&(ssp)->ss_lock) + +#define CPTOVC(cp) ((struct smb_vc *)(cp)) +#define VCTOCP(vcp) (&(vcp)->vc_co) + +#define CPTOSS(cp) ((struct smb_share *)(cp)) +#define SSTOVC(ssp) CPTOVC(((ssp)->ss_co.co_parent)) +#define SSTOCP(ssp) (&(ssp)->ss_co) + +/* + * This is used internally to pass all the info about + * some VC that an ioctl caller is looking for. + */ +struct smb_vcspec { + char *srvname; + struct sockaddr *sap; + struct sockaddr *lap; + int optflags; + char *domain; + char *username; + char *pass; + uid_t owner; + gid_t group; + mode_t mode; + mode_t rights; + char *localcs; + char *servercs; + size_t toklen; + caddr_t tok; +}; +typedef struct smb_vcspec smb_vcspec_t; + +/* + * This is used internally to pass all the info about + * some share that an ioctl caller is looking for. + */ +struct smb_sharespec { + char *name; + char *pass; + mode_t mode; + mode_t rights; + uid_t owner; + gid_t group; + int stype; + int optflags; +}; +typedef struct smb_sharespec smb_sharespec_t; + + +/* + * Call-back operations vector, so the netsmb module + * can notify smbfs about events affecting mounts. + * Installed in netsmb after smbfs loads. + */ +/* #define NEED_SMBFS_CALLBACKS 1 */ +#ifdef NEED_SMBFS_CALLBACKS +typedef struct smb_fscb { + void (*fscb_dead)(smb_share_t *); + void (*fscb_down)(smb_share_t *); + void (*fscb_up)(smb_share_t *); +} smb_fscb_t; +/* Install the above vector, or pass NULL to clear it. */ +int smb_fscb_set(smb_fscb_t *); +#endif /* NEED_SMBFS_CALLBACKS */ + +/* + * IOD functions + */ +int smb_iod_create(struct smb_vc *vcp); +int smb_iod_destroy(struct smb_vc *vcp); +int smb_iod_connect(struct smb_vc *vcp); +int smb_iod_disconnect(struct smb_vc *vcp); +int smb_iod_addrq(struct smb_rq *rqp); +int smb_iod_multirq(struct smb_rq *rqp); +int smb_iod_waitrq(struct smb_rq *rqp); +int smb_iod_removerq(struct smb_rq *rqp); +void smb_iod_shutdown_share(struct smb_share *ssp); +void smb_iod_notify_down(struct smb_vc *vcp); +void smb_iod_notify_up(struct smb_vc *vcp); + +/* + * Session level functions + */ +int smb_sm_init(void); +int smb_sm_idle(void); +void smb_sm_done(void); + +int smb_sm_negotiate(struct smb_vcspec *vcspec, + struct smb_cred *scred, struct smb_vc **vcpp); +int smb_sm_ssnsetup(struct smb_vcspec *vcspec, + struct smb_cred *scred, struct smb_vc *vcp); +int smb_sm_tcon(struct smb_sharespec *shspec, struct smb_cred *scred, + struct smb_vc *vcp, struct smb_share **sspp); + +/* + * VC level functions + */ +int smb_vc_setup(struct smb_vcspec *vcspec, struct smb_cred *scred, + struct smb_vc *vcp, int is_ss); +int smb_vc_create(struct smb_vcspec *vcspec, + struct smb_cred *scred, struct smb_vc **vcpp); +int smb_vc_negotiate(struct smb_vc *vcp, struct smb_cred *scred); +int smb_vc_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred); +void smb_vc_hold(struct smb_vc *vcp); +void smb_vc_rele(struct smb_vc *vcp); +void smb_vc_kill(struct smb_vc *vcp); +int smb_vc_lookupshare(struct smb_vc *vcp, struct smb_sharespec *shspec, + struct smb_cred *scred, struct smb_share **sspp); +const char *smb_vc_getpass(struct smb_vc *vcp); +uint16_t smb_vc_nextmid(struct smb_vc *vcp); +void *smb_vc_getipaddr(struct smb_vc *vcp, int *ipvers); + +/* + * share level functions + */ +int smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec, + struct smb_cred *scred, struct smb_share **sspp); + +void smb_share_hold(struct smb_share *ssp); +void smb_share_rele(struct smb_share *ssp); +void smb_share_kill(struct smb_share *ssp); + +void smb_share_invalidate(struct smb_share *ssp); +int smb_share_tcon(struct smb_share *ssp); +int smb_share_valid(struct smb_share *ssp); +const char *smb_share_getpass(struct smb_share *ssp); +int smb_share_count(void); + +/* + * SMB protocol level functions + */ +int smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred); +int smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred); +int smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred); +int smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred); +int smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred); +int smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo); +#ifdef APPLE +int smb_smb_checkdir(struct smb_share *ssp, void *dnp, + char *name, int nmlen, struct smb_cred *scred); +#endif +int smb_rwuio(struct smb_share *ssp, uint16_t fid, uio_rw_t rw, + uio_t *uiop, struct smb_cred *scred, int timo); + +#endif /* _SMB_CONN_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_crypt.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2000-2001, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_crypt.c,v 1.13 2005/01/26 23:50:50 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/proc.h> +#include <sys/fcntl.h> +#include <sys/socket.h> +#include <sys/md4.h> +#include <sys/md5.h> +#include <sys/des.h> +#include <sys/kmem.h> +#include <sys/crypto/api.h> +#include <sys/crypto/common.h> +#include <sys/cmn_err.h> + +#include <netsmb/smb_osdep.h> +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> +#include <netsmb/smb_dev.h> + +static uchar_t N8[] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25}; + +static void +smb_E(const uchar_t *key, uchar_t *data, uchar_t *dest) +{ + int rv; + uchar_t kk[8]; + crypto_mechanism_t mech; + crypto_data_t d1, d2; + crypto_key_t keyt; + + + bzero(&d1, sizeof (crypto_data_t)); + bzero(&d2, sizeof (crypto_data_t)); + /* + * 'Key' here is the username - 7-bytes. Convert that to + * to a 8-byte string. + */ + kk[0] = key[0] & 0xfe; + kk[1] = key[0] << 7 | (key[1] >> 1 & 0xfe); + kk[2] = key[1] << 6 | (key[2] >> 2 & 0xfe); + kk[3] = key[2] << 5 | (key[3] >> 3 & 0xfe); + kk[4] = key[3] << 4 | (key[4] >> 4 & 0xfe); + kk[5] = key[4] << 3 | (key[5] >> 5 & 0xfe); + kk[6] = key[5] << 2 | (key[6] >> 6 & 0xfe); + kk[7] = key[6] << 1; + + keyt.ck_format = CRYPTO_KEY_RAW; + keyt.ck_length = 8 * 8; + keyt.ck_data = (void *)kk; + + d1.cd_format = CRYPTO_DATA_RAW; + d1.cd_length = 8; + d1.cd_offset = 0; + d1.cd_raw.iov_len = 8; + d1.cd_raw.iov_base = (void *)data; + + d2.cd_format = CRYPTO_DATA_RAW; + d2.cd_length = 8; + d2.cd_offset = 0; + d2.cd_raw.iov_len = 8; + d2.cd_raw.iov_base = (void *)dest; + + mech.cm_type = crypto_mech2id(SUN_CKM_DES_ECB); + if (mech.cm_type == CRYPTO_MECH_INVALID) + cmn_err(CE_NOTE, "Invalid algorithm\n"); + mech.cm_param = NULL; + mech.cm_param_len = 0; + + rv = crypto_encrypt(&mech, &d1, &keyt, NULL, &d2, NULL); + if (rv != CRYPTO_SUCCESS) + SMBSDEBUG("crypto_encrypt failed.\n"); +} + +/* + * Compute the LM hash, which is used to compute the LM response. + */ +void +smb_oldlm_hash(const char *apwd, uchar_t *lmhash) +{ + uchar_t P14[14+1]; + + /* Convert apwd to upper case, zero extend. */ + bzero(P14, sizeof (P14)); + smb_toupper(apwd, (char *)P14, 14); + + /* + * lmhash = concat(Ex(P14, N8), zeros(5)); + */ + bzero(lmhash, 21); + smb_E(P14, N8, lmhash); + smb_E(P14 + 7, N8, lmhash + 8); +} + +/* + * Compute an LM or NTLM response given the LM or NTLM hash and a + * challenge. Note: This now replaces smb_ntlmresponse which + * used to compute a different hash and then do the same + * response computation as found here. Now that the hash + * is computed by the caller, this is used for both. + */ +int +smb_lmresponse(const uchar_t *hash, uchar_t *C8, uchar_t *RN) +{ + + smb_E(hash, C8, RN); + smb_E(hash + 7, C8, RN + 8); + smb_E(hash + 14, C8, RN + 16); + + return (0); +} + +/* + * Compute the NTLMv1 hash, which is used to compute both NTLMv1 and + * NTLMv2 responses. + */ +void +smb_ntlmv1hash(const char *apwd, uchar_t *v1hash) +{ + u_int16_t *unipwd; + MD4_CTX *ctxp; + size_t alen, unilen; + + alen = strlen(apwd); + unipwd = kmem_alloc(alen * 2, KM_SLEEP); + /* + * v1hash = concat(MD4(U(apwd)), zeros(5)); + */ + unilen = smb_strtouni(unipwd, apwd, alen, UCONV_IGNORE_NULL); + + ctxp = kmem_alloc(sizeof (MD4_CTX), KM_SLEEP); + MD4Init(ctxp); + MD4Update(ctxp, unipwd, unilen); + bzero(v1hash, 21); + MD4Final(v1hash, ctxp); + + kmem_free(ctxp, sizeof (MD4_CTX)); + kmem_free(unipwd, alen * 2); +} + +/* + * Note: smb_ntlmresponse() is gone. + * Use: smb_lmresponse() instead. + */ + +static void +HMACT64(const uchar_t *key, size_t key_len, const uchar_t *data, + size_t data_len, uchar_t *digest) +{ + MD5_CTX context; + uchar_t k_ipad[64]; /* inner padding - key XORd with ipad */ + uchar_t k_opad[64]; /* outer padding - key XORd with opad */ + int i; + + /* if key is longer than 64 bytes use only the first 64 bytes */ + if (key_len > 64) + key_len = 64; + + /* + * The HMAC-MD5 (and HMACT64) transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, data)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and data is the data being protected. + */ + + /* start out by storing key in pads */ + bzero(k_ipad, sizeof (k_ipad)); + bzero(k_opad, sizeof (k_opad)); + bcopy(key, k_ipad, key_len); + bcopy(key, k_opad, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < 64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* + * perform inner MD5 + */ + MD5Init(&context); /* init context for 1st pass */ + MD5Update(&context, k_ipad, 64); /* start with inner pad */ + MD5Update(&context, data, data_len); /* then data of datagram */ + MD5Final(digest, &context); /* finish up 1st pass */ + + /* + * perform outer MD5 + */ + MD5Init(&context); /* init context for 2nd pass */ + MD5Update(&context, k_opad, 64); /* start with outer pad */ + MD5Update(&context, digest, 16); /* then results of 1st hash */ + MD5Final(digest, &context); /* finish up 2nd pass */ +} + +/* + * Compute an NTLMv2 response given the 21 byte NTLM(v1) hash, + * the user name, the destination workgroup/domain name, + * a challenge, and the blob. + */ +int +smb_ntlmv2response(const uchar_t *v1hash, const uchar_t *user, + const uchar_t *destination, uchar_t *C8, const uchar_t *blob, + size_t bloblen, uchar_t **RN, size_t *RNlen) +{ + u_int16_t *uniuser, *unidest; + size_t uniuserlen, unidestlen; + uchar_t v2hash[16]; + size_t len; + size_t datalen; + uchar_t *data, *data1; + size_t v2resplen; + uchar_t *v2resp; + + /* + * v2hash=HMACT64(v1hash, 16, concat(upcase(user), upcase(destination)) + * We assume that user and destination are supplied to us as + * upper-case UTF-8. + */ + len = strlen((char *)user); + uniuser = kmem_alloc(len * sizeof (u_int16_t) + 1, KM_SLEEP); + uniuserlen = smb_strtouni(uniuser, (char *)user, len, + UCONV_IGNORE_NULL); + len = strlen((char *)destination); + unidest = kmem_alloc(len * sizeof (u_int16_t) + 1, KM_SLEEP); + unidestlen = smb_strtouni(unidest, (char *)destination, len, + UCONV_IGNORE_NULL); + datalen = uniuserlen + unidestlen; + data = kmem_alloc(datalen, KM_SLEEP); + bcopy(uniuser, data, uniuserlen); + bcopy(unidest, data + uniuserlen, unidestlen); + kmem_free(uniuser, strlen((char *)user) * sizeof (u_int16_t) + 1); + kmem_free(unidest, len * sizeof (u_int16_t) + 1); + HMACT64(v1hash, 16, data, datalen, v2hash); + kmem_free(data, datalen); + + datalen = 8 + bloblen; + data1 = kmem_alloc(datalen, KM_SLEEP); + bcopy(C8, data1, 8); + bcopy(blob, data1 + 8, bloblen); + v2resplen = 16 + bloblen; + v2resp = kmem_alloc(v2resplen, KM_SLEEP); + HMACT64(v2hash, 16, data1, datalen, v2resp); + kmem_free(data1, datalen); + bcopy(blob, v2resp + 16, bloblen); + *RN = v2resp; + *RNlen = v2resplen; + return (0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,938 @@ +/* + * Copyright (c) 2000-2001 Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_dev.c,v 1.21 2004/12/13 00:25:18 lindak Exp $ + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/sysmacros.h> +#include <sys/uio.h> +#include <sys/buf.h> +#include <sys/modctl.h> +#include <sys/open.h> +#include <sys/file.h> +#include <sys/kmem.h> +#include <sys/conf.h> +#include <sys/cmn_err.h> +#include <sys/stat.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/sunldi.h> +#include <sys/policy.h> +#include <sys/zone.h> +#include <sys/pathname.h> +#include <sys/mount.h> +#include <sys/sdt.h> +#include <fs/fs_subr.h> +#include <sys/modctl.h> +#include <sys/devops.h> +#include <sys/thread.h> +#include <sys/mkdev.h> +#include <sys/types.h> +#include <sys/zone.h> + +#ifdef APPLE +#include <sys/smb_apple.h> +#else +#include <netsmb/smb_osdep.h> +#endif + +#include <netsmb/mchain.h> /* for "htoles()" */ + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> +#include <netsmb/smb_dev.h> +#include <netsmb/smb_pass.h> + +/* for version checks */ +const uint32_t nsmb_version = NSMB_VERSION; + +/* + * Userland code loops through minor #s 0 to 1023, looking for one which opens. + * Intially we create minor 0 and leave it for anyone. Minor zero will never + * actually get used - opening triggers creation of another (but private) minor, + * which userland code will get to and mark busy. + */ +#define SMBMINORS 1024 +static void *statep; +static major_t nsmb_major; +static minor_t nsmb_minor = 1; + +#define NSMB_MAX_MINOR (1 << 8) +#define NSMB_MIN_MINOR (NSMB_MAX_MINOR + 1) + +#define ILP32 1 +#define LP64 2 + +static kmutex_t dev_lck; + +/* Zone support */ +zone_key_t nsmb_zone_key; +extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data); +extern void nsmb_zone_destroy(zoneid_t zoneid, void *data); + +/* + * cb_ops device operations. + */ +static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp); +static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp); +static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, + cred_t *credp, int *rvalp); +/* smbfs cb_ops */ +static struct cb_ops nsmb_cbops = { + nsmb_open, /* open */ + nsmb_close, /* close */ + nodev, /* strategy */ + nodev, /* print */ + nodev, /* dump */ + nodev, /* read */ + nodev, /* write */ + nsmb_ioctl, /* ioctl */ + nodev, /* devmap */ + nodev, /* mmap */ + nodev, /* segmap */ + nochpoll, /* poll */ + ddi_prop_op, /* prop_op */ + NULL, /* stream */ + D_MP, /* cb_flag */ + CB_REV, /* rev */ + nodev, /* int (*cb_aread)() */ + nodev /* int (*cb_awrite)() */ +}; + +/* + * Device options + */ +static int nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); +static int nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); +static int nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, + void *arg, void **result); + +static struct dev_ops nsmb_ops = { + DEVO_REV, /* devo_rev, */ + 0, /* refcnt */ + nsmb_getinfo, /* info */ + nulldev, /* identify */ + nulldev, /* probe */ + nsmb_attach, /* attach */ + nsmb_detach, /* detach */ + nodev, /* reset */ + &nsmb_cbops, /* driver ops - devctl interfaces */ + NULL, /* bus operations */ + NULL /* power */ +}; + +/* + * Module linkage information. + */ + +static struct modldrv nsmb_modldrv = { + &mod_driverops, /* Driver module */ + "SMBFS network driver v" NSMB_VER_STR, + &nsmb_ops /* Driver ops */ +}; + +static struct modlinkage nsmb_modlinkage = { + MODREV_1, + (void *)&nsmb_modldrv, + NULL +}; + +int +_init(void) +{ + int error; + + ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1); + + /* Can initialize some mutexes also. */ + mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL); + /* + * Create a major name and number. + */ + nsmb_major = ddi_name_to_major(NSMB_NAME); + nsmb_minor = 0; + + /* Connection data structures. */ + (void) smb_sm_init(); + + /* Initialize password Key chain DB. */ + smb_pkey_init(); + + zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown, + nsmb_zone_destroy); + + /* + * Install the module. Do this after other init, + * to prevent entrances before we're ready. + */ + if ((error = mod_install((&nsmb_modlinkage))) != 0) { + + /* Same as 2nd half of _fini */ + (void) zone_key_delete(nsmb_zone_key); + smb_pkey_fini(); + smb_sm_done(); + mutex_destroy(&dev_lck); + ddi_soft_state_fini(&statep); + + return (error); + } + + return (0); +} + +int +_fini(void) +{ + int status; + + /* + * Prevent unload if we have active VCs + * or stored passwords + */ + if ((status = smb_sm_idle()) != 0) + return (status); + if ((status = smb_pkey_idle()) != 0) + return (status); + + /* + * Remove the module. Do this before destroying things, + * to prevent new entrances while we're destorying. + */ + if ((status = mod_remove(&nsmb_modlinkage)) != 0) { + return (status); + } + + (void) zone_key_delete(nsmb_zone_key); + + /* Destroy password Key chain DB. */ + smb_pkey_fini(); + + smb_sm_done(); + + mutex_destroy(&dev_lck); + ddi_soft_state_fini(&statep); + + return (status); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&nsmb_modlinkage, modinfop)); +} + +/*ARGSUSED*/ +static int +nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) +{ + int ret = DDI_SUCCESS; + + switch (cmd) { + case DDI_INFO_DEVT2DEVINFO: + *result = 0; + break; + case DDI_INFO_DEVT2INSTANCE: + *result = 0; + break; + default: + ret = DDI_FAILURE; + } + return (ret); +} + +static int +nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + smb_dev_t *sdp; + + if (cmd != DDI_ATTACH) + return (DDI_FAILURE); + /* + * only one instance - but we clone using the open routine + */ + if (ddi_get_instance(dip) > 0) + return (DDI_FAILURE); + + mutex_enter(&dev_lck); + + /* + * This is the Zero'th minor device which is created. + */ + if (ddi_soft_state_zalloc(statep, 0) == DDI_FAILURE) { + cmn_err(CE_WARN, "nsmb_attach: soft state alloc"); + goto attach_failed; + } + if (ddi_create_minor_node(dip, "nsmb", S_IFCHR, 0, DDI_PSEUDO, + NULL) == DDI_FAILURE) { + cmn_err(CE_WARN, "nsmb_attach: create minor"); + goto attach_failed; + } + if ((sdp = ddi_get_soft_state(statep, 0)) == NULL) { + cmn_err(CE_WARN, "nsmb_attach: get soft state"); + ddi_remove_minor_node(dip, NULL); + goto attach_failed; + } + + /* + * Need to see if this field is required. + * REVISIT + */ + sdp->smb_dip = dip; + sdp->sd_seq = 0; + sdp->sd_opened = 1; + + mutex_exit(&dev_lck); + ddi_report_dev(dip); + return (DDI_SUCCESS); + +attach_failed: + ddi_soft_state_free(statep, 0); + mutex_exit(&dev_lck); + return (DDI_FAILURE); +} + +/*ARGSUSED*/ +static int +nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + + if (cmd != DDI_DETACH) + return (DDI_FAILURE); + if (ddi_get_instance(dip) > 0) + return (DDI_FAILURE); + + ddi_soft_state_free(statep, 0); + ddi_remove_minor_node(dip, NULL); + + return (DDI_SUCCESS); +} + +/*ARGSUSED*/ +static int +nsmb_ioctl(dev_t dev, + int cmd, + intptr_t arg, + int mode, + cred_t *credp, + int *rvalp) +{ + smb_dev_t *sdp; + struct smb_vc *vcp = NULL; + struct smb_share *ssp = NULL; + struct smb_cred scred; + int err, error; + uid_t uid; + + /* Free any+all of these at end of switch. */ + smbioc_lookup_t *sioc = NULL; + smbioc_rq_t *srq = NULL; + smbioc_rw_t *rwrq = NULL; + smbioc_t2rq_t *strq = NULL; + smbioc_pk_t *pk = NULL; + + sdp = ddi_get_soft_state(statep, getminor(dev)); + if (sdp == NULL) { + return (DDI_FAILURE); + } + if ((sdp->sd_flags & NSMBFL_OPEN) == 0) { + return (EBADF); + } + + /* + * Dont give access if the zone id is not as the same as we + * set in the nsmb_open or dont belong to the global zone. + * Check if the user belongs to this zone.. + */ + if (sdp->zoneid != getzoneid()) + return (EIO); + if (cmd != SMBIOC_TDIS && + zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN) + return (EIO); + + + error = 0; + smb_credinit(&scred, curproc, credp); + switch (cmd) { + case SMBIOC_GETVERS: + ddi_copyout(&nsmb_version, (void *)arg, + sizeof (nsmb_version), mode); + break; + + case SMBIOC_REQUEST: + if (sdp->sd_share == NULL) { + error = ENOTCONN; + break; + } + srq = kmem_alloc(sizeof (*srq), KM_SLEEP); + if (ddi_copyin((void *) arg, srq, + sizeof (*srq), mode)) { + error = EFAULT; + break; + } + error = smb_usr_simplerequest(sdp->sd_share, + srq, &scred); + ddi_copyout(srq, (void *)arg, + SMBIOC_RQ_COPYOUT_SIZE, mode); + break; + + case SMBIOC_T2RQ: + if (sdp->sd_share == NULL) { + error = ENOTCONN; + break; + } + strq = kmem_alloc(sizeof (*strq), KM_SLEEP); + if (ddi_copyin((void *)arg, strq, + sizeof (*strq), mode)) { + error = EFAULT; + break; + } + error = smb_usr_t2request(sdp->sd_share, strq, &scred); + ddi_copyout(strq, (void *)arg, + SMBIOC_T2RQ_COPYOUT_SIZE, mode); + break; + + case SMBIOC_READ: + case SMBIOC_WRITE: + if ((ssp = sdp->sd_share) == NULL) { + error = ENOTCONN; + break; + } + rwrq = kmem_alloc(sizeof (*rwrq), KM_SLEEP); + if (ddi_copyin((void *)arg, rwrq, + sizeof (*rwrq), mode)) { + error = EFAULT; + break; + } + error = smb_usr_rw(ssp, rwrq, cmd, &scred); + ddi_copyout(rwrq, (void *)arg, + SMBIOC_RW_COPYOUT_SIZE, mode); + break; + + case SMBIOC_NEGOTIATE: + /* Should be no VC (and no share) */ + if (sdp->sd_vc || sdp->sd_share) { + error = EISCONN; + break; + } + sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP); + if (ddi_copyin((void *)arg, sioc, + sizeof (*sioc), mode)) { + error = EFAULT; + break; + } + vcp = NULL; + ssp = NULL; + error = smb_usr_negotiate(sioc, &scred, &vcp); + if (error) + break; + if (vcp) { + /* + * The VC has a hold from _negotiate + * which we keep until nsmb_close(). + */ + sdp->sd_level = SMBL_VC; + sdp->sd_vc = vcp; + /* + * If we just created this VC, and + * this minor is doing the setup, + * keep track of that fact here. + */ + if (vcp->vc_state < SMBIOD_ST_VCACTIVE) + sdp->sd_flags |= NSMBFL_NEWVC; + + } + /* + * Copyout the "out token" (security blob). + * + * This code used to be near the end of + * smb_usr_negotiate(). Moved the copyout + * calls here so we know the "mode" + */ + if (vcp->vc_outtok) { + /* + * Note: will copyout sioc below + * including sioc.vc_outtoklen, + * so we no longer put the length + * at the start of the outtok data. + */ + sioc->ioc_ssn.ioc_outtoklen = + vcp->vc_outtoklen; + err = ddi_copyout( + vcp->vc_outtok, + sioc->ioc_ssn.ioc_outtok, + vcp->vc_outtoklen, mode); + if (err) { + error = EFAULT; + break; + } + /* + * Save this blob in vc_negtok. + * We need it in case we have to + * reconnect. + * + * Set vc_negtok = vc_outtok + * but free vc_negtok first. + */ + if (vcp->vc_negtok) { + kmem_free( + vcp->vc_negtok, + vcp->vc_negtoklen); + vcp->vc_negtok = NULL; + vcp->vc_negtoklen = 0; + } + vcp->vc_negtok = vcp->vc_outtok; + vcp->vc_negtoklen = vcp->vc_outtoklen; + vcp->vc_outtok = NULL; + vcp->vc_outtoklen = 0; + } + /* + * Added copyout here of (almost) + * the whole struct, even though + * the lib only needs _outtoklen. + * We may put other things in this + * struct that user-land needs. + */ + err = ddi_copyout(sioc, (void *)arg, + SMBIOC_LOOK_COPYOUT_SIZE, mode); + if (err) + error = EFAULT; + break; + + case SMBIOC_SSNSETUP: + /* Must have a VC, but no share. */ + if (sdp->sd_share) { + error = EISCONN; + break; + } + if (!sdp->sd_vc) { + error = ENOTCONN; + break; + } + sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP); + if (ddi_copyin((void *)arg, sioc, + sizeof (*sioc), mode)) { + error = EFAULT; + break; + } + vcp = sdp->sd_vc; + ssp = NULL; + error = smb_usr_ssnsetup(sioc, &scred, vcp); + if (error) + break; + /* + * If this minor has finished ssn setup, + * turn off the NEWVC flag, otherwise we + * will kill this VC when we close. + */ + if (vcp->vc_state == SMBIOD_ST_VCACTIVE) + sdp->sd_flags &= ~NSMBFL_NEWVC; + /* + * Copyout the "out token" (security blob). + * + * This code used to be near the end of + * smb_usr_ssnsetup(). Moved the copyout + * calls here so we know the "mode" + */ + if (vcp->vc_outtok) { + /* + * Note: will copyout sioc below + * including sioc.vc_outtoklen, + * so we no longer put the length + * at the start of the outtok data. + */ + sioc->ioc_ssn.ioc_outtoklen = + vcp->vc_outtoklen; + err = ddi_copyout( + vcp->vc_outtok, + sioc->ioc_ssn.ioc_outtok, + vcp->vc_outtoklen, mode); + if (err) { + error = EFAULT; + break; + } + /* + * Done with vc_outtok. Similar, + * but NOT the same as after the + * smb_usr_negotiate call above. + */ + kmem_free( + vcp->vc_outtok, + vcp->vc_outtoklen); + vcp->vc_outtok = NULL; + vcp->vc_outtoklen = 0; + } + /* Added copyout here... (see above) */ + err = ddi_copyout(sioc, (void *)arg, + SMBIOC_LOOK_COPYOUT_SIZE, mode); + if (err) + error = EFAULT; + break; + + case SMBIOC_TCON: + /* Must have a VC, but no share. */ + if (sdp->sd_share) { + error = EISCONN; + break; + } + if (!sdp->sd_vc) { + error = ENOTCONN; + break; + } + sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP); + if (ddi_copyin((void *)arg, sioc, + sizeof (*sioc), mode)) { + error = EFAULT; + break; + } + vcp = sdp->sd_vc; + ssp = NULL; + error = smb_usr_tcon(sioc, &scred, vcp, &ssp); + if (error) + break; + if (ssp) { + /* + * The share has a hold from _tcon + * which we keep until nsmb_close() + * or the SMBIOC_TDIS below. + */ + sdp->sd_share = ssp; + sdp->sd_level = SMBL_SHARE; + } + /* No need for copyout here. */ + break; + + case SMBIOC_TDIS: + if (sdp->sd_share == NULL) { + error = ENOTCONN; + break; + } + smb_share_rele(sdp->sd_share); + sdp->sd_share = NULL; + sdp->sd_level = SMBL_VC; + break; + case SMBIOC_FLAGS2: + if (sdp->sd_share == NULL) { + error = ENOTCONN; + break; + } + if (!sdp->sd_vc) { + error = ENOTCONN; + break; + } + vcp = sdp->sd_vc; + /* + * Return the flags2 value. + */ + ddi_copyout(&vcp->vc_hflags2, (void *)arg, + sizeof (u_int16_t), mode); + break; + + case SMBIOC_PK_ADD: + pk = kmem_alloc(sizeof (*pk), KM_SLEEP); + if (ddi_copyin((void *)arg, pk, + sizeof (*pk), mode)) { + error = EFAULT; + break; + } + error = smb_pkey_add(pk, credp); + break; + + case SMBIOC_PK_DEL: + pk = kmem_alloc(sizeof (*pk), KM_SLEEP); + if (ddi_copyin((void *)arg, pk, + sizeof (*pk), mode)) { + error = EFAULT; + break; + } + error = smb_pkey_del(pk, credp); + break; + + case SMBIOC_PK_CHK: + pk = kmem_alloc(sizeof (*pk), KM_SLEEP); + if (ddi_copyin((void *)arg, pk, + sizeof (*pk), mode)) { + error = EFAULT; + break; + } + error = smb_pkey_check(pk, credp); + /* + * Note: Intentionally DO NOT copyout + * the pasword here. It can only be + * retrieved by internal calls. This + * ioctl only tells the caller if the + * keychain entry exists. + */ + break; + + case SMBIOC_PK_DEL_OWNER: + uid = crgetruid(credp); + error = smb_pkey_deluid(uid, credp); + break; + + case SMBIOC_PK_DEL_EVERYONE: + uid = (uid_t)-1; + error = smb_pkey_deluid(uid, credp); + break; + + default: + error = ENODEV; + } + + /* + * Let's just do all the kmem_free stuff HERE, + * instead of at every switch break. + */ + + /* SMBIOC_REQUEST */ + if (srq) + kmem_free(srq, sizeof (*srq)); + + /* SMBIOC_T2RQ */ + if (strq) + kmem_free(strq, sizeof (*strq)); + + /* SMBIOC_READ */ + /* SMBIOC_WRITE */ + if (rwrq) + kmem_free(rwrq, sizeof (*rwrq)); + + /* SMBIOC_NEGOTIATE */ + /* SMBIOC_SSNSETUP */ + /* SMBIOC_TCON */ + if (sioc) { + /* + * This data structure may contain + * cleartext passwords, so zap it. + */ + bzero(sioc, sizeof (*sioc)); + kmem_free(sioc, sizeof (*sioc)); + } + + /* SMBIOC_PK_... */ + if (pk) { + /* + * This data structure may contain + * cleartext passwords, so zap it. + */ + bzero(pk, sizeof (*pk)); + kmem_free(pk, sizeof (*pk)); + } + + smb_credrele(&scred); + + return (error); +} + +/*ARGSUSED*/ +static int +nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr) +{ + major_t new_major; + smb_dev_t *sdp, *sdv; + + mutex_enter(&dev_lck); + for (; ; ) { + minor_t start = nsmb_minor; + do { + if (nsmb_minor >= MAXMIN32) { + if (nsmb_major == getmajor(*dev)) + nsmb_minor = NSMB_MIN_MINOR; + else + nsmb_minor = 0; + } else { + nsmb_minor++; + } + sdv = ddi_get_soft_state(statep, nsmb_minor); + } while ((sdv != NULL) && (nsmb_minor != start)); + if (nsmb_minor == start) { + /* + * The condition we need to solve here is all the + * MAXMIN32(~262000) minors numbers are reached. We + * need to create a new major number. + * zfs uses getudev() to create a new major number. + */ + if ((new_major = getudev()) == (major_t)-1) { + cmn_err(CE_WARN, + "nsmb: Can't get unique major " + "device number."); + mutex_exit(&dev_lck); + return (-1); + } + nsmb_major = new_major; + nsmb_minor = 0; + } else { + break; + } + } + + /* + * This is called by mount or open call. + * The open() routine is passed a pointer to a device number so + * that the driver can change the minor number. This allows + * drivers to dynamically create minor instances of the dev- + * ice. An example of this might be a pseudo-terminal driver + * that creates a new pseudo-terminal whenever it is opened. + * A driver that chooses the minor number dynamically, normally + * creates only one minor device node in attach(9E) with + * ddi_create_minor_node(9F) then changes the minor number com- + * ponent of *devp using makedevice(9F) and getmajor(9F) The + * driver needs to keep track of available minor numbers inter- + * nally. + * Stuff the structure smb_dev. + * return. + */ + + if (ddi_soft_state_zalloc(statep, nsmb_minor) == DDI_FAILURE) { + mutex_exit(&dev_lck); + return (ENXIO); + } + if ((sdp = ddi_get_soft_state(statep, nsmb_minor)) == NULL) { + mutex_exit(&dev_lck); + return (ENXIO); + } + + sdp->sd_opened = 1; + sdp->sd_seq = nsmb_minor; + sdp->smb_cred = cr; + sdp->sd_flags |= NSMBFL_OPEN; + sdp->zoneid = crgetzoneid(cr); + mutex_exit(&dev_lck); + + *dev = makedevice(nsmb_major, nsmb_minor); + + return (0); +} + +/*ARGSUSED*/ +static int +nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr) +{ + struct smb_vc *vcp; + struct smb_share *ssp; + struct smb_cred scred; + minor_t inst = getminor(dev); + smb_dev_t *sdp; + + mutex_enter(&dev_lck); + /* + * 1. Check the validity of the minor number. + * 2. Release any shares/vc associated with the connection. + * 3. Can close the minor number. + * 4. Deallocate any resources allocated in open() call. + */ + smb_credinit(&scred, curproc, cr); + + sdp = ddi_get_soft_state(statep, inst); + + /* + * time to call ddi_get_soft_state() + */ + ssp = sdp->sd_share; + if (ssp != NULL) + smb_share_rele(ssp); + vcp = sdp->sd_vc; + if (vcp != NULL) { + /* + * If this dev minor was doing session setup + * and failed to authenticate (or whatever) + * then we need to "kill" the VC here so any + * other threads waiting for the VC setup to + * finish will drop their references. + */ + if (sdp->sd_flags & NSMBFL_NEWVC) + smb_vc_kill(vcp); + smb_vc_rele(vcp); + } + smb_credrele(&scred); + + /* + * Free the instance + */ + ddi_soft_state_free(statep, inst); + mutex_exit(&dev_lck); + return (0); +} + +int +smb_dev2share(int fd, struct smb_share **sspp) +{ + register vnode_t *vp; + smb_dev_t *sdp; + struct smb_share *ssp; + dev_t dev; + file_t *fp; + + if ((fp = getf(fd)) == NULL) + return (set_errno(EBADF)); + vp = fp->f_vnode; + dev = vp->v_rdev; + if (dev == NULL) { + releasef(fd); + return (EBADF); + } + sdp = ddi_get_soft_state(statep, getminor(dev)); + if (sdp == NULL) { + releasef(fd); + return (DDI_FAILURE); + } + ssp = sdp->sd_share; + if (ssp == NULL) { + releasef(fd); + return (ENOTCONN); + } + /* + * The share is already locked and referenced by the TCON ioctl + * We NULL to hand off share to caller (mount) + * This allows further ioctls against connection, for instance + * another tree connect and mount, in the automounter case + * + * We're effectively giving our reference to the mount. + * + * XXX: I'm not sure I like this. I'd rather see the ioctl + * caller do something explicit to give up this reference, + * (i.e. SMBIOC_TDIS above) and increment the hold here. + */ + sdp->sd_share = NULL; + releasef(fd); + *sspp = ssp; + return (0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,1372 @@ +/* + * Copyright (c) 2000-2001 Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_iod.c,v 1.32 2005/02/12 00:17:09 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef DEBUG +/* See sys/queue.h */ +#define QUEUEDEBUG 1 +#endif + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/atomic.h> +#include <sys/proc.h> +#include <sys/thread.h> +#include <sys/kmem.h> +#include <sys/unistd.h> +#include <sys/mount.h> +#include <sys/vnode.h> +#include <sys/types.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/stream.h> +#include <sys/strsun.h> +#include <sys/time.h> +#include <sys/class.h> +#include <sys/disp.h> +#include <sys/cmn_err.h> +#include <sys/zone.h> +#include <sys/sdt.h> + +#ifdef APPLE +#include <sys/smb_apple.h> +#else +#include <netsmb/smb_osdep.h> +#endif + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_rq.h> +#include <netsmb/smb_subr.h> +#include <netsmb/smb_tran.h> +#include <netsmb/smb_trantcp.h> + +#ifdef NEED_SMBFS_CALLBACKS +/* + * This is set/cleared when smbfs loads/unloads + * No locks should be necessary, because smbfs + * can't unload until all the mounts are gone. + */ +static smb_fscb_t *fscb; +int +smb_fscb_set(smb_fscb_t *cb) +{ + fscb = cb; + return (0); +} +#endif /* NEED_SMBFS_CALLBACKS */ + +static void smb_iod_sendall(struct smb_vc *); +static void smb_iod_recvall(struct smb_vc *); +static void smb_iod_main(struct smb_vc *); + + +#define SMBIOD_SLEEP_TIMO 2 +#define SMBIOD_PING_TIMO 60 /* seconds */ + +/* + * After this many seconds we want an unresponded-to request to trigger + * some sort of UE (dialogue). If the connection hasn't responded at all + * in this many seconds then the dialogue is of the "connection isn't + * responding would you like to force unmount" variety. If the connection + * has been responding (to other requests that is) then we need a dialogue + * of the "operation is still pending do you want to cancel it" variety. + * At present this latter dialogue does not exist so we have no UE and + * just keep waiting for the slow operation. + */ +#define SMBUETIMEOUT 8 /* seconds */ + + +/* Lock Held version of the next function. */ +static inline void +smb_iod_rqprocessed_LH( + struct smb_rq *rqp, + int error, + int flags) +{ + rqp->sr_flags |= flags; + rqp->sr_lerror = error; + rqp->sr_rpgen++; + rqp->sr_state = SMBRQ_NOTIFIED; + cv_broadcast(&rqp->sr_cond); +} + +static void +smb_iod_rqprocessed( + struct smb_rq *rqp, + int error, + int flags) +{ + + SMBRQ_LOCK(rqp); + smb_iod_rqprocessed_LH(rqp, error, flags); + SMBRQ_UNLOCK(rqp); +} + +static void +smb_iod_invrq(struct smb_vc *vcp) +{ + struct smb_rq *rqp; + + /* + * Invalidate all outstanding requests for this connection + */ + rw_enter(&vcp->iod_rqlock, RW_READER); + TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) { + smb_iod_rqprocessed(rqp, ENOTCONN, SMBR_RESTART); + } + rw_exit(&vcp->iod_rqlock); +} + +#ifdef SMBTP_UPCALL +static void +smb_iod_sockwakeup(struct smb_vc *vcp) +{ + /* note: called from socket upcall... */ +} +#endif + +/* + * Called after we fail to send or recv. + * Called with no locks held. + */ +static void +smb_iod_dead(struct smb_vc *vcp) +{ + + SMB_VC_LOCK(vcp); + vcp->vc_state = SMBIOD_ST_DEAD; + cv_broadcast(&vcp->vc_statechg); + +#ifdef NEED_SMBFS_CALLBACKS + if (fscb != NULL) { + struct smb_connobj *co; + /* + * Walk the share list, notify... + * Was: smbfs_dead(...share->ss_mount); + * XXX: Ok to hold vc_lock here? + * XXX: More to do here? + */ + SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) { + /* smbfs_dead() */ + fscb->fscb_dead(CPTOSS(co)); + } + } +#endif /* NEED_SMBFS_CALLBACKS */ + + SMB_VC_UNLOCK(vcp); + + smb_iod_invrq(vcp); +} + +int +smb_iod_connect(struct smb_vc *vcp) +{ + struct proc *p = curproc; + int error; + + if (vcp->vc_state != SMBIOD_ST_RECONNECT) + return (EINVAL); + + if (vcp->vc_laddr) { + error = SMB_TRAN_BIND(vcp, vcp->vc_laddr, p); + if (error) + goto errout; + } + +#ifdef SMBTP_SELECTID + SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, vcp); +#endif +#ifdef SMBTP_UPCALL + SMB_TRAN_SETPARAM(vcp, SMBTP_UPCALL, (void *)smb_iod_sockwakeup); +#endif + + error = SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, p); + if (error) { + SMBIODEBUG("connection to %s error %d\n", + vcp->vc_srvname, error); + goto errout; + } + + /* Success! */ + return (0); + +errout: + + return (error); +} + +/* + * Called by smb_vc_rele, smb_vc_kill + * Make the connection go away, and + * the IOD (reader) thread too! + */ +int +smb_iod_disconnect(struct smb_vc *vcp) +{ + + /* + * Let's be safe here and avoid doing any + * call across the network while trying to + * shut things down. If we just disconnect, + * the server will take care of the logoff. + */ +#if 0 + if (vcp->vc_state == SMBIOD_ST_VCACTIVE) { + smb_smb_ssnclose(vcp, &vcp->vc_scred); + vcp->vc_state = SMBIOD_ST_TRANACTIVE; + } + vcp->vc_smbuid = SMB_UID_UNKNOWN; +#endif + + /* + * Used to call smb_iod_closetran here, + * which did both disconnect and close. + * We now do the close in smb_vc_free, + * so we always have a valid vc_tdata. + * Now just send the disconnect here. + * Extra disconnect calls are ignored. + */ + SMB_TRAN_DISCONNECT(vcp, curproc); + + /* + * If we have an IOD, let it handle the + * state change when it receives the ACK + * from the disconnect we just sent. + * Otherwise set the state here, i.e. + * after failing session setup. + */ + SMB_VC_LOCK(vcp); + if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { + vcp->vc_state = SMBIOD_ST_DEAD; + cv_broadcast(&vcp->vc_statechg); + } + SMB_VC_UNLOCK(vcp); + + return (0); +} + +/* + * Send one request. + * + * Called by _addrq (for internal requests) + * and by _sendall (via _addrq, _waitrq) + */ +static int +smb_iod_sendrq(struct smb_rq *rqp) +{ + struct proc *p = curproc; + struct smb_vc *vcp = rqp->sr_vc; + struct smb_share *ssp = rqp->sr_share; + mblk_t *m; + int error; + + ASSERT(vcp); + ASSERT(SEMA_HELD(&vcp->vc_sendlock)); + ASSERT(RW_READ_HELD(&vcp->iod_rqlock)); + + /* + * Note: requests with sr_flags & SMBR_INTERNAL + * need to pass here with these states: + * SMBIOD_ST_TRANACTIVE: smb_negotiate + * SMBIOD_ST_NEGOACTIVE: smb_ssnsetup + */ + SMBIODEBUG("vc_state = %d\n", vcp->vc_state); + switch (vcp->vc_state) { + case SMBIOD_ST_NOTCONN: + smb_iod_rqprocessed(rqp, ENOTCONN, 0); + return (0); + case SMBIOD_ST_DEAD: + /* This is what keeps the iod itself from sending more */ + smb_iod_rqprocessed(rqp, ENOTCONN, 0); + return (0); + case SMBIOD_ST_RECONNECT: + return (0); + default: + break; + } + + if (rqp->sr_sendcnt == 0) { + + *rqp->sr_rquid = htoles(vcp->vc_smbuid); + + /* + * XXX: Odd place for all this... + * Would expect these values in vc_smbuid + * and/or the request before we get here. + * I think most of this mess is due to having + * the initial UID set to SMB_UID_UKNOWN when + * it should have been initialized to zero! + * REVIST this later. XXX -gwr + * + * This is checking for the case where + * "vc_smbuid" was set to 0 in "smb_smb_ssnsetup()"; + * that happens for requests that occur + * after that's done but before we get back the final + * session setup reply, where the latter is what + * gives us the UID. (There can be an arbitrary # of + * session setup packet exchanges to complete + * "extended security" authentication.) + * + * However, if the server gave us a UID of 0 in a + * Session Setup andX reply, and we then do a + * Tree Connect andX and get back a TID, we should + * use that TID, not 0, in subsequent references to + * that tree (e.g., in NetShareEnum RAP requests). + * + * So, for now, we forcibly zero out the TID only if we're + * doing extended security, as that's the only time + * that "vc_smbuid" should be explicitly zeroed. + * + * note we must and do use SMB_TID_UNKNOWN for SMB_COM_ECHO + */ + if (!vcp->vc_smbuid && + (vcp->vc_hflags2 & SMB_FLAGS2_EXT_SEC)) + *rqp->sr_rqtid = htoles(0); + else + *rqp->sr_rqtid = + htoles(ssp ? ssp->ss_tid : SMB_TID_UNKNOWN); + mb_fixhdr(&rqp->sr_rq); + } + if (rqp->sr_sendcnt++ >= 60/SMBSBTIMO) { /* one minute */ + smb_iod_rqprocessed(rqp, rqp->sr_lerror, SMBR_RESTART); + /* + * If all attempts to send a request failed, then + * something is seriously hosed. + */ + return (ENOTCONN); + } + + /* + * Replaced m_copym() with Solaris copymsg() which does the same + * work when we want to do a M_COPYALL. + * m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, 0); + */ + m = copymsg(rqp->sr_rq.mb_top); + +#ifdef DTRACE_PROBE + DTRACE_PROBE2(smb_iod_sendrq, + (smb_rq_t *), rqp, (mblk_t *), m); +#else + SMBIODEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0); +#endif + m_dumpm(m); + + error = rqp->sr_lerror = m ? SMB_TRAN_SEND(vcp, m, p) : ENOBUFS; + m = 0; /* consumed by SEND */ + if (error == 0) { + SMBRQ_LOCK(rqp); + rqp->sr_flags |= SMBR_SENT; + rqp->sr_state = SMBRQ_SENT; + if (rqp->sr_flags & SMBR_SENDWAIT) + cv_broadcast(&rqp->sr_cond); + SMBRQ_UNLOCK(rqp); + return (0); + } + /* + * Check for fatal errors + */ + if (SMB_TRAN_FATAL(vcp, error)) { + /* + * No further attempts should be made + */ + SMBSDEBUG("TRAN_SEND returned fatal error %d\n", error); + return (ENOTCONN); + } + if (error) + SMBSDEBUG("TRAN_SEND returned non-fatal error %d\n", error); + +#ifdef APPLE + /* If proc waiting on rqp was signaled... */ + if (smb_rq_intr(rqp)) + smb_iod_rqprocessed(rqp, EINTR, 0); +#endif + + return (0); +} + +static int +smb_iod_recv1(struct smb_vc *vcp, mblk_t **mpp) +{ + struct proc *p = curproc; + mblk_t *m; + uchar_t *hp; + int error; + +top: + m = NULL; + error = SMB_TRAN_RECV(vcp, &m, p); + if (error == EAGAIN) + goto top; + if (error) + return (error); + ASSERT(m); + + m = m_pullup(m, SMB_HDRLEN); + if (m == NULL) { + return (ENOSR); + } + + /* + * Check the SMB header + */ + hp = mtod(m, uchar_t *); + if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) { + m_freem(m); + return (EPROTO); + } + + *mpp = m; + return (0); +} + +/* + * Process incoming packets + * + * This is the "reader" loop, run by the IOD thread + * while in state SMBIOD_ST_VCACTIVE. The loop now + * simply blocks in the socket recv until either a + * message arrives, or a disconnect. + */ +static void +smb_iod_recvall(struct smb_vc *vcp) +{ + struct smb_rq *rqp; + mblk_t *m; + uchar_t *hp; + ushort_t mid; + int error; + int etime_count = 0; /* for "server not responding", etc. */ + + for (;;) { + + if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { + SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state); + error = EIO; + break; + } + + if (vcp->iod_flags & SMBIOD_SHUTDOWN) { + SMBIODEBUG("SHUTDOWN set\n"); + error = EIO; + break; + } + + m = NULL; + error = smb_iod_recv1(vcp, &m); + + if ((error == ETIME) && vcp->iod_rqwaiting) { + /* + * Nothing received for 15 seconds, + * and we have requests waiting. + */ + etime_count++; + + /* + * Once, at 15 sec. notify callbacks + * and print the warning message. + */ + if (etime_count == 1) { + smb_iod_notify_down(vcp); + zprintf(vcp->vc_zoneid, + "SMB server %s not responding\n", + vcp->vc_srvname); + } + + /* + * At 30 sec. try sending an echo, and then + * once a minute thereafter. It's tricky to + * do a send from the IOD thread because + * we don't want to block here. + * + * Using tmo=SMBNOREPLYWAIT in the request + * so smb_rq_reply will skip smb_iod_waitrq. + * The smb_smb_echo call uses SMBR_INTERNAL + * to avoid calling smb_iod_sendall(). + */ + if ((etime_count & 3) == 2) { + smb_smb_echo(vcp, &vcp->vc_scred, + SMBNOREPLYWAIT); + } + + continue; + } /* ETIME && iod_rqwaiting */ + + if (error == ETIME) { + /* + * If the IOD thread holds the last reference + * to this VC, disconnect, release, terminate. + * Usually can avoid the lock/unlock here. + * Note, in-line: _vc_kill ... _vc_gone + */ + if (vcp->vc_co.co_usecount > 1) + continue; + SMB_VC_LOCK(vcp); + if (vcp->vc_co.co_usecount == 1 && + (vcp->vc_flags & SMBV_GONE) == 0) { + vcp->vc_flags |= SMBV_GONE; + SMB_VC_UNLOCK(vcp); + smb_iod_disconnect(vcp); + continue; /* wait for ACK */ + } + SMB_VC_UNLOCK(vcp); + continue; + } /* error == ETIME */ + + if (error) { + /* + * It's dangerous to continue here. + * (possible infinite loop!) + */ + break; + } + + /* + * Received something. Yea! + */ + if (etime_count) { + etime_count = 0; + + zprintf(vcp->vc_zoneid, "SMB server %s OK\n", + vcp->vc_srvname); + + smb_iod_notify_up(vcp); + } + + /* + * Have an SMB packet. The SMB header was + * checked in smb_iod_recv1(). + * Find the request... + */ + hp = mtod(m, uchar_t *); + /*LINTED*/ + mid = SMB_HDRMID(hp); + SMBIODEBUG("mid %04x\n", (uint_t)mid); + + rw_enter(&vcp->iod_rqlock, RW_READER); + TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) { + + if (rqp->sr_mid != mid) + continue; + + DTRACE_PROBE2(smb_iod_recvrq, + (smb_rq_t *), rqp, (mblk_t *), m); + m_dumpm(m); + + SMBRQ_LOCK(rqp); + if (rqp->sr_rp.md_top == NULL) { + md_initm(&rqp->sr_rp, m); + } else { + if (rqp->sr_flags & SMBR_MULTIPACKET) { + md_append_record(&rqp->sr_rp, m); + } else { + SMBRQ_UNLOCK(rqp); + SMBSDEBUG("duplicate response %d " + "(ignored)\n", mid); + break; + } + } + smb_iod_rqprocessed_LH(rqp, 0, 0); + SMBRQ_UNLOCK(rqp); + break; + } + + if (rqp == NULL) { + int cmd = SMB_HDRCMD(hp); + + if (cmd != SMB_COM_ECHO) + SMBSDEBUG("drop resp: mid %d, cmd %d\n", + (uint_t)mid, cmd); +/* smb_printrqlist(vcp); */ + m_freem(m); + } + rw_exit(&vcp->iod_rqlock); + + } +#ifdef APPLE + /* + * check for interrupts + * On Solaris, handle in smb_iod_waitrq + */ + rw_enter(&vcp->iod_rqlock, RW_READER); + TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) { + if (smb_sigintr(rqp->sr_cred->scr_vfsctx)) + smb_iod_rqprocessed(rqp, EINTR, 0); + } + rw_exit(&vcp->iod_rqlock); +#endif +} + +/* + * Looks like we don't need these callbacks, + * but keep the code for now (for Apple). + */ +/*ARGSUSED*/ +void +smb_iod_notify_down(struct smb_vc *vcp) +{ +#ifdef NEED_SMBFS_CALLBACKS + struct smb_connobj *co; + + if (fscb == NULL) + return; + + /* + * Walk the share list, notify... + * Was: smbfs_down(...share->ss_mount); + * XXX: Ok to hold vc_lock here? + */ + SMB_VC_LOCK(vcp); + SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) { + /* smbfs_down() */ + fscb->fscb_down(CPTOSS(co)); + } + SMB_VC_UNLOCK(vcp); +#endif /* NEED_SMBFS_CALLBACKS */ +} + +/*ARGSUSED*/ +void +smb_iod_notify_up(struct smb_vc *vcp) +{ +#ifdef NEED_SMBFS_CALLBACKS + struct smb_connobj *co; + + if (fscb == NULL) + return; + + /* + * Walk the share list, notify... + * Was: smbfs_up(...share->ss_mount); + * XXX: Ok to hold vc_lock here? + */ + SMB_VC_LOCK(vcp); + SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) { + /* smbfs_up() */ + fscb->fscb_up(CPTOSS(co)); + } + SMB_VC_UNLOCK(vcp); +#endif /* NEED_SMBFS_CALLBACKS */ +} + +/* + * The IOD thread is now just a "reader", + * so no more smb_iod_request(). Yea! + */ + +/* + * Place request in the queue, and send it now if possible. + * Called with no locks held. + */ +int +smb_iod_addrq(struct smb_rq *rqp) +{ + struct smb_vc *vcp = rqp->sr_vc; + int error, save_newrq; + + SMBIODEBUG("entry, mid=%d\n", rqp->sr_mid); + + ASSERT(rqp->sr_cred); + + /* This helps a little with debugging. */ + rqp->sr_owner = curthread; + + if (rqp->sr_flags & SMBR_INTERNAL) { + /* + * This is some kind of internal request, + * i.e. negotiate, session setup, echo... + * Allow vc_state < SMBIOD_ST_VCACTIVE, and + * always send directly from this thread. + * May be called by the IOD thread (echo). + * Note lock order: iod_rqlist, vc_sendlock + */ + rw_enter(&vcp->iod_rqlock, RW_WRITER); + TAILQ_INSERT_HEAD(&vcp->iod_rqlist, rqp, sr_link); + rw_downgrade(&vcp->iod_rqlock); + + /* + * Note: iod_sendrq expects vc_sendlock, + * so take that here, but carefully: + * Never block the IOD thread here. + */ + if (curthread == vcp->iod_thr) { + if (sema_tryp(&vcp->vc_sendlock) == 0) { + SMBIODEBUG("sendlock busy\n"); + error = EAGAIN; + } else { + /* Have vc_sendlock */ + error = smb_iod_sendrq(rqp); + sema_v(&vcp->vc_sendlock); + } + } else { + sema_p(&vcp->vc_sendlock); + error = smb_iod_sendrq(rqp); + sema_v(&vcp->vc_sendlock); + } + + rw_exit(&vcp->iod_rqlock); + if (error) + smb_iod_removerq(rqp); + + return (error); + } + + /* + * Normal request from the driver or smbfs. + * State should be correct after the check in + * smb_rq_enqueue(), but we dropped locks... + */ + if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { + SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state); + return (ENOTCONN); + } + + rw_enter(&vcp->iod_rqlock, RW_WRITER); + + TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link); + + /* iod_rqlock/WRITER protects iod_newrq */ + save_newrq = vcp->iod_newrq; + vcp->iod_newrq++; + + rw_exit(&vcp->iod_rqlock); + + /* + * Now send any requests that need to be sent, + * including the one we just put on the list. + * Only the thread that found iod_newrq==0 + * needs to run the send loop. + */ + if (save_newrq == 0) + smb_iod_sendall(vcp); + + return (0); +} + +/* + * Mark an SMBR_MULTIPACKET request as + * needing another send. Similar to the + * "normal" part of smb_iod_addrq. + */ +int +smb_iod_multirq(struct smb_rq *rqp) +{ + struct smb_vc *vcp = rqp->sr_vc; + int save_newrq; + + ASSERT(rqp->sr_flags & SMBR_MULTIPACKET); + + if (rqp->sr_flags & SMBR_INTERNAL) + return (EINVAL); + + if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { + SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state); + return (ENOTCONN); + } + + rw_enter(&vcp->iod_rqlock, RW_WRITER); + + /* Already on iod_rqlist, just reset state. */ + rqp->sr_state = SMBRQ_NOTSENT; + + /* iod_rqlock/WRITER protects iod_newrq */ + save_newrq = vcp->iod_newrq; + vcp->iod_newrq++; + + rw_exit(&vcp->iod_rqlock); + + /* + * Now send any requests that need to be sent, + * including the one we just marked NOTSENT. + * Only the thread that found iod_newrq==0 + * needs to run the send loop. + */ + if (save_newrq == 0) + smb_iod_sendall(vcp); + + return (0); +} + + +int +smb_iod_removerq(struct smb_rq *rqp) +{ + struct smb_vc *vcp = rqp->sr_vc; + + SMBIODEBUG("entry, mid=%d\n", rqp->sr_mid); + + rw_enter(&vcp->iod_rqlock, RW_WRITER); +#ifdef QUEUEDEBUG + /* + * Make sure we have not already removed it. + * See sys/queue.h QUEUEDEBUG_TAILQ_POSTREMOVE + * XXX: Don't like the constant 1 here... + */ + ASSERT(rqp->sr_link.tqe_next != (void *)1L); +#endif + TAILQ_REMOVE(&vcp->iod_rqlist, rqp, sr_link); + rw_exit(&vcp->iod_rqlock); + + return (0); +} + + +/* + * Internal version of smb_iod_waitrq. + * + * This is used when there is no reader thread, + * so we have to do the recv here. The request + * must have the SMBR_INTERNAL flag set. + */ +static int +smb_iod_waitrq_internal(struct smb_rq *rqp) +{ + struct smb_vc *vcp = rqp->sr_vc; + mblk_t *m; + uchar_t *hp; + int error; + uint16_t mid; + uint8_t cmd; + + /* Make sure it's an internal request. */ + if ((rqp->sr_flags & SMBR_INTERNAL) == 0) { + SMBIODEBUG("not internal\n"); + return (EINVAL); + } + + /* Only simple requests allowed. */ + if (rqp->sr_flags & SMBR_MULTIPACKET) { + SMBIODEBUG("multipacket\n"); + return (EINVAL); + } + + /* Should not already have a response. */ + if (rqp->sr_rp.md_top) { + DEBUG_ENTER("smb_iod_waitrq again?\n"); + return (0); + } + + /* + * The message recv loop. Terminates when we + * receive the message we're looking for. + * Drop others, with complaints. + * Scaled-down version of smb_iod_recvall + */ + for (;;) { + m = NULL; + error = smb_iod_recv1(vcp, &m); + if (error) { + /* + * It's dangerous to continue here. + * (possible infinite loop!) + */ +#if 0 + if (SMB_TRAN_FATAL(vcp, error)) { + return (error); + } + continue; +#endif + return (error); + } + + hp = mtod(m, uchar_t *); + cmd = SMB_HDRCMD(hp); + /*LINTED*/ + mid = SMB_HDRMID(hp); + + SMBIODEBUG("cmd 0x%02x mid %04x\n", + (uint_t)cmd, (uint_t)mid); + m_dumpm(m); + + /* + * Normally, the MID will match. + * For internal requests, also + * match on the cmd to be safe. + */ + if (mid == rqp->sr_mid) + break; + if (cmd == rqp->sr_cmd) { + SMBIODEBUG("cmd match but not mid!\n"); + break; + } + + SMBIODEBUG("drop nomatch\n"); + m_freem(m); + } + + /* + * Have the response we were waiting for. + * Simplified version of the code from + * smb_iod_recvall + */ + SMBRQ_LOCK(rqp); + if (rqp->sr_rp.md_top == NULL) { + md_initm(&rqp->sr_rp, m); + } else { + SMBIODEBUG("drop duplicate\n"); + m_freem(m); + } + SMBRQ_UNLOCK(rqp); + + return (0); +} + + +/* + * Wait for a request to complete. + * + * For internal requests, see smb_iod_waitrq_internal. + * For normal requests, we need to deal with + * ioc_muxcnt dropping below vc_maxmux by + * making arrangements to send more... + */ +int +smb_iod_waitrq(struct smb_rq *rqp) +{ + struct smb_vc *vcp = rqp->sr_vc; + clock_t tr, tmo1, tmo2; + int error, rc; + + SMBIODEBUG("entry, cmd=0x%02x mid=0x%04x\n", + (uint_t)rqp->sr_cmd, (uint_t)rqp->sr_mid); + + if (rqp->sr_flags & SMBR_INTERNAL) { + ASSERT((rqp->sr_flags & SMBR_MULTIPACKET) == 0); + error = smb_iod_waitrq_internal(rqp); + smb_iod_removerq(rqp); + return (error); + } + + /* + * Make sure this is NOT the IOD thread, + * or the wait below will always timeout. + */ + ASSERT(curthread != vcp->iod_thr); + + atomic_inc_uint(&vcp->iod_rqwaiting); + SMBRQ_LOCK(rqp); + + /* + * First, wait for the request to be sent. Normally the send + * has already happened by the time we get here. However, if + * we have more than maxmux entries in the request list, our + * request may not be sent until other requests complete. + * The wait in this case is due to local I/O demands, so + * we don't want the server response timeout to apply. + * + * If a request is allowed to interrupt this wait, then the + * request is cancelled and never sent OTW. Some kinds of + * requests should never be cancelled (i.e. close) and those + * are marked SMBR_NOINTR_SEND so they either go eventually, + * or a connection close will terminate them with ENOTCONN. + */ + while (rqp->sr_state == SMBRQ_NOTSENT) { + rqp->sr_flags |= SMBR_SENDWAIT; + if (rqp->sr_flags & SMBR_NOINTR_SEND) { + cv_wait(&rqp->sr_cond, &rqp->sr_lock); + rc = 1; + } else + rc = cv_wait_sig(&rqp->sr_cond, &rqp->sr_lock); + rqp->sr_flags &= ~SMBR_SENDWAIT; + if (rc == 0) { + SMBIODEBUG("EINTR in sendwait, mid=%u\n", rqp->sr_mid); + error = EINTR; + goto out; + } + } + + /* + * The request has been sent. Now wait for the response, + * with the timeout specified for this request. + * Compute all the deadlines now, so we effectively + * start the timer(s) after the request is sent. + */ + if (smb_timo_notice && (smb_timo_notice < rqp->sr_timo)) + tmo1 = lbolt + SEC_TO_TICK(smb_timo_notice); + else + tmo1 = 0; + tmo2 = lbolt + SEC_TO_TICK(rqp->sr_timo); + + /* + * As above, we don't want to allow interrupt for some + * requests like open, because we could miss a succesful + * response and therefore "leak" a FID. Such requests + * are marked SMBR_NOINTR_RECV to prevent that. + * + * If "slow server" warnings are enabled, wait first + * for the "notice" timeout, and warn if expired. + */ + if (tmo1 && rqp->sr_rpgen == rqp->sr_rplast) { + if (rqp->sr_flags & SMBR_NOINTR_RECV) + tr = cv_timedwait(&rqp->sr_cond, + &rqp->sr_lock, tmo1); + else + tr = cv_timedwait_sig(&rqp->sr_cond, + &rqp->sr_lock, tmo1); + if (tr == 0) { + error = EINTR; + goto out; + } + if (tr < 0) { +#ifdef DTRACE_PROBE + DTRACE_PROBE1(smb_iod_waitrq1, + (smb_rq_t *), rqp); +#endif +#ifdef NOT_YET + /* Want this to go ONLY to the user. */ + uprintf("SMB server %s has not responded" + " to request %d after %d seconds..." + " (still waiting).\n", vcp->vc_srvname, + rqp->sr_mid, smb_timo_notice); +#endif + } + } + + /* + * Keep waiting until tmo2 is expired. + */ + while (rqp->sr_rpgen == rqp->sr_rplast) { + if (rqp->sr_flags & SMBR_NOINTR_RECV) + tr = cv_timedwait(&rqp->sr_cond, + &rqp->sr_lock, tmo2); + else + tr = cv_timedwait_sig(&rqp->sr_cond, + &rqp->sr_lock, tmo2); + if (tr == 0) { + error = EINTR; + goto out; + } + if (tr < 0) { +#ifdef DTRACE_PROBE + DTRACE_PROBE1(smb_iod_waitrq2, + (smb_rq_t *), rqp); +#endif +#ifdef NOT_YET + /* Want this to go ONLY to the user. */ + uprintf("SMB server %s has not responded" + " to request %d after %d seconds..." + " (giving up).\n", vcp->vc_srvname, + rqp->sr_mid, rqp->sr_timo); +#endif + error = ETIME; + goto out; + } + /* got wakeup */ + } + error = rqp->sr_lerror; + rqp->sr_rplast++; + +out: + SMBRQ_UNLOCK(rqp); + atomic_dec_uint(&vcp->iod_rqwaiting); + + /* + * MULTIPACKET request must stay in the list. + * They may need additional responses. + */ + if ((rqp->sr_flags & SMBR_MULTIPACKET) == 0) + smb_iod_removerq(rqp); + + /* + * Some request has been completed. + * If we reached the mux limit, + * re-run the send loop... + */ + if (vcp->iod_muxfull) + smb_iod_sendall(vcp); + + return (error); +} + +/* + * Shutdown all outstanding I/O requests on the specified share with + * ENXIO; used when unmounting a share. (There shouldn't be any for a + * non-forced unmount; if this is a forced unmount, we have to shutdown + * the requests as part of the unmount process.) + */ +void +smb_iod_shutdown_share(struct smb_share *ssp) +{ + struct smb_vc *vcp = SSTOVC(ssp); + struct smb_rq *rqp; + + /* + * Loop through the list of requests and shutdown the ones + * that are for the specified share. + */ + rw_enter(&vcp->iod_rqlock, RW_READER); + TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) { + if (rqp->sr_state != SMBRQ_NOTIFIED && rqp->sr_share == ssp) + smb_iod_rqprocessed(rqp, EIO, 0); + } + rw_exit(&vcp->iod_rqlock); +} + +/* + * Send all requests that need sending. + * Called from _addrq, _multirq, _waitrq + */ +static void +smb_iod_sendall(struct smb_vc *vcp) +{ + struct smb_rq *rqp; + int error, save_newrq, muxcnt; + + /* + * Clear "newrq" to make sure threads adding + * new requests will run this function again. + */ + rw_enter(&vcp->iod_rqlock, RW_WRITER); + save_newrq = vcp->iod_newrq; + vcp->iod_newrq = 0; + + /* + * We only read iod_rqlist, so downgrade rwlock. + * This allows the IOD to handle responses while + * some requesting thread may be blocked in send. + */ + rw_downgrade(&vcp->iod_rqlock); + + /* Expect to find about this many requests. */ + SMBIODEBUG("top, save_newrq=%d\n", save_newrq); + + /* + * Serialize to prevent multiple senders. + * Note lock order: iod_rqlock, vc_sendlock + */ + sema_p(&vcp->vc_sendlock); + + /* + * Walk the list of requests and send when possible. + * We avoid having more than vc_maxmux requests + * outstanding to the server by traversing only + * vc_maxmux entries into this list. Simple! + */ + ASSERT(vcp->vc_maxmux > 0); + error = muxcnt = 0; + TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) { + + if (vcp->vc_state == SMBIOD_ST_DEAD) { + error = ENOTCONN; /* stop everything! */ + break; + } + + if (rqp->sr_state == SMBRQ_NOTSENT) { + error = smb_iod_sendrq(rqp); + if (error) + break; + } + + if (++muxcnt == vcp->vc_maxmux) { + SMBIODEBUG("muxcnt == vc_maxmux\n"); + break; + } + + } + + /* + * If we have vc_maxmux requests outstanding, + * arrange for _waitrq to call _sendall as + * requests are completed. + */ + vcp->iod_muxfull = + (muxcnt < vcp->vc_maxmux) ? 0 : 1; + + sema_v(&vcp->vc_sendlock); + rw_exit(&vcp->iod_rqlock); + + if (error == ENOTCONN) + smb_iod_dead(vcp); + +} + + +/* + * "main" function for smbiod daemon thread + */ +void +smb_iod_main(struct smb_vc *vcp) +{ + kthread_t *thr = curthread; + + SMBIODEBUG("entry\n"); + + SMBIODEBUG("Running, thr=0x%p\n", thr); + + /* + * Prevent race with thread that created us. + * After we get this lock iod_thr is set. + */ + SMB_VC_LOCK(vcp); + ASSERT(thr == vcp->iod_thr); + + /* Redundant with iod_thr, but may help debugging. */ + vcp->iod_flags |= SMBIOD_RUNNING; + SMB_VC_UNLOCK(vcp); + + /* + * OK, this is a new reader thread. + * In case of reconnect, tell any + * old requests they can restart. + */ + smb_iod_invrq(vcp); + + /* + * Run the "reader" loop. + */ + smb_iod_recvall(vcp); + + /* + * The reader loop function returns only when + * there's been a fatal error on the connection. + */ + smb_iod_dead(vcp); + + /* + * The reader thread is going away. Clear iod_thr, + * and wake up anybody waiting for us to quit. + */ + SMB_VC_LOCK(vcp); + vcp->iod_flags &= ~SMBIOD_RUNNING; + vcp->iod_thr = NULL; + cv_broadcast(&vcp->iod_exit); + SMB_VC_UNLOCK(vcp); + + /* + * This hold was taken in smb_iod_create() + * when this thread was created. + */ + smb_vc_rele(vcp); + + SMBIODEBUG("Exiting, p=0x%p\n", curproc); + zthread_exit(); +} + +/* + * Create the reader thread. + * + * This happens when we are just about to + * enter vc_state = SMBIOD_ST_VCACTIVE; + * See smb_sm_ssnsetup() + */ +int +smb_iod_create(struct smb_vc *vcp) +{ + kthread_t *thr = NULL; + int error; + + /* + * Take a hold on the VC for the IOD thread. + * This hold will be released when the IOD + * thread terminates. (or on error below) + */ + smb_vc_hold(vcp); + + SMB_VC_LOCK(vcp); + + if (vcp->iod_thr != NULL) { + SMBIODEBUG("aready have an IOD?"); + error = EIO; + goto out; + } + + /* + * Darwin code used: IOCreateThread(...) + * In Solaris, we use... + */ + thr = zthread_create( + NULL, /* stack */ + 0, /* stack size (default) */ + smb_iod_main, /* entry func... */ + vcp, /* ... and arg */ + 0, /* len (of what?) */ + minclsyspri); /* priority */ + if (thr == NULL) { + SMBERROR("can't start smbiod\n"); + error = ENOMEM; + goto out; + } + + /* Success! */ + error = 0; + vcp->iod_thr = thr; + +out: + SMB_VC_UNLOCK(vcp); + + if (error) + smb_vc_rele(vcp); + + return (error); +} + +/* + * Called from smb_vc_free to do any + * cleanup of our IOD (reader) thread. + */ +int +smb_iod_destroy(struct smb_vc *vcp) +{ + clock_t tmo; + + /* + * Let's try to make sure the IOD thread + * goes away, by waiting for it to exit. + * Normally, it's gone by now. + * + * Only wait for a second, because we're in the + * teardown path and don't want to get stuck here. + * Should not take long, or things are hosed... + */ + SMB_VC_LOCK(vcp); + if (vcp->iod_thr) { + vcp->iod_flags |= SMBIOD_SHUTDOWN; + tmo = lbolt + hz; + tmo = cv_timedwait(&vcp->iod_exit, &vcp->vc_lock, tmo); + if (tmo == -1) { + SMBERROR("IOD thread for %s did not exit?\n", + vcp->vc_srvname); + } + } + if (vcp->iod_thr) { + /* This should not happen. */ + SMBIODEBUG("IOD thread did not exit!\n"); + /* Try harder? */ + tsignal(vcp->iod_thr, SIGKILL); + } + SMB_VC_UNLOCK(vcp); + + return (0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,102 @@ +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Code corresponding to smb_apple.h + * XXX: Could merge this into smb_subr.h + * as long as that doesn't break smbfs + */ + +#ifndef _NETSMB_SMB_OSDEP_H_ +#define _NETSMB_SMB_OSDEP_H_ + +#ifndef PRIVSYM +#define PRIVSYM +#endif + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#define CAST_DOWN(type, addr) (((type)((uintptr_t)(addr)))) +#define USER_ADDR_NULL ((user_addr_t)0) +#define CAST_USER_ADDR_T(a_ptr) ((user_addr_t)(a_ptr)) + +/* + * flags to (BSD) malloc + */ +#define M_WAITOK 0x0000 +#define M_NOWAIT 0x0001 +#define M_ZERO 0x0004 /* bzero the allocation */ + +/* Iconv stuff */ + +/* + * Some UTF Related stuff. Will be deleting this once compiled and using + * ienup's code. + */ +/* + * UTF-8 encode/decode flags + */ +#define UTF_REVERSE_ENDIAN 0x01 /* reverse UCS-2 byte order */ +#define UTF_NO_NULL_TERM 0x02 /* do not add null termination */ +#define UTF_DECOMPOSED 0x04 /* generate fully decomposed UCS-2 */ +#define UTF_PRECOMPOSED 0x08 /* generate precomposed UCS-2 */ + +/* + * These are actually included in sunddi.h. I am getting compilation + * errors right now. Adding the induvidual defines here again from sunddi.h + * Unicode encoding conversion functions and their macros. + */ +#define UCONV_IN_BIG_ENDIAN 0x0001 +#define UCONV_OUT_BIG_ENDIAN 0x0002 +#define UCONV_IN_SYSTEM_ENDIAN 0x0004 +#define UCONV_OUT_SYSTEM_ENDIAN 0x0008 +#define UCONV_IN_LITTLE_ENDIAN 0x0010 +#define UCONV_OUT_LITTLE_ENDIAN 0x0020 +#define UCONV_IGNORE_NULL 0x0040 +#define UCONV_IN_ACCEPT_BOM 0x0080 +#define UCONV_OUT_EMIT_BOM 0x0100 + +extern int uconv_u8tou16(const uchar_t *, size_t *, uint16_t *, size_t *, int); + +/* Legacy type names for Solaris. */ +typedef uint64_t u_int64_t; +typedef uint32_t u_int32_t; +typedef uint16_t u_int16_t; +typedef uint8_t u_int8_t; + +typedef const char * c_caddr_t; +typedef uint64_t user_addr_t; + +/* + * Time related calls. + */ + +/* BEGIN CSTYLED */ +#define timespeccmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec == (uvp)->tv_sec) ? \ + ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \ + ((tvp)->tv_sec cmp (uvp)->tv_sec)) +/* END CSTYLED */ + +#define timespecadd(vvp, uvp) \ + { \ + (vvp)->tv_sec += (uvp)->tv_sec; \ + (vvp)->tv_nsec += (uvp)->tv_nsec; \ + if ((vvp)->tv_nsec >= 1000000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_nsec -= 1000000000; \ + } \ + } + +#define timespecsub(vvp, uvp) \ + { \ + (vvp)->tv_sec -= (uvp)->tv_sec; \ + (vvp)->tv_nsec -= (uvp)->tv_nsec; \ + if ((vvp)->tv_nsec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_nsec += 1000000000; \ + } \ + } + +#endif /* _NETSMB_SMB_OSDEP_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,391 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Password Keychain storage mechanism. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/sysmacros.h> +#include <sys/uio.h> +#include <sys/buf.h> +#include <sys/modctl.h> +#include <sys/open.h> +#include <sys/file.h> +#include <sys/kmem.h> +#include <sys/conf.h> +#include <sys/cmn_err.h> +#include <sys/stat.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/sunldi.h> +#include <sys/policy.h> +#include <sys/zone.h> +#include <sys/pathname.h> +#include <sys/mount.h> +#include <sys/sdt.h> +#include <fs/fs_subr.h> +#include <sys/devops.h> +#include <sys/thread.h> +#include <sys/mkdev.h> +#include <sys/avl.h> +#include <sys/avl_impl.h> + +#include <netsmb/smb_osdep.h> + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> +#include <netsmb/smb_dev.h> +#include <netsmb/smb_pass.h> + +/* + * The smb_ptd is a cache of Uid's, User names, passwords and domain names. + * It will be used for storing the password information for a user and will + * be used to for connections without entering the pasword again if its + * already keyed in by the user. Its a kind of Key-Chain mechanism + * implemented by Apple folks. + */ + +/* + * Information stored in the nodes: + * UID: Uid of the person who initiated the login request. + * ZoneID: ZoneID of the zone from where the login request is initiated. + * Username: Username in the CIFS server. + * Srvdom: Domain name/ Server name of the CIFS server. + * Password: Password of the user. + * For more information, see smb_pass.h and sys/avl.h + */ + +/* + * Information retrieved from the node. + * Node/password information can only be retrived with a call + * to smb_pkey_getpw(). Password never gets copied to the userspace. + * It will be copied to the Kernel data structure smbioc_ossn->ioc_password + * when needed for doing the "Session Setup". All other calls will return + * either a success or a failure. + */ + +avl_tree_t smb_ptd; /* AVL password tree descriptor */ +unsigned int smb_list_len = 0; /* No. of elements in the tree. */ +kmutex_t smb_ptd_lock; /* Mutex lock for controlled access */ + +/* + * This routine is called by AVL tree calls when they want to find a + * node, find the next position in the tree to add or for deletion. + * Compare nodes from the tree to find the actual node based on + * uid/zoneid/username/domainname. + */ +int +smb_pkey_cmp(const void *a, const void *b) +{ + const smb_passid_t *pa = (smb_passid_t *)a; + const smb_passid_t *pb = (smb_passid_t *)b; + int duser, dsrv; + + ASSERT(MUTEX_HELD(&smb_ptd_lock)); + + /* + * The nodes are added sorted on the uid/zoneid/domainname/username + * We will do this: + * Compare uid's. The owner who stored the node gets access. + * Then zoneid to check if the access is from the same zone. + * Compare usernames. + * If the above are same, then compare domain/server names. + */ + if (pa->uid < pb->uid) + return (-1); + if (pa->uid > pb->uid) + return (+1); + if (pa->zoneid < pb->zoneid) + return (-1); + if (pa->zoneid > pb->zoneid) + return (+1); + dsrv = strcasecmp(pa->srvdom, pb->srvdom); + if (dsrv < 0) + return (-1); + if (dsrv > 0) + return (+1); + duser = strcasecmp(pa->username, pb->username); + if (duser < 0) + return (-1); + if (duser > 0) + return (+1); + return (0); +} + +/* + * Initialization of the code that deals with uid and passwords. + */ +void +smb_pkey_init() +{ + avl_create(&smb_ptd, + smb_pkey_cmp, + sizeof (smb_passid_t), + offsetof(smb_passid_t, + cpnode)); + mutex_init(&smb_ptd_lock, NULL, MUTEX_DEFAULT, NULL); +} + +/* + * Destroy the full AVL tree. + */ +void +smb_pkey_fini() +{ + smb_pkey_deluid((uid_t)-1, CRED()); + avl_destroy(&smb_ptd); + mutex_destroy(&smb_ptd_lock); +} + +/* + * Driver unload calls this to ask if we + * have any stored passwords + */ +int +smb_pkey_idle() +{ + int n; + + mutex_enter(&smb_ptd_lock); + n = avl_numnodes(&smb_ptd); + mutex_exit(&smb_ptd_lock); + + return ((n) ? EBUSY : 0); +} + +int +smb_node_delete(smb_passid_t *tmp) +{ + ASSERT(MUTEX_HELD(&smb_ptd_lock)); + avl_remove(&smb_ptd, tmp); + smb_strfree(tmp->srvdom); + smb_strfree(tmp->username); + kmem_free(tmp, sizeof (*tmp)); + return (0); +} + + +/* + * Remove a node from the AVL tree identified by cpid. + */ +int +smb_pkey_del(smbioc_pk_t *pk, cred_t *cr) +{ + avl_index_t where; + smb_passid_t buf, *cpid, *tmp; + uid_t uid; + + tmp = &buf; + uid = pk->pk_uid; + if (uid == (uid_t)-1) + uid = crgetruid(cr); + else { + if (secpolicy_smbfs_login(cr, uid)) + return (EPERM); + } + tmp->uid = uid; + tmp->zoneid = getzoneid(); + tmp->srvdom = pk->pk_dom; + tmp->username = pk->pk_usr; + + mutex_enter(&smb_ptd_lock); + if ((cpid = (smb_passid_t *)avl_find(&smb_ptd, + tmp, &where)) != NULL) { + smb_node_delete(cpid); + } + mutex_exit(&smb_ptd_lock); + + return (0); +} + +/* + * Delete the entries owned by a particular user + * based on uid. We go through all the nodes and + * delete the nodes whereever the uid matches. + * + * Also implements "delete all" when uid == -1. + * + * You must have privilege to use any uid other + * than your real uid. + */ +int +smb_pkey_deluid(uid_t ioc_uid, cred_t *cr) +{ + smb_passid_t *cpid, *tmp; + + if (secpolicy_smbfs_login(cr, ioc_uid)) + return (EPERM); + + mutex_enter(&smb_ptd_lock); + for (tmp = avl_first(&smb_ptd); tmp != NULL; + tmp = cpid) { + cpid = AVL_NEXT(&smb_ptd, tmp); + if (ioc_uid == (uid_t)-1 || + ioc_uid == tmp->uid) { + /* + * Delete the node. + */ + smb_node_delete(tmp); + } + } + mutex_exit(&smb_ptd_lock); + + return (0); +} + +/* + * Add entry or modify existing. + * Check for existing entry.. + * If present, delete. + * Now, add the new entry. + */ +int +smb_pkey_add(smbioc_pk_t *pk, cred_t *cr) +{ + avl_tree_t *t = &smb_ptd; + avl_index_t where; + smb_passid_t *tmp, *cpid; + int ret; + uid_t uid; + + uid = pk->pk_uid; + if (uid == (uid_t)-1) + uid = crgetruid(cr); + else { + if (secpolicy_smbfs_login(cr, uid)) + return (EPERM); + } + cpid = kmem_zalloc(sizeof (smb_passid_t), KM_SLEEP); + cpid->uid = uid; + cpid->zoneid = getzoneid(); + cpid->srvdom = smb_strdup(pk->pk_dom); + cpid->username = smb_strdup(pk->pk_usr); + smb_oldlm_hash(pk->pk_pass, cpid->lmhash); + smb_ntlmv1hash(pk->pk_pass, cpid->nthash); + + /* + * XXX: Instead of calling smb_pkey_check here, + * should call avl_find directly, and hold the + * lock across: avl_find, avl_remove, avl_insert. + */ + + /* If it already exists, delete it. */ + ret = smb_pkey_check(pk, cr); + if (ret == 0) { + smb_pkey_del(pk, cr); + } + + mutex_enter(&smb_ptd_lock); + tmp = (smb_passid_t *)avl_find(t, cpid, &where); + if (tmp == NULL) { + avl_insert(t, cpid, where); + } else { + smb_strfree(cpid->srvdom); + smb_strfree(cpid->username); + kmem_free(cpid, sizeof (smb_passid_t)); + } + mutex_exit(&smb_ptd_lock); + + return (0); +} + +/* + * Determine if a node with uid,zoneid, uname & dname exists in the tree + * given the information. Does NOT return the stored password. + */ +int +smb_pkey_check(smbioc_pk_t *pk, cred_t *cr) +{ + avl_tree_t *t = &smb_ptd; + avl_index_t where; + smb_passid_t *tmp, *cpid; + int error = ENOENT; + uid_t uid; + + uid = pk->pk_uid; + if (uid == (uid_t)-1) + uid = crgetruid(cr); + else { + if (secpolicy_smbfs_login(cr, uid)) + return (EPERM); + } + cpid = kmem_alloc(sizeof (smb_passid_t), KM_SLEEP); + cpid->uid = uid; + cpid->zoneid = getzoneid(); + cpid->srvdom = pk->pk_dom; + cpid->username = pk->pk_usr; + + mutex_enter(&smb_ptd_lock); + tmp = (smb_passid_t *)avl_find(t, cpid, &where); + if (tmp != NULL) + error = 0; + mutex_exit(&smb_ptd_lock); + + kmem_free(cpid, sizeof (smb_passid_t)); + return (error); +} + +/* + * Interface function between the keychain mechanism and SMB password + * handling during Session Setup. Internal form of smb_pkey_check(). + * Copies the password hashes into the VC. + */ +int +smb_pkey_getpwh(struct smb_vc *vcp, cred_t *cr) +{ + avl_tree_t *t = &smb_ptd; + avl_index_t where; + smb_passid_t *tmp, *cpid; + int error = ENOENT; + + cpid = kmem_alloc(sizeof (smb_passid_t), KM_SLEEP); + cpid->uid = crgetruid(cr); + cpid->zoneid = getzoneid(); + cpid->username = vcp->vc_username; + + if (vcp->vc_vopt & SMBVOPT_KC_DOMAIN) + cpid->srvdom = vcp->vc_domain; + else + cpid->srvdom = vcp->vc_srvname; + + mutex_enter(&smb_ptd_lock); + tmp = (smb_passid_t *)avl_find(t, cpid, &where); + if (tmp != NULL) { + bcopy(tmp->lmhash, vcp->vc_lmhash, SMB_PWH_MAX); + bcopy(tmp->nthash, vcp->vc_nthash, SMB_PWH_MAX); + error = 0; + } + mutex_exit(&smb_ptd_lock); + + kmem_free(cpid, sizeof (smb_passid_t)); + return (error); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,66 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SMB_PASS_H +#define _SMB_PASS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Password keychains interface + */ + +#include <sys/avl.h> +#include <netsmb/smb_dev.h> + +/* + * Here just so our mdb module can use it. + * Otherwise could be private to smb_pass.c + */ +typedef struct smb_passid { + avl_node_t cpnode; /* Next Node information */ + uid_t uid; /* User id */ + zoneid_t zoneid; /* Future Use */ + char *srvdom; /* Windows Domain (or server) */ + char *username; /* Windows User name */ + uchar_t lmhash[SMB_PWH_MAX]; + uchar_t nthash[SMB_PWH_MAX]; +} smb_passid_t; + +/* Called from smb_dev.c */ +void smb_pkey_init(void); +void smb_pkey_fini(void); +int smb_pkey_idle(void); +int smb_pkey_add(smbioc_pk_t *pk, cred_t *cr); +int smb_pkey_del(smbioc_pk_t *pk, cred_t *cr); +int smb_pkey_check(smbioc_pk_t *pk, cred_t *cr); +int smb_pkey_deluid(uid_t uid, cred_t *cr); + +/* Called from smb_usr.c */ +struct smb_vc; +int smb_pkey_getpwh(struct smb_vc *vcp, cred_t *cr); + +#endif /* _SMB_PASS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,1408 @@ +/* + * Copyright (c) 2000-2001, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_rq.c,v 1.29 2005/02/11 01:44:17 lindak Exp $ + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kmem.h> +#include <sys/proc.h> +#include <sys/lock.h> +#include <sys/socket.h> +#include <sys/mount.h> +#include <sys/cmn_err.h> +#include <sys/sdt.h> + +#ifdef APPLE +#include <sys/smb_apple.h> +#else +#include <netsmb/smb_osdep.h> +#endif + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> +#include <netsmb/smb_tran.h> +#include <netsmb/smb_rq.h> + +static int smb_rq_reply(struct smb_rq *rqp); +static int smb_rq_enqueue(struct smb_rq *rqp); +static int smb_rq_getenv(struct smb_connobj *layer, + struct smb_vc **vcpp, struct smb_share **sspp); +static int smb_rq_new(struct smb_rq *rqp, uchar_t cmd); +static int smb_t2_reply(struct smb_t2rq *t2p); +static int smb_nt_reply(struct smb_ntrq *ntp); + + + +int +smb_rq_alloc(struct smb_connobj *layer, uchar_t cmd, struct smb_cred *scred, + struct smb_rq **rqpp) +{ + struct smb_rq *rqp; + int error; + + rqp = (struct smb_rq *)kmem_alloc(sizeof (struct smb_rq), KM_SLEEP); + if (rqp == NULL) + return (ENOMEM); + error = smb_rq_init(rqp, layer, cmd, scred); + if (error) { + smb_rq_done(rqp); + return (error); + } + rqp->sr_flags |= SMBR_ALLOCED; + *rqpp = rqp; + return (0); +} + + +int +smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer, uchar_t cmd, + struct smb_cred *scred) +{ + int error; + + bzero(rqp, sizeof (*rqp)); + mutex_init(&rqp->sr_lock, NULL, MUTEX_DRIVER, NULL); + cv_init(&rqp->sr_cond, NULL, CV_DEFAULT, NULL); + + error = smb_rq_getenv(layer, &rqp->sr_vc, &rqp->sr_share); + if (error) + return (error); + + rqp->sr_rexmit = SMBMAXRESTARTS; + rqp->sr_cred = scred; /* XXX no ref hold */ + rqp->sr_mid = smb_vc_nextmid(rqp->sr_vc); + error = smb_rq_new(rqp, cmd); + if (!error) { + rqp->sr_flags |= SMBR_VCREF; + smb_vc_hold(rqp->sr_vc); + } + return (error); +} + +static int +smb_rq_new(struct smb_rq *rqp, uchar_t cmd) +{ + struct smb_vc *vcp = rqp->sr_vc; + struct mbchain *mbp = &rqp->sr_rq; + int error; + static char tzero[12]; + caddr_t ptr; + pid_t pid; + + ASSERT(rqp != NULL); + ASSERT(rqp->sr_cred != NULL); + pid = rqp->sr_cred->vc_pid; + rqp->sr_sendcnt = 0; + rqp->sr_cmd = cmd; + mb_done(mbp); + md_done(&rqp->sr_rp); + error = mb_init(mbp); + if (error) + return (error); + mb_put_mem(mbp, SMB_SIGNATURE, SMB_SIGLEN, MB_MSYSTEM); + mb_put_uint8(mbp, cmd); + mb_put_uint32le(mbp, 0); + mb_put_uint8(mbp, vcp->vc_hflags); + if (cmd == SMB_COM_TRANSACTION || cmd == SMB_COM_TRANSACTION_SECONDARY) + mb_put_uint16le(mbp, (vcp->vc_hflags2 & ~SMB_FLAGS2_UNICODE)); + else + mb_put_uint16le(mbp, vcp->vc_hflags2); + mb_put_mem(mbp, tzero, 12, MB_MSYSTEM); + ptr = mb_reserve(mbp, sizeof (u_int16_t)); + /*LINTED*/ + ASSERT(ptr == (caddr_t)((u_int16_t *)ptr)); + /*LINTED*/ + rqp->sr_rqtid = (u_int16_t *)ptr; + mb_put_uint16le(mbp, (u_int16_t)(pid)); + ptr = mb_reserve(mbp, sizeof (u_int16_t)); + /*LINTED*/ + ASSERT(ptr == (caddr_t)((u_int16_t *)ptr)); + /*LINTED*/ + rqp->sr_rquid = (u_int16_t *)ptr; + mb_put_uint16le(mbp, rqp->sr_mid); + return (0); +} + +void +smb_rq_done(struct smb_rq *rqp) +{ + /* No locks. Last ref. here. */ + if (rqp->sr_flags & SMBR_VCREF) { + rqp->sr_flags &= ~SMBR_VCREF; + smb_vc_rele(rqp->sr_vc); + } + mb_done(&rqp->sr_rq); + md_done(&rqp->sr_rp); + mutex_destroy(&rqp->sr_lock); + cv_destroy(&rqp->sr_cond); + if (rqp->sr_flags & SMBR_ALLOCED) + kmem_free(rqp, sizeof (*rqp)); +} + +/* + * Simple request-reply exchange + */ +int +smb_rq_simple_timed(struct smb_rq *rqp, int timeout) +{ + int error = EINVAL; + + for (; ; ) { + /* + * Don't send any new requests if force unmount is underway. + * This check was moved into smb_rq_enqueue. + */ + rqp->sr_flags &= ~SMBR_RESTART; + rqp->sr_timo = timeout; /* in seconds */ + rqp->sr_state = SMBRQ_NOTSENT; + error = smb_rq_enqueue(rqp); + if (error) { + break; + } + error = smb_rq_reply(rqp); + if (!error) + break; + if ((rqp->sr_flags & (SMBR_RESTART | SMBR_NORESTART)) != + SMBR_RESTART) + break; + if (rqp->sr_rexmit <= 0) + break; + SMBRQ_LOCK(rqp); + if (rqp->sr_share && rqp->sr_share->ss_mount) { + cv_timedwait(&rqp->sr_cond, &(rqp)->sr_lock, + lbolt + (hz * SMB_RCNDELAY)); + + } else { + delay(lbolt + (hz * SMB_RCNDELAY)); + } + SMBRQ_UNLOCK(rqp); + rqp->sr_rexmit--; +#ifdef XXX + timeout *= 2; +#endif + } + return (error); +} + + +int +smb_rq_simple(struct smb_rq *rqp) +{ + return (smb_rq_simple_timed(rqp, smb_timo_default)); +} + +static int +smb_rq_enqueue(struct smb_rq *rqp) +{ + struct smb_vc *vcp = rqp->sr_vc; + struct smb_share *ssp = rqp->sr_share; + int error = 0; + + /* + * Unfortunate special case needed for + * tree disconnect, which needs sr_share + * but should skip the reconnect check. + */ + if (rqp->sr_cmd == SMB_COM_TREE_DISCONNECT) + ssp = NULL; + + /* + * If this is an "internal" request, bypass any + * wait for connection state changes, etc. + * This request is making those changes. + */ + if (rqp->sr_flags & SMBR_INTERNAL) { + ASSERT(ssp == NULL); + goto just_doit; + } + + /* + * Wait for VC reconnect to finish... + * XXX: Deal with reconnect later. + * Just bail out for now. + * + * MacOS might check vfs_isforce() here. + */ + if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { + SMBSDEBUG("bad vc_state=%d\n", vcp->vc_state); + return (ENOTCONN); + } + + /* + * If this request has a "share" object: + * 1: Deny access if share is _GONE (unmounted) + * 2: Wait for state changes in that object, + * Initiate share (re)connect if needed. + * XXX: Not really doing 2 yet. + */ + if (ssp) { + if (ssp->ss_flags & SMBS_GONE) + return (ENOTCONN); + SMB_SS_LOCK(ssp); + if (!smb_share_valid(ssp)) { + error = smb_share_tcon(ssp); + } + SMB_SS_UNLOCK(ssp); + } + + if (!error) { + just_doit: + error = smb_iod_addrq(rqp); + } + + return (error); +} + +/* + * Mark location of the word count, which is filled in later by + * smb_rw_wend(). Also initialize the counter that it uses + * to figure out what value to fill in. + * + * Note that the word count happens to be 8-bit. + */ +void +smb_rq_wstart(struct smb_rq *rqp) +{ + rqp->sr_wcount = mb_reserve(&rqp->sr_rq, sizeof (uint8_t)); + rqp->sr_rq.mb_count = 0; +} + +void +smb_rq_wend(struct smb_rq *rqp) +{ + uint_t wcnt; + + if (rqp->sr_wcount == NULL) { + SMBSDEBUG("no wcount\n"); + return; + } + wcnt = rqp->sr_rq.mb_count; + if (wcnt > 0x1ff) + SMBSDEBUG("word count too large (%d)\n", wcnt); + if (wcnt & 1) + SMBSDEBUG("odd word count\n"); + /* Fill in the word count (8-bits) */ + *rqp->sr_wcount = (wcnt >> 1); +} + +/* + * Mark location of the byte count, which is filled in later by + * smb_rw_bend(). Also initialize the counter that it uses + * to figure out what value to fill in. + * + * Note that the byte count happens to be 16-bit. + */ +void +smb_rq_bstart(struct smb_rq *rqp) +{ + rqp->sr_bcount = mb_reserve(&rqp->sr_rq, sizeof (uint16_t)); + rqp->sr_rq.mb_count = 0; +} + +void +smb_rq_bend(struct smb_rq *rqp) +{ + uint_t bcnt; + + if (rqp->sr_bcount == NULL) { + SMBSDEBUG("no bcount\n"); + return; + } + bcnt = rqp->sr_rq.mb_count; + if (bcnt > 0xffff) + SMBSDEBUG("byte count too large (%d)\n", bcnt); + /* + * Fill in the byte count (16-bits) + * The pointer is char * type due to + * typical off-by-one alignment. + */ + rqp->sr_bcount[0] = bcnt & 0xFF; + rqp->sr_bcount[1] = (bcnt >> 8); +} + +int +smb_rq_intr(struct smb_rq *rqp) +{ + if (rqp->sr_flags & SMBR_INTR) + return (EINTR); + + return (0); +#ifdef APPLE + return (smb_sigintr(rqp->sr_cred->scr_vfsctx)); +#endif +} + +int +smb_rq_getrequest(struct smb_rq *rqp, struct mbchain **mbpp) +{ + *mbpp = &rqp->sr_rq; + return (0); +} + +int +smb_rq_getreply(struct smb_rq *rqp, struct mdchain **mbpp) +{ + *mbpp = &rqp->sr_rp; + return (0); +} + +static int +smb_rq_getenv(struct smb_connobj *co, + struct smb_vc **vcpp, struct smb_share **sspp) +{ + struct smb_vc *vcp = NULL; + struct smb_share *ssp = NULL; + int error = 0; + + if (co->co_flags & SMBO_GONE) { + SMBSDEBUG("zombie CO\n"); + error = EINVAL; + goto out; + } + + switch (co->co_level) { + case SMBL_VC: + vcp = CPTOVC(co); + if (co->co_parent == NULL) { + SMBSDEBUG("zombie VC %s\n", vcp->vc_srvname); + error = EINVAL; + break; + } + break; + + case SMBL_SHARE: + ssp = CPTOSS(co); + if (co->co_parent == NULL) { + SMBSDEBUG("zombie share %s\n", ssp->ss_name); + error = EINVAL; + break; + } + error = smb_rq_getenv(co->co_parent, &vcp, NULL); + break; + default: + SMBSDEBUG("invalid level %d passed\n", co->co_level); + error = EINVAL; + } + +out: + if (!error) { + if (vcpp) + *vcpp = vcp; + if (sspp) + *sspp = ssp; + } + + return (error); +} + +/* + * Wait for reply on the request + */ +static int +smb_rq_reply(struct smb_rq *rqp) +{ + struct mdchain *mdp = &rqp->sr_rp; + u_int32_t tdw; + u_int8_t tb; + int error, rperror = 0; + + if (rqp->sr_timo == SMBNOREPLYWAIT) + return (smb_iod_removerq(rqp)); + + error = smb_iod_waitrq(rqp); + if (error) + return (error); + error = md_get_uint32(mdp, &tdw); + if (error) + return (error); + error = md_get_uint8(mdp, &tb); + error = md_get_uint32le(mdp, &rqp->sr_error); + error = md_get_uint8(mdp, &rqp->sr_rpflags); + error = md_get_uint16le(mdp, &rqp->sr_rpflags2); + if (rqp->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) { + /* + * Do a special check for STATUS_BUFFER_OVERFLOW; + * it's not an error. + */ + if (rqp->sr_error == NT_STATUS_BUFFER_OVERFLOW) { + /* + * Don't report it as an error to our caller; + * they can look at rqp->sr_error if they + * need to know whether we got a + * STATUS_BUFFER_OVERFLOW. + * XXX - should we do that for all errors + * where (error & 0xC0000000) is 0x80000000, + * i.e. all warnings? + */ + rperror = 0; + } else + rperror = smb_maperr32(rqp->sr_error); + } else { + rqp->sr_errclass = rqp->sr_error & 0xff; + rqp->sr_serror = rqp->sr_error >> 16; + rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror); + } + if (rperror == EMOREDATA) { + rperror = E2BIG; + rqp->sr_flags |= SMBR_MOREDATA; + } else + rqp->sr_flags &= ~SMBR_MOREDATA; + + error = md_get_uint32(mdp, &tdw); + error = md_get_uint32(mdp, &tdw); + error = md_get_uint32(mdp, &tdw); + + error = md_get_uint16le(mdp, &rqp->sr_rptid); + error = md_get_uint16le(mdp, &rqp->sr_rppid); + error = md_get_uint16le(mdp, &rqp->sr_rpuid); + error = md_get_uint16le(mdp, &rqp->sr_rpmid); + + SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x, E: %d:%d\n", + rqp->sr_rpmid, rqp->sr_rppid, rqp->sr_rpuid, rqp->sr_rptid, + rqp->sr_errclass, rqp->sr_serror); + + return ((error) ? error : rperror); +} + + +#define ALIGN4(a) (((a) + 3) & ~3) + +/* + * TRANS2 request implementation + * TRANS implementation is in the "t2" routines + * NT_TRANSACTION implementation is the separate "nt" stuff + */ +int +smb_t2_alloc(struct smb_connobj *layer, ushort_t setup, struct smb_cred *scred, + struct smb_t2rq **t2pp) +{ + struct smb_t2rq *t2p; + int error; + + t2p = (struct smb_t2rq *)kmem_alloc(sizeof (*t2p), KM_SLEEP); + if (t2p == NULL) + return (ENOMEM); + error = smb_t2_init(t2p, layer, &setup, 1, scred); + mutex_init(&t2p->t2_lock, NULL, MUTEX_DRIVER, NULL); + cv_init(&t2p->t2_cond, NULL, CV_DEFAULT, NULL); + t2p->t2_flags |= SMBT2_ALLOCED; + if (error) { + smb_t2_done(t2p); + return (error); + } + *t2pp = t2p; + return (0); +} + +int +smb_nt_alloc(struct smb_connobj *layer, ushort_t fn, struct smb_cred *scred, + struct smb_ntrq **ntpp) +{ + struct smb_ntrq *ntp; + int error; + + ntp = (struct smb_ntrq *)kmem_alloc(sizeof (*ntp), KM_SLEEP); + if (ntp == NULL) + return (ENOMEM); + error = smb_nt_init(ntp, layer, fn, scred); + mutex_init(&ntp->nt_lock, NULL, MUTEX_DRIVER, NULL); + cv_init(&ntp->nt_cond, NULL, CV_DEFAULT, NULL); + ntp->nt_flags |= SMBT2_ALLOCED; + if (error) { + smb_nt_done(ntp); + return (error); + } + *ntpp = ntp; + return (0); +} + +int +smb_t2_init(struct smb_t2rq *t2p, struct smb_connobj *source, ushort_t *setup, + int setupcnt, struct smb_cred *scred) +{ + int i; + int error; + + bzero(t2p, sizeof (*t2p)); + t2p->t2_source = source; + t2p->t2_setupcount = (u_int16_t)setupcnt; + t2p->t2_setupdata = t2p->t2_setup; + for (i = 0; i < setupcnt; i++) + t2p->t2_setup[i] = setup[i]; + t2p->t2_fid = 0xffff; + t2p->t2_cred = scred; + t2p->t2_share = (source->co_level == SMBL_SHARE ? + CPTOSS(source) : NULL); /* for smb up/down */ + error = smb_rq_getenv(source, &t2p->t2_vc, NULL); + if (error) + return (error); + return (0); +} + +int +smb_nt_init(struct smb_ntrq *ntp, struct smb_connobj *source, ushort_t fn, + struct smb_cred *scred) +{ + int error; + + bzero(ntp, sizeof (*ntp)); + ntp->nt_source = source; + ntp->nt_function = fn; + ntp->nt_cred = scred; + ntp->nt_share = (source->co_level == SMBL_SHARE ? + CPTOSS(source) : NULL); /* for smb up/down */ + error = smb_rq_getenv(source, &ntp->nt_vc, NULL); + if (error) + return (error); + return (0); +} + +void +smb_t2_done(struct smb_t2rq *t2p) +{ + mb_done(&t2p->t2_tparam); + mb_done(&t2p->t2_tdata); + md_done(&t2p->t2_rparam); + md_done(&t2p->t2_rdata); + mutex_destroy(&t2p->t2_lock); + cv_destroy(&t2p->t2_cond); +#ifdef NOTYETRESOLVED + if (t2p->t2_flags & SMBT2_ALLOCED) + kmem_free(t2p, sizeof (*t2p)); +#endif + if (t2p) { + kmem_free(t2p, sizeof (*t2p)); + } +} + +u_int32_t +smb_t2_err(struct smb_t2rq *t2p) +{ + /* mask off "severity" and the "component" bit */ + return (t2p->t2_sr_error & ~(0xe0000000)); +} + +void +smb_nt_done(struct smb_ntrq *ntp) +{ + mb_done(&ntp->nt_tsetup); + mb_done(&ntp->nt_tparam); + mb_done(&ntp->nt_tdata); + md_done(&ntp->nt_rparam); + md_done(&ntp->nt_rdata); + cv_destroy(&ntp->nt_cond); + mutex_destroy(&ntp->nt_lock); + if (ntp->nt_flags & SMBT2_ALLOCED) + kmem_free(ntp, sizeof (*ntp)); +} + +/* + * Extract data [offset,count] from mtop and add to mdp. + */ +static int +smb_t2_placedata(mblk_t *mtop, u_int16_t offset, u_int16_t count, + struct mdchain *mdp) +{ + mblk_t *n; + + n = m_copym(mtop, offset, count, M_WAITOK); + if (n == NULL) + return (EBADRPC); + + if (mdp->md_top == NULL) { + md_initm(mdp, n); + } else + m_cat(mdp->md_top, n); + + return (0); +} + +static int +smb_t2_reply(struct smb_t2rq *t2p) +{ + struct mdchain *mdp; + struct smb_rq *rqp = t2p->t2_rq; + int error, error2, totpgot, totdgot; + u_int16_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp; + u_int16_t tmp, bc, dcount; + u_int8_t wc; + + t2p->t2_flags &= ~SMBT2_MOREDATA; + + error = smb_rq_reply(rqp); + if (rqp->sr_flags & SMBR_MOREDATA) + t2p->t2_flags |= SMBT2_MOREDATA; + t2p->t2_sr_errclass = rqp->sr_errclass; + t2p->t2_sr_serror = rqp->sr_serror; + t2p->t2_sr_error = rqp->sr_error; + t2p->t2_sr_rpflags2 = rqp->sr_rpflags2; + if (error && !(rqp->sr_flags & SMBR_MOREDATA)) + return (error); + /* + * Now we have to get all subseqent responses, if any. + * The CIFS specification says that they can be misordered, + * which is weird. + * TODO: timo + */ + totpgot = totdgot = 0; + totpcount = totdcount = 0xffff; + mdp = &rqp->sr_rp; + for (;;) { + DTRACE_PROBE2(smb_trans_reply, + (smb_rq_t *), rqp, (mblk_t *), mdp->md_top); + m_dumpm(mdp->md_top); + + if ((error2 = md_get_uint8(mdp, &wc)) != 0) + break; + if (wc < 10) { + error2 = ENOENT; + break; + } + if ((error2 = md_get_uint16le(mdp, &tmp)) != 0) + break; + if (totpcount > tmp) + totpcount = tmp; + if ((error2 = md_get_uint16le(mdp, &tmp)) != 0) + break; + if (totdcount > tmp) + totdcount = tmp; + if ((error2 = md_get_uint16le(mdp, &tmp)) != 0 || /* reserved */ + (error2 = md_get_uint16le(mdp, &pcount)) != 0 || + (error2 = md_get_uint16le(mdp, &poff)) != 0 || + (error2 = md_get_uint16le(mdp, &pdisp)) != 0) + break; + if (pcount != 0 && pdisp != totpgot) { + SMBSDEBUG("Can't handle misordered parameters %d:%d\n", + pdisp, totpgot); + error2 = EINVAL; + break; + } + if ((error2 = md_get_uint16le(mdp, &dcount)) != 0 || + (error2 = md_get_uint16le(mdp, &doff)) != 0 || + (error2 = md_get_uint16le(mdp, &ddisp)) != 0) + break; + if (dcount != 0 && ddisp != totdgot) { + SMBSDEBUG("Can't handle misordered data: dcount %d\n", + dcount); + error2 = EINVAL; + break; + } + + /* XXX: Skip setup words? We don't save them? */ + md_get_uint8(mdp, &wc); /* SetupCount */ + md_get_uint8(mdp, NULL); /* Reserved2 */ + tmp = wc; + while (tmp--) + md_get_uint16(mdp, NULL); + + if ((error2 = md_get_uint16le(mdp, &bc)) != 0) + break; + + /* + * There are pad bytes here, and the poff value + * indicates where the next data are found. + * No need to guess at the padding size. + */ + if (pcount) { + error2 = smb_t2_placedata(mdp->md_top, poff, + pcount, &t2p->t2_rparam); + if (error2) + break; + } + totpgot += pcount; + + if (dcount) { + error2 = smb_t2_placedata(mdp->md_top, doff, + dcount, &t2p->t2_rdata); + if (error2) + break; + } + totdgot += dcount; + + if (totpgot >= totpcount && totdgot >= totdcount) { + error2 = 0; + t2p->t2_flags |= SMBT2_ALLRECV; + break; + } + /* + * We're done with this reply, look for the next one. + */ + SMBRQ_LOCK(rqp); + md_next_record(&rqp->sr_rp); + SMBRQ_UNLOCK(rqp); + error2 = smb_rq_reply(rqp); + if (rqp->sr_flags & SMBR_MOREDATA) + t2p->t2_flags |= SMBT2_MOREDATA; + if (!error2) + continue; + t2p->t2_sr_errclass = rqp->sr_errclass; + t2p->t2_sr_serror = rqp->sr_serror; + t2p->t2_sr_error = rqp->sr_error; + t2p->t2_sr_rpflags2 = rqp->sr_rpflags2; + error = error2; + if (!(rqp->sr_flags & SMBR_MOREDATA)) + break; + } + return (error ? error : error2); +} + +static int +smb_nt_reply(struct smb_ntrq *ntp) +{ + struct mdchain *mdp; + struct smb_rq *rqp = ntp->nt_rq; + int error, error2; + u_int32_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp; + u_int32_t tmp, dcount, totpgot, totdgot; + u_int16_t bc; + u_int8_t wc; + + ntp->nt_flags &= ~SMBT2_MOREDATA; + + error = smb_rq_reply(rqp); + if (rqp->sr_flags & SMBR_MOREDATA) + ntp->nt_flags |= SMBT2_MOREDATA; + ntp->nt_sr_error = rqp->sr_error; + ntp->nt_sr_rpflags2 = rqp->sr_rpflags2; + if (error && !(rqp->sr_flags & SMBR_MOREDATA)) + return (error); + /* + * Now we have to get all subseqent responses. The CIFS specification + * says that they can be misordered which is weird. + * TODO: timo + */ + totpgot = totdgot = 0; + totpcount = totdcount = 0xffffffff; + mdp = &rqp->sr_rp; + for (;;) { + DTRACE_PROBE2(smb_trans_reply, + (smb_rq_t *), rqp, (mblk_t *), mdp->md_top); + m_dumpm(mdp->md_top); + + if ((error2 = md_get_uint8(mdp, &wc)) != 0) + break; + if (wc < 18) { + error2 = ENOENT; + break; + } + md_get_mem(mdp, NULL, 3, MB_MSYSTEM); /* reserved */ + if ((error2 = md_get_uint32le(mdp, &tmp)) != 0) + break; + if (totpcount > tmp) + totpcount = tmp; + if ((error2 = md_get_uint32le(mdp, &tmp)) != 0) + break; + if (totdcount > tmp) + totdcount = tmp; + if ((error2 = md_get_uint32le(mdp, &pcount)) != 0 || + (error2 = md_get_uint32le(mdp, &poff)) != 0 || + (error2 = md_get_uint32le(mdp, &pdisp)) != 0) + break; + if (pcount != 0 && pdisp != totpgot) { + SMBSDEBUG("Can't handle misordered parameters %d:%d\n", + pdisp, totpgot); + error2 = EINVAL; + break; + } + if ((error2 = md_get_uint32le(mdp, &dcount)) != 0 || + (error2 = md_get_uint32le(mdp, &doff)) != 0 || + (error2 = md_get_uint32le(mdp, &ddisp)) != 0) + break; + if (dcount != 0 && ddisp != totdgot) { + SMBSDEBUG("Can't handle misordered data: dcount %d\n", + dcount); + error2 = EINVAL; + break; + } + + /* XXX: Skip setup words? We don't save them? */ + md_get_uint8(mdp, &wc); /* SetupCount */ + tmp = wc; + while (tmp--) + md_get_uint16(mdp, NULL); + + if ((error2 = md_get_uint16le(mdp, &bc)) != 0) + break; + + /* + * There are pad bytes here, and the poff value + * indicates where the next data are found. + * No need to guess at the padding size. + */ + if (pcount) { + error2 = smb_t2_placedata(mdp->md_top, poff, pcount, + &ntp->nt_rparam); + if (error2) + break; + } + totpgot += pcount; + + if (dcount) { + error2 = smb_t2_placedata(mdp->md_top, doff, dcount, + &ntp->nt_rdata); + if (error2) + break; + } + totdgot += dcount; + + if (totpgot >= totpcount && totdgot >= totdcount) { + error2 = 0; + ntp->nt_flags |= SMBT2_ALLRECV; + break; + } + /* + * We're done with this reply, look for the next one. + */ + SMBRQ_LOCK(rqp); + md_next_record(&rqp->sr_rp); + SMBRQ_UNLOCK(rqp); + error2 = smb_rq_reply(rqp); + if (rqp->sr_flags & SMBR_MOREDATA) + ntp->nt_flags |= SMBT2_MOREDATA; + if (!error2) + continue; + ntp->nt_sr_error = rqp->sr_error; + ntp->nt_sr_rpflags2 = rqp->sr_rpflags2; + error = error2; + if (!(rqp->sr_flags & SMBR_MOREDATA)) + break; + } + return (error ? error : error2); +} + +int md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret); +int mb_put_mbuf(struct mbchain *mbp, mblk_t *m); + +/* + * Perform a full round of TRANS2 request + */ +static int +smb_t2_request_int(struct smb_t2rq *t2p) +{ + struct smb_vc *vcp = t2p->t2_vc; + struct smb_cred *scred = t2p->t2_cred; + struct mbchain *mbp; + struct mdchain *mdp, mbparam, mbdata; + mblk_t *m; + struct smb_rq *rqp; + int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i; + int error, doff, poff, txdcount, txpcount, nmlen; + + m = t2p->t2_tparam.mb_top; + if (m) { + md_initm(&mbparam, m); /* do not free it! */ + totpcount = m_fixhdr(m); + if (totpcount > 0xffff) /* maxvalue for ushort_t */ + return (EINVAL); + } else + totpcount = 0; + m = t2p->t2_tdata.mb_top; + if (m) { + md_initm(&mbdata, m); /* do not free it! */ + totdcount = m_fixhdr(m); + if (totdcount > 0xffff) + return (EINVAL); + } else + totdcount = 0; + leftdcount = totdcount; + leftpcount = totpcount; + txmax = vcp->vc_txmax; + error = smb_rq_alloc(t2p->t2_source, t2p->t_name[0] ? + SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred, &rqp); + if (error) + return (error); + rqp->sr_timo = smb_timo_default; + rqp->sr_flags |= SMBR_MULTIPACKET; + t2p->t2_rq = rqp; + mbp = &rqp->sr_rq; + smb_rq_wstart(rqp); + mb_put_uint16le(mbp, totpcount); + mb_put_uint16le(mbp, totdcount); + mb_put_uint16le(mbp, t2p->t2_maxpcount); + mb_put_uint16le(mbp, t2p->t2_maxdcount); + mb_put_uint8(mbp, t2p->t2_maxscount); + mb_put_uint8(mbp, 0); /* reserved */ + mb_put_uint16le(mbp, 0); /* flags */ + mb_put_uint32le(mbp, 0); /* Timeout */ + mb_put_uint16le(mbp, 0); /* reserved 2 */ + len = mb_fixhdr(mbp); + + /* + * now we have known packet size as + * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + strlen(name) + 1), + * and need to decide which parts should go into the first request + */ + nmlen = t2p->t_name ? strlen(t2p->t_name) : 0; + len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmlen + 1); + if (len + leftpcount > txmax) { + txpcount = min(leftpcount, txmax - len); + poff = len; + txdcount = 0; + doff = 0; + } else { + txpcount = leftpcount; + poff = txpcount ? len : 0; + /* + * Other client traffic seems to "ALIGN2" here. The extra + * 2 byte pad we use has no observed downside and may be + * required for some old servers(?) + */ + len = ALIGN4(len + txpcount); + txdcount = min(leftdcount, txmax - len); + doff = txdcount ? len : 0; + } + leftpcount -= txpcount; + leftdcount -= txdcount; + mb_put_uint16le(mbp, txpcount); + mb_put_uint16le(mbp, poff); + mb_put_uint16le(mbp, txdcount); + mb_put_uint16le(mbp, doff); + mb_put_uint8(mbp, t2p->t2_setupcount); + mb_put_uint8(mbp, 0); + for (i = 0; i < t2p->t2_setupcount; i++) { + mb_put_uint16le(mbp, t2p->t2_setupdata[i]); + } + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + /* TDUNICODE */ + if (t2p->t_name) + mb_put_mem(mbp, t2p->t_name, nmlen, MB_MSYSTEM); + mb_put_uint8(mbp, 0); /* terminating zero */ + len = mb_fixhdr(mbp); + if (txpcount) { + mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); + error = md_get_mbuf(&mbparam, txpcount, &m); + SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax); + if (error) + goto freerq; + mb_put_mbuf(mbp, m); + } + len = mb_fixhdr(mbp); + if (txdcount) { + mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); + error = md_get_mbuf(&mbdata, txdcount, &m); + if (error) + goto freerq; + mb_put_mbuf(mbp, m); + } + smb_rq_bend(rqp); /* incredible, but thats it... */ + error = smb_rq_enqueue(rqp); + if (error) + goto freerq; + if (leftpcount || leftdcount) { + error = smb_rq_reply(rqp); + if (error) + goto bad; + /* + * this is an interim response, ignore it. + */ + SMBRQ_LOCK(rqp); + md_next_record(&rqp->sr_rp); + SMBRQ_UNLOCK(rqp); + } + while (leftpcount || leftdcount) { + error = smb_rq_new(rqp, t2p->t_name ? + SMB_COM_TRANSACTION_SECONDARY : + SMB_COM_TRANSACTION2_SECONDARY); + if (error) + goto bad; + mbp = &rqp->sr_rq; + smb_rq_wstart(rqp); + mb_put_uint16le(mbp, totpcount); + mb_put_uint16le(mbp, totdcount); + len = mb_fixhdr(mbp); + /* + * now we have known packet size as + * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one, + * and need to decide which parts should go into request + */ + len = ALIGN4(len + 6 * 2 + 2); + if (t2p->t_name == NULL) + len += 2; + if (len + leftpcount > txmax) { + txpcount = min(leftpcount, txmax - len); + poff = len; + txdcount = 0; + doff = 0; + } else { + txpcount = leftpcount; + poff = txpcount ? len : 0; + len = ALIGN4(len + txpcount); + txdcount = min(leftdcount, txmax - len); + doff = txdcount ? len : 0; + } + mb_put_uint16le(mbp, txpcount); + mb_put_uint16le(mbp, poff); + mb_put_uint16le(mbp, totpcount - leftpcount); + mb_put_uint16le(mbp, txdcount); + mb_put_uint16le(mbp, doff); + mb_put_uint16le(mbp, totdcount - leftdcount); + leftpcount -= txpcount; + leftdcount -= txdcount; + if (t2p->t_name == NULL) + mb_put_uint16le(mbp, t2p->t2_fid); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint8(mbp, 0); /* name */ + len = mb_fixhdr(mbp); + if (txpcount) { + mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); + error = md_get_mbuf(&mbparam, txpcount, &m); + if (error) + goto bad; + mb_put_mbuf(mbp, m); + } + len = mb_fixhdr(mbp); + if (txdcount) { + mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); + error = md_get_mbuf(&mbdata, txdcount, &m); + if (error) + goto bad; + mb_put_mbuf(mbp, m); + } + smb_rq_bend(rqp); + error = smb_iod_multirq(rqp); + if (error) + goto bad; + } /* while left params or data */ + error = smb_t2_reply(t2p); + if (error && !(t2p->t2_flags & SMBT2_MOREDATA)) + goto bad; + mdp = &t2p->t2_rdata; + if (mdp->md_top) { + m_fixhdr(mdp->md_top); + md_initm(mdp, mdp->md_top); + } + mdp = &t2p->t2_rparam; + if (mdp->md_top) { + m_fixhdr(mdp->md_top); + md_initm(mdp, mdp->md_top); + } +bad: + smb_iod_removerq(rqp); +freerq: + if (error && !(t2p->t2_flags & SMBT2_MOREDATA)) { + if (rqp->sr_flags & SMBR_RESTART) + t2p->t2_flags |= SMBT2_RESTART; + md_done(&t2p->t2_rparam); + md_done(&t2p->t2_rdata); + } + smb_rq_done(rqp); + return (error); +} + + +/* + * Perform a full round of NT_TRANSACTION request + */ +static int +smb_nt_request_int(struct smb_ntrq *ntp) +{ + struct smb_vc *vcp = ntp->nt_vc; + struct smb_cred *scred = ntp->nt_cred; + struct mbchain *mbp; + struct mdchain *mdp, mbsetup, mbparam, mbdata; + mblk_t *m; + struct smb_rq *rqp; + int totpcount, leftpcount, totdcount, leftdcount, len, txmax; + int error, doff, poff, txdcount, txpcount; + int totscount; + + m = ntp->nt_tsetup.mb_top; + if (m) { + md_initm(&mbsetup, m); /* do not free it! */ + totscount = m_fixhdr(m); + if (totscount > 2 * 0xff) + return (EINVAL); + } else + totscount = 0; + m = ntp->nt_tparam.mb_top; + if (m) { + md_initm(&mbparam, m); /* do not free it! */ + totpcount = m_fixhdr(m); + if (totpcount > 0x7fffffff) + return (EINVAL); + } else + totpcount = 0; + m = ntp->nt_tdata.mb_top; + if (m) { + md_initm(&mbdata, m); /* do not free it! */ + totdcount = m_fixhdr(m); + if (totdcount > 0x7fffffff) + return (EINVAL); + } else + totdcount = 0; + leftdcount = totdcount; + leftpcount = totpcount; + txmax = vcp->vc_txmax; + error = smb_rq_alloc(ntp->nt_source, SMB_COM_NT_TRANSACT, scred, &rqp); + if (error) + return (error); + rqp->sr_timo = smb_timo_default; + rqp->sr_flags |= SMBR_MULTIPACKET; + ntp->nt_rq = rqp; + mbp = &rqp->sr_rq; + smb_rq_wstart(rqp); + mb_put_uint8(mbp, ntp->nt_maxscount); + mb_put_uint16le(mbp, 0); /* reserved (flags?) */ + mb_put_uint32le(mbp, totpcount); + mb_put_uint32le(mbp, totdcount); + mb_put_uint32le(mbp, ntp->nt_maxpcount); + mb_put_uint32le(mbp, ntp->nt_maxdcount); + len = mb_fixhdr(mbp); + /* + * now we have known packet size as + * ALIGN4(len + 4 * 4 + 1 + 2 + ((totscount+1)&~1) + 2), + * and need to decide which parts should go into the first request + */ + len = ALIGN4(len + 4 * 4 + 1 + 2 + ((totscount+1)&~1) + 2); + if (len + leftpcount > txmax) { + txpcount = min(leftpcount, txmax - len); + poff = len; + txdcount = 0; + doff = 0; + } else { + txpcount = leftpcount; + poff = txpcount ? len : 0; + len = ALIGN4(len + txpcount); + txdcount = min(leftdcount, txmax - len); + doff = txdcount ? len : 0; + } + leftpcount -= txpcount; + leftdcount -= txdcount; + mb_put_uint32le(mbp, txpcount); + mb_put_uint32le(mbp, poff); + mb_put_uint32le(mbp, txdcount); + mb_put_uint32le(mbp, doff); + mb_put_uint8(mbp, (totscount+1)/2); + mb_put_uint16le(mbp, ntp->nt_function); + if (totscount) { + error = md_get_mbuf(&mbsetup, totscount, &m); + SMBSDEBUG("%d:%d:%d\n", error, totscount, txmax); + if (error) + goto freerq; + mb_put_mbuf(mbp, m); + if (totscount & 1) + mb_put_uint8(mbp, 0); /* setup is in words */ + } + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + len = mb_fixhdr(mbp); + if (txpcount) { + mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); + error = md_get_mbuf(&mbparam, txpcount, &m); + SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax); + if (error) + goto freerq; + mb_put_mbuf(mbp, m); + } + len = mb_fixhdr(mbp); + if (txdcount) { + mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); + error = md_get_mbuf(&mbdata, txdcount, &m); + if (error) + goto freerq; + mb_put_mbuf(mbp, m); + } + smb_rq_bend(rqp); /* incredible, but thats it... */ + error = smb_rq_enqueue(rqp); + if (error) + goto freerq; + if (leftpcount || leftdcount) { + error = smb_rq_reply(rqp); + if (error) + goto bad; + /* + * this is an interim response, ignore it. + */ + SMBRQ_LOCK(rqp); + md_next_record(&rqp->sr_rp); + SMBRQ_UNLOCK(rqp); + } + while (leftpcount || leftdcount) { + error = smb_rq_new(rqp, SMB_COM_NT_TRANSACT_SECONDARY); + if (error) + goto bad; + mbp = &rqp->sr_rq; + smb_rq_wstart(rqp); + mb_put_mem(mbp, NULL, 3, MB_MZERO); + mb_put_uint32le(mbp, totpcount); + mb_put_uint32le(mbp, totdcount); + len = mb_fixhdr(mbp); + /* + * now we have known packet size as + * ALIGN4(len + 6 * 4 + 2) + * and need to decide which parts should go into request + */ + len = ALIGN4(len + 6 * 4 + 2); + if (len + leftpcount > txmax) { + txpcount = min(leftpcount, txmax - len); + poff = len; + txdcount = 0; + doff = 0; + } else { + txpcount = leftpcount; + poff = txpcount ? len : 0; + len = ALIGN4(len + txpcount); + txdcount = min(leftdcount, txmax - len); + doff = txdcount ? len : 0; + } + mb_put_uint32le(mbp, txpcount); + mb_put_uint32le(mbp, poff); + mb_put_uint32le(mbp, totpcount - leftpcount); + mb_put_uint32le(mbp, txdcount); + mb_put_uint32le(mbp, doff); + mb_put_uint32le(mbp, totdcount - leftdcount); + leftpcount -= txpcount; + leftdcount -= txdcount; + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + len = mb_fixhdr(mbp); + if (txpcount) { + mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); + error = md_get_mbuf(&mbparam, txpcount, &m); + if (error) + goto bad; + mb_put_mbuf(mbp, m); + } + len = mb_fixhdr(mbp); + if (txdcount) { + mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); + error = md_get_mbuf(&mbdata, txdcount, &m); + if (error) + goto bad; + mb_put_mbuf(mbp, m); + } + smb_rq_bend(rqp); + error = smb_iod_multirq(rqp); + if (error) + goto bad; + } /* while left params or data */ + error = smb_nt_reply(ntp); + if (error && !(ntp->nt_flags & SMBT2_MOREDATA)) + goto bad; + mdp = &ntp->nt_rdata; + if (mdp->md_top) { + m_fixhdr(mdp->md_top); + md_initm(mdp, mdp->md_top); + } + mdp = &ntp->nt_rparam; + if (mdp->md_top) { + m_fixhdr(mdp->md_top); + md_initm(mdp, mdp->md_top); + } +bad: + smb_iod_removerq(rqp); +freerq: + if (error && !(ntp->nt_flags & SMBT2_MOREDATA)) { + if (rqp->sr_flags & SMBR_RESTART) + ntp->nt_flags |= SMBT2_RESTART; + md_done(&ntp->nt_rparam); + md_done(&ntp->nt_rdata); + } + smb_rq_done(rqp); + return (error); +} + +int +smb_t2_request(struct smb_t2rq *t2p) +{ + int error = EINVAL, i; + + for (i = 0; ; ) { + /* + * Don't send any new requests if force unmount is underway. + * This check was moved into smb_rq_enqueue, called by + * smb_t2_request_int() + */ + t2p->t2_flags &= ~SMBT2_RESTART; + error = smb_t2_request_int(t2p); + if (!error) + break; + if ((t2p->t2_flags & (SMBT2_RESTART | SMBT2_NORESTART)) != + SMBT2_RESTART) + break; + if (++i > SMBMAXRESTARTS) + break; + mutex_enter(&(t2p)->t2_lock); + if (t2p->t2_share && t2p->t2_share->ss_mount) { + cv_timedwait(&t2p->t2_cond, &(t2p)->t2_lock, + lbolt + (hz * SMB_RCNDELAY)); + } else { + delay(lbolt + (hz * SMB_RCNDELAY)); + } + mutex_exit(&(t2p)->t2_lock); + } + return (error); +} + + +int +smb_nt_request(struct smb_ntrq *ntp) +{ + int error = EINVAL, i; + + for (i = 0; ; ) { + /* + * Don't send any new requests if force unmount is underway. + * This check was moved into smb_rq_enqueue, called by + * smb_nt_request_int() + */ + ntp->nt_flags &= ~SMBT2_RESTART; + error = smb_nt_request_int(ntp); + if (!error) + break; + if ((ntp->nt_flags & (SMBT2_RESTART | SMBT2_NORESTART)) != + SMBT2_RESTART) + break; + if (++i > SMBMAXRESTARTS) + break; + mutex_enter(&(ntp)->nt_lock); + if (ntp->nt_share && ntp->nt_share->ss_mount) { + cv_timedwait(&ntp->nt_cond, &(ntp)->nt_lock, + lbolt + (hz * SMB_RCNDELAY)); + + } else { + delay(lbolt + (hz * SMB_RCNDELAY)); + } + mutex_exit(&(ntp)->nt_lock); + } + return (error); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2000-2001, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_rq.h,v 1.9 2005/01/22 22:20:58 lindak Exp $ + */ +#ifndef _NETSMB_SMB_RQ_H_ +#define _NETSMB_SMB_RQ_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <netsmb/mchain.h> +#include <sys/queue.h> + +#define SMBR_ALLOCED 0x0001 /* structure was malloced */ +#define SMBR_SENT 0x0002 /* request successfully transmitted */ +#define SMBR_REXMIT 0x0004 /* request should be retransmitted */ +#define SMBR_INTR 0x0008 /* request interrupted */ +#define SMBR_RESTART 0x0010 /* req should be repeated if possible */ +#define SMBR_NORESTART 0x0020 /* request is not restartable */ +#define SMBR_MULTIPACKET 0x0040 /* multiple pkts can be sent/received */ +#define SMBR_INTERNAL 0x0080 /* request is internal to netsmb */ +#define SMBR_NOINTR_SEND 0x0100 /* no interrupt in send wait */ +#define SMBR_NOINTR_RECV 0x0200 /* no interrupt in recv wait */ +#define SMBR_SENDWAIT 0x0400 /* waiting for send to complete */ +#define SMBR_VCREF 0x4000 /* took vc reference */ +#define SMBR_MOREDATA 0x8000 /* our buffer was too small */ + +#define SMBT2_ALLSENT 0x0001 /* all data and params are sent */ +#define SMBT2_ALLRECV 0x0002 /* all data and params are received */ +#define SMBT2_ALLOCED 0x0004 +#define SMBT2_RESTART 0x0008 +#define SMBT2_NORESTART 0x0010 +#define SMBT2_MOREDATA 0x8000 /* our buffer was too small */ + +#define SMBRQ_LOCK(rqp) mutex_enter(&(rqp)->sr_lock) +#define SMBRQ_UNLOCK(rqp) mutex_exit(&(rqp)->sr_lock) + + +enum smbrq_state { + SMBRQ_NOTSENT, /* rq have data to send */ + SMBRQ_SENT, /* send procedure completed */ + SMBRQ_REPLYRECEIVED, + SMBRQ_NOTIFIED /* owner notified about completion */ +}; + +struct smb_vc; + +struct smb_rq { + TAILQ_ENTRY(smb_rq) sr_link; + kmutex_t sr_lock; + kcondvar_t sr_cond; + enum smbrq_state sr_state; + struct smb_vc *sr_vc; + struct smb_share *sr_share; + struct _kthread *sr_owner; + ushort_t sr_mid; + struct mbchain sr_rq; + uchar_t sr_cmd; + uint8_t sr_rqflags; + uint16_t sr_rqflags2; + uchar_t *sr_wcount; + uchar_t *sr_bcount; + struct mdchain sr_rp; + int sr_rpgen; + int sr_rplast; + int sr_flags; /* SMBR_* */ + int sr_rpsize; + struct smb_cred *sr_cred; + int sr_timo; + int sr_rexmit; /* how many more retries. dflt 0 */ + int sr_sendcnt; + struct timespec sr_timesent; + int sr_lerror; + uint16_t *sr_rqtid; + uint16_t *sr_rquid; + uint8_t sr_errclass; + uint16_t sr_serror; + uint32_t sr_error; + uint8_t sr_rpflags; + uint16_t sr_rpflags2; + uint16_t sr_rptid; + uint16_t sr_rppid; + uint16_t sr_rpuid; + uint16_t sr_rpmid; +}; +typedef struct smb_rq smb_rq_t; + +struct smb_t2rq { + kmutex_t t2_lock; + kcondvar_t t2_cond; + uint16_t t2_setupcount; + uint16_t *t2_setupdata; + uint16_t t2_setup[SMB_MAXSETUPWORDS]; + uint8_t t2_maxscount; /* max setup words to return */ + uint16_t t2_maxpcount; /* max param bytes to return */ + uint16_t t2_maxdcount; /* max data bytes to return */ + uint16_t t2_fid; /* for T2 request */ + char t_name[128]; /* for T, should be zero for T2 */ + int t2_flags; /* SMBT2_ */ + struct mbchain t2_tparam; /* parameters to transmit */ + struct mbchain t2_tdata; /* data to transmit */ + struct mdchain t2_rparam; /* received paramters */ + struct mdchain t2_rdata; /* received data */ + struct smb_cred *t2_cred; + struct smb_connobj *t2_source; + struct smb_rq *t2_rq; + struct smb_vc *t2_vc; + struct smb_share *t2_share; /* for smb up/down */ + /* unmapped windows error detail */ + uint8_t t2_sr_errclass; + uint16_t t2_sr_serror; + uint32_t t2_sr_error; + uint16_t t2_sr_rpflags2; +}; +typedef struct smb_t2rq smb_t2rq_t; + +struct smb_ntrq { + kmutex_t nt_lock; + kcondvar_t nt_cond; + uint16_t nt_function; + uint8_t nt_maxscount; /* max setup words to return */ + uint32_t nt_maxpcount; /* max param bytes to return */ + uint32_t nt_maxdcount; /* max data bytes to return */ + int nt_flags; /* SMBT2_ */ + struct mbchain nt_tsetup; /* setup to transmit */ + struct mbchain nt_tparam; /* parameters to transmit */ + struct mbchain nt_tdata; /* data to transmit */ + struct mdchain nt_rparam; /* received paramters */ + struct mdchain nt_rdata; /* received data */ + struct smb_cred *nt_cred; + struct smb_connobj *nt_source; + struct smb_rq *nt_rq; + struct smb_vc *nt_vc; + struct smb_share *nt_share; /* for smb up/down */ + /* unmapped windows error details */ + uint32_t nt_sr_error; + uint16_t nt_sr_rpflags2; +}; +typedef struct smb_ntrq smb_ntrq_t; + +int smb_rq_alloc(struct smb_connobj *layer, uchar_t cmd, + struct smb_cred *scred, struct smb_rq **rqpp); +int smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer, + uchar_t cmd, struct smb_cred *scred); +void smb_rq_done(struct smb_rq *rqp); +int smb_rq_getrequest(struct smb_rq *rqp, struct mbchain **mbpp); +int smb_rq_getreply(struct smb_rq *rqp, struct mdchain **mbpp); +void smb_rq_wstart(struct smb_rq *rqp); +void smb_rq_wend(struct smb_rq *rqp); +void smb_rq_bstart(struct smb_rq *rqp); +void smb_rq_bend(struct smb_rq *rqp); +int smb_rq_intr(struct smb_rq *rqp); +int smb_rq_simple(struct smb_rq *rqp); +int smb_rq_simple_timed(struct smb_rq *rqp, int timeout); + +int smb_t2_alloc(struct smb_connobj *layer, ushort_t setup, + struct smb_cred *scred, struct smb_t2rq **rqpp); +int smb_t2_init(struct smb_t2rq *rqp, struct smb_connobj *layer, + ushort_t *setup, int setupcnt, struct smb_cred *scred); +void smb_t2_done(struct smb_t2rq *t2p); +int smb_t2_request(struct smb_t2rq *t2p); +uint32_t smb_t2_err(struct smb_t2rq *t2p); + +int smb_nt_alloc(struct smb_connobj *layer, ushort_t fn, + struct smb_cred *scred, struct smb_ntrq **rqpp); +int smb_nt_init(struct smb_ntrq *rqp, struct smb_connobj *layer, + ushort_t fn, struct smb_cred *scred); +void smb_nt_done(struct smb_ntrq *ntp); +int smb_nt_request(struct smb_ntrq *ntp); + +#endif /* _NETSMB_SMB_RQ_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,1783 @@ +/* + * Copyright (c) 2000-2001 Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_smb.c,v 1.35.100.2 2005/06/02 00:55:39 lindak Exp $ + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * various SMB requests. Most of the routines merely packs data into mbufs. + */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kmem.h> +#include <sys/proc.h> +#include <sys/lock.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/random.h> +#include <sys/note.h> +#include <sys/cmn_err.h> + +#ifdef APPLE +#include <sys/smb_apple.h> +#include <sys/utfconv.h> +#else +#include <netsmb/smb_osdep.h> +#endif + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_rq.h> +#include <netsmb/smb_subr.h> +#include <netsmb/smb_tran.h> + +/* + * Largest size to use with LARGE_READ/LARGE_WRITE. + * Specs say up to 64k data bytes, but Windows traffic + * uses 60k... no doubt for some good reason. + * (Probably to keep 4k block alignment.) + * XXX: Move to smb.h maybe? + */ +#define SMB_MAX_LARGE_RW_SIZE (60*1024) + +/* + * Default timeout values, all in seconds. + * Make these tunable (only via mdb for now). + */ +int smb_timo_notice = 15; +int smb_timo_default = 30; /* was SMB_DEFRQTIMO */ +int smb_timo_open = 45; +int smb_timo_read = 45; +int smb_timo_write = 60; /* was SMBWRTTIMO */ +int smb_timo_append = 90; + +static int smb_smb_read(struct smb_share *ssp, u_int16_t fid, + int *len, int *rresid, uio_t *uiop, struct smb_cred *scred, int timo); +static int smb_smb_write(struct smb_share *ssp, u_int16_t fid, + int *len, int *rresid, uio_t *uiop, struct smb_cred *scred, int timo); + +struct smb_dialect { + int d_id; + const char *d_name; +}; + +smb_unichar smb_unieol = 0; + +static struct smb_dialect smb_dialects[] = { + {SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"}, + {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"}, + {SMB_DIALECT_LANMAN2_0, "LM1.2X002"}, + {SMB_DIALECT_LANMAN2_1, "LANMAN2.1"}, + {SMB_DIALECT_NTLM0_12, "NT LM 0.12"}, + {-1, NULL} +}; + +#define SMB_DIALECT_MAX \ + (sizeof (smb_dialects) / sizeof (struct smb_dialect) - 2) + +/* + * Number of seconds between 1970 and 1601 year + */ +const u_int64_t DIFF1970TO1601 = 11644473600ULL; + +void +smb_time_local2server(struct timespec *tsp, int tzoff, long *seconds) +{ + /* + * XXX - what if we connected to the server when it was in + * daylight savings/summer time and we've subsequently switched + * to standard time, or vice versa, so that the time zone + * offset we got from the server is now wrong? + */ + *seconds = tsp->tv_sec - tzoff * 60; + /* - tz.tz_minuteswest * 60 - (wall_cmos_clock ? adjkerntz : 0) */ +} + +void +smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp) +{ + /* + * XXX - what if we connected to the server when it was in + * daylight savings/summer time and we've subsequently switched + * to standard time, or vice versa, so that the time zone + * offset we got from the server is now wrong? + */ + tsp->tv_sec = seconds + tzoff * 60; + /* + tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); */ + tsp->tv_nsec = 0; +} + +/* + * Time from server comes as UTC, so no need to use tz + */ +/*ARGSUSED*/ +void +smb_time_NT2local(u_int64_t nsec, int tzoff, struct timespec *tsp) +{ + smb_time_server2local(nsec / 10000000 - DIFF1970TO1601, 0, tsp); +} + +/*ARGSUSED*/ +void +smb_time_local2NT(struct timespec *tsp, int tzoff, u_int64_t *nsec) +{ + long seconds; + + smb_time_local2server(tsp, 0, &seconds); + *nsec = (((u_int64_t)(seconds) & ~1) + DIFF1970TO1601) * + (u_int64_t)10000000; +} + +#if defined(NOICONVSUPPORT) || defined(lint) +extern int iconv_open(const char *to, const char *from, void **handle); +extern int iconv_close(void *handle); +#endif + +int +smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) +{ + struct smb_dialect *dp; + struct smb_sopt *sp = NULL; + struct smb_rq *rqp; + struct mbchain *mbp; + struct mdchain *mdp; + u_int8_t wc, stime[8], sblen; + u_int16_t dindex, tw, tw1, swlen, bc; + int error; + int unicode = 0; + char *servercs; + void *servercshandle = NULL; + void *localcshandle = NULL; + u_int16_t toklen; + + vcp->vc_hflags = SMB_FLAGS_CASELESS; /* XXX on Unix? */ + /* + * Make sure SMB_FLAGS2_UNICODE is "off" so mb_put_dstring + * marshalls the dialect strings in plain ascii. + */ + vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE; + vcp->vc_hflags2 |= SMB_FLAGS2_ERR_STATUS; + + SMB_VC_LOCK(vcp); + vcp->vc_flags &= ~(SMBV_ENCRYPT); + SMB_VC_UNLOCK(vcp); + + sp = &vcp->vc_sopt; + bzero(sp, sizeof (struct smb_sopt)); + error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + for (dp = smb_dialects; dp->d_id != -1; dp++) { + mb_put_uint8(mbp, SMB_DT_DIALECT); + smb_put_dstring(mbp, vcp, dp->d_name, SMB_CS_NONE); + } + smb_rq_bend(rqp); + + /* + * This request should not wait for + * connection state changes, etc. + */ + rqp->sr_flags |= SMBR_INTERNAL; + error = smb_rq_simple(rqp); + SMBSDEBUG("%d\n", error); + if (error) + goto bad; + + smb_rq_getreply(rqp, &mdp); + do { + error = md_get_uint8(mdp, &wc); + if (error) + break; + error = md_get_uint16le(mdp, &dindex); + if (error) + break; + error = EBADRPC; + if (dindex > SMB_DIALECT_MAX) { + SMBERROR( + "Don't know how to talk with server %s (%d)\n", + vcp->vc_srvname, dindex); + break; + } + dp = smb_dialects + dindex; + if (dindex < SMB_DIALECT_MAX) { + SMBERROR( + "Server %s negotiated old dialect (%s)\n", + vcp->vc_srvname, dp->d_name); + } + sp->sv_proto = dp->d_id; + SMBSDEBUG("Dialect %s (%d, %d)\n", dp->d_name, dindex, wc); + if (dp->d_id >= SMB_DIALECT_NTLM0_12) { + if (wc != 17) + break; + md_get_uint8(mdp, &sp->sv_sm); + md_get_uint16le(mdp, &sp->sv_maxmux); + md_get_uint16le(mdp, &sp->sv_maxvcs); + md_get_uint32le(mdp, &sp->sv_maxtx); + md_get_uint32le(mdp, &sp->sv_maxraw); + md_get_uint32le(mdp, &sp->sv_skey); + md_get_uint32le(mdp, &sp->sv_caps); + md_get_mem(mdp, (char *)stime, 8, MB_MSYSTEM); + md_get_uint16le(mdp, (u_int16_t *)&sp->sv_tz); + md_get_uint8(mdp, &sblen); + error = md_get_uint16le(mdp, &bc); + if (error) + break; + if (sp->sv_sm & SMB_SM_SIGS_REQUIRE) + SMBERROR("server configuration requires " + "packet signing, which we dont support: " + "sp->sv_sm %d\n", sp->sv_sm); + if (sp->sv_caps & SMB_CAP_UNICODE) { + SMB_VC_LOCK(vcp); + vcp->vc_flags |= SMBV_UNICODE; + SMB_VC_UNLOCK(vcp); + unicode = 1; + } + if (!(sp->sv_caps & SMB_CAP_STATUS32)) { + /* + * They don't do NT error codes. + * + * If we send requests with + * SMB_FLAGS2_ERR_STATUS set in + * Flags2, Windows 98, at least, + * appears to send replies with that + * bit set even though it sends back + * DOS error codes. (They probably + * just use the request header as + * a template for the reply header, + * and don't bother clearing that bit.) + * + * Therefore, we clear that bit in + * our vc_hflags2 field. + */ + vcp->vc_hflags2 &= ~SMB_FLAGS2_ERR_STATUS; + } + if (dp->d_id == SMB_DIALECT_NTLM0_12 && + sp->sv_maxtx < 4096 && + (sp->sv_caps & SMB_CAP_NT_SMBS) == 0) { + SMB_VC_LOCK(vcp); + vcp->vc_flags |= SMBV_WIN95; + SMB_VC_UNLOCK(vcp); + SMBSDEBUG("Win95 detected\n"); + } + + /* + * 3 cases here: + * + * 1) Extended security. + * Read bc bytes below for security blob. + * Note that we DON'T put the Caps flag in outtok. + * outtoklen = bc + * + * 2) No extended security, have challenge data and + * possibly a domain name (which might be zero + * bytes long, meaning "missing"). + * Copy challenge stuff to vcp->vc_ch (sblen bytes), + * then copy Cap flags and domain name (bc-sblen + * bytes) to outtok. + * outtoklen = bc-sblen+4, where the 4 is for the + * Caps flag. + * + * 3) No extended security, no challenge data, just + * possibly a domain name. + * Copy Capsflags and domain name (bc) to outtok. + * outtoklen = bc+4, where 4 is for the Caps flag + */ + + /* + * Sanity check: make sure the challenge length + * isn't bigger than the byte count. + */ + if (sblen > bc) { + error = EBADRPC; + break; + } + toklen = bc; + + if (sblen && sblen <= SMB_MAXCHALLENGELEN && + sp->sv_sm & SMB_SM_ENCRYPT) { + error = md_get_mem(mdp, + (char *)vcp->vc_challenge, + sblen, MB_MSYSTEM); + if (error) + break; + vcp->vc_chlen = sblen; + toklen -= sblen; + + SMB_VC_LOCK(vcp); + vcp->vc_flags |= SMBV_ENCRYPT; + SMB_VC_UNLOCK(vcp); + } + + /* + * For servers that don't support unicode + * there are 2 things we could do: + * 1) Pass the server Caps flags up to the + * user level so the logic up there will + * know whether the domain name is unicode + * (this is what I did). + * 2) Try to convert the non-unicode string + * to unicode. This doubles the length of + * the outtok buffer and would be guessing that + * the string was single-byte ascii, and that + * might be wrong. Why ask for trouble? + */ + + /* Warning: NetApp may omit the GUID */ + + if (!(sp->sv_caps & SMB_CAP_EXT_SECURITY)) { + /* + * No extended security. + * Stick domain name, if present, + * and caps in outtok. + */ + toklen = toklen + 4; /* space for Caps flags */ + vcp->vc_outtoklen = toklen; + vcp->vc_outtok = kmem_alloc(toklen, KM_SLEEP); + /* first store server capability bits */ + /*LINTED*/ + ASSERT(vcp->vc_outtok == + (caddr_t)(((u_int32_t *)vcp->vc_outtok))); + /*LINTED*/ + *(u_int32_t *)(vcp->vc_outtok) = sp->sv_caps; + + /* + * Then store the domain name if present; + * be sure to subtract 4 from the length + * for the Caps flag. + */ + if (toklen > 4) { + error = md_get_mem(mdp, + vcp->vc_outtok+4, toklen-4, + MB_MSYSTEM); + } + } else { + /* + * Extended security. + * Stick the rest of the buffer in outtok. + */ + vcp->vc_outtoklen = toklen; + vcp->vc_outtok = kmem_alloc(toklen, KM_SLEEP); + error = md_get_mem(mdp, vcp->vc_outtok, toklen, + MB_MSYSTEM); + } + break; + } + vcp->vc_hflags2 &= ~(SMB_FLAGS2_EXT_SEC|SMB_FLAGS2_DFS| + SMB_FLAGS2_ERR_STATUS|SMB_FLAGS2_UNICODE); + if (dp->d_id > SMB_DIALECT_CORE) { + md_get_uint16le(mdp, &tw); + sp->sv_sm = (uchar_t)tw; + md_get_uint16le(mdp, &tw); + sp->sv_maxtx = tw; + md_get_uint16le(mdp, &sp->sv_maxmux); + md_get_uint16le(mdp, &sp->sv_maxvcs); + md_get_uint16le(mdp, &tw); /* rawmode */ + md_get_uint32le(mdp, &sp->sv_skey); + if (wc == 13) { /* >= LANMAN1 */ + md_get_uint16(mdp, &tw); /* time */ + md_get_uint16(mdp, &tw1); /* date */ + md_get_uint16le(mdp, (u_int16_t *)&sp->sv_tz); + md_get_uint16le(mdp, &swlen); + if (swlen > SMB_MAXCHALLENGELEN) + break; + md_get_uint16(mdp, NULL); /* mbz */ + if (md_get_uint16le(mdp, &bc) != 0) + break; + if (bc < swlen) + break; + if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) { + error = md_get_mem(mdp, + (char *)vcp->vc_challenge, + swlen, MB_MSYSTEM); + if (error) + break; + vcp->vc_chlen = swlen; + + SMB_VC_LOCK(vcp); + vcp->vc_flags |= SMBV_ENCRYPT; + SMB_VC_UNLOCK(vcp); + } + } + } else { /* an old CORE protocol */ + vcp->vc_hflags2 &= ~SMB_FLAGS2_KNOWS_LONG_NAMES; + sp->sv_maxmux = 1; + } + error = 0; + /*LINTED*/ + } while (0); + if (error == 0) { + uint32_t x; + + /* + * Maximum outstanding requests. + */ + if (vcp->vc_maxmux < 1) + vcp->vc_maxmux = 1; + + /* + * Max VCs between server and client. + * We only use one. + */ + vcp->vc_maxvcs = sp->sv_maxvcs; + if (vcp->vc_maxvcs < 1) + vcp->vc_maxvcs = 1; + + /* + * Maximum transfer size. + * Sanity checks: + * + * Spec. says lower limit is 1024. OK. + * + * Let's be conservative about an upper limit here. + * Win2k uses 16644 (and others) so 32k should be a + * reasonable sanity limit for this value. + * + * Note that this limit does NOT affect READX/WRITEX + * with CAP_LARGE_xxx, which we nearly always use. + */ + vcp->vc_txmax = sp->sv_maxtx; + if (vcp->vc_txmax < 1024) + vcp->vc_txmax = 1024; + if (vcp->vc_txmax > 0x8000) + vcp->vc_txmax = 0x8000; + + /* + * Max read/write sizes, WITHOUT overhead. + * This is just the payload size, so we must + * leave room for the SMB headers, etc. + * + * With CAP_LARGE_xxx, always use 60k. + * Otherwise use the vc_txmax value, but + * reduced and rounded down. Tricky bit: + * + * Servers typically give us a value that's + * some nice "round" number, i.e 0x4000 plus + * some overhead, i.e. Win2k: 16644==0x4104 + * Subtract for the SMB header (32) and the + * SMB command word and byte vectors (34?), + * then round down to a 512 byte multiple. + */ + x = (vcp->vc_txmax - 68) & 0xFE00; + if (sp->sv_caps & SMB_CAP_LARGE_READX) + vcp->vc_rxmax = SMB_MAX_LARGE_RW_SIZE; + else + vcp->vc_rxmax = x; + if (sp->sv_caps & SMB_CAP_LARGE_WRITEX) + vcp->vc_wxmax = SMB_MAX_LARGE_RW_SIZE; + else + vcp->vc_wxmax = x; + + SMBSDEBUG("TZ = %d\n", sp->sv_tz); + SMBSDEBUG("CAPS = %x\n", sp->sv_caps); + + SMBSDEBUG("maxmux = %d\n", vcp->vc_maxmux); + SMBSDEBUG("maxvcs = %d\n", vcp->vc_maxvcs); + SMBSDEBUG("txmax = %d\n", vcp->vc_txmax); + SMBSDEBUG("rxmax = %d\n", vcp->vc_rxmax); + SMBSDEBUG("wxmax = %d\n", vcp->vc_wxmax); + } + + /* + * If the server supports Unicode, set up to use Unicode + * when talking to them. Othewise, use code page 437. + */ + if (unicode) + servercs = "ucs-2"; + else { + /* + * todo: if we can't determine the server's encoding, we + * need to try a best-guess here. + */ + servercs = "cp437"; + } +#if defined(NOICONVSUPPORT) || defined(lint) + /* + * REVISIT + */ + error = iconv_open(servercs, "utf-8", &servercshandle); + if (error != 0) + goto bad; + error = iconv_open("utf-8", servercs, &localcshandle); + if (error != 0) { + iconv_close(servercshandle); + goto bad; + } + if (vcp->vc_toserver) + iconv_close(vcp->vc_toserver); + if (vcp->vc_tolocal) + iconv_close(vcp->vc_tolocal); + vcp->vc_toserver = servercshandle; + vcp->vc_tolocal = localcshandle; +#endif + if (unicode) + vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE; +bad: + smb_rq_done(rqp); + return (error); +} + +static void +get_ascii_password(struct smb_vc *vcp, int upper, char *pbuf) +{ + const char *pw = smb_vc_getpass(vcp); + if (upper) + smb_toupper(pw, pbuf, SMB_MAXPASSWORDLEN); + else + strncpy(pbuf, pw, SMB_MAXPASSWORDLEN); + pbuf[SMB_MAXPASSWORDLEN] = '\0'; +} + +#ifdef APPLE +static void +get_unicode_password(struct smb_vc *vcp, char *pbuf) +{ + strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN); + pbuf[SMB_MAXPASSWORDLEN] = '\0'; +} +#endif + +/*ARGSUSED*/ +static uchar_t * +add_name_to_blob(uchar_t *blobnames, struct smb_vc *vcp, const uchar_t *name, + size_t namelen, int nametype, int uppercase) +{ + struct ntlmv2_namehdr namehdr; + char *namebuf; + u_int16_t *uninamebuf; + size_t uninamelen; + + if (name != NULL) { + uninamebuf = kmem_alloc(2 * namelen, KM_SLEEP); + if (uppercase) { + namebuf = kmem_alloc(namelen + 1, KM_SLEEP); + smb_toupper((const char *)name, namebuf, namelen); + namebuf[namelen] = '\0'; + uninamelen = smb_strtouni(uninamebuf, namebuf, namelen, + UCONV_IGNORE_NULL); + kmem_free(namebuf, namelen + 1); + } else { + uninamelen = smb_strtouni(uninamebuf, (char *)name, + namelen, UCONV_IGNORE_NULL); + } + } else { + uninamelen = 0; + uninamebuf = NULL; + } + namehdr.type = htoles(nametype); + namehdr.len = htoles(uninamelen); + bcopy(&namehdr, blobnames, sizeof (namehdr)); + blobnames += sizeof (namehdr); + if (uninamebuf != NULL) { + bcopy(uninamebuf, blobnames, uninamelen); + blobnames += uninamelen; + kmem_free(uninamebuf, namelen * 2); + } + return (blobnames); +} + +static uchar_t * +make_ntlmv2_blob(struct smb_vc *vcp, u_int64_t client_nonce, size_t *bloblen) +{ + uchar_t *blob; + size_t blobsize; + size_t domainlen, srvlen; + struct ntlmv2_blobhdr *blobhdr; + struct timespec now; + u_int64_t timestamp; + uchar_t *blobnames; + ptrdiff_t diff; + + /* + * XXX - the information at + * + * http://davenport.sourceforge.net/ntlm.html#theNtlmv2Response + * + * says that the "target information" comes from the Type 2 message, + * but, as we're not doing NTLMSSP, we don't have that. + * + * Should we use the names from the NegProt response? Can we trust + * the NegProt response? (I've seen captures where the primary + * domain name has an extra byte in front of it.) + * + * For now, we don't trust it - we use vcp->vc_domain and + * vcp->vc_srvname, instead. We upper-case them and convert + * them to Unicode, as that's what's supposed to be in the blob. + */ + domainlen = strlen(vcp->vc_domain); + srvlen = strlen(vcp->vc_srvname); + blobsize = sizeof (struct ntlmv2_blobhdr) + + 3*sizeof (struct ntlmv2_namehdr) + 4 + 2*domainlen + 2*srvlen; + blob = kmem_zalloc(blobsize, KM_SLEEP); + /*LINTED*/ + ASSERT(blob == (uchar_t *)((struct ntlmv2_blobhdr *)blob)); + /*LINTED*/ + blobhdr = (struct ntlmv2_blobhdr *)blob; + blobhdr->header = htolel(0x00000101); + gethrestime(&now); + smb_time_local2NT(&now, 0, ×tamp); + blobhdr->timestamp = htoleq(timestamp); + blobhdr->client_nonce = client_nonce; + blobnames = blob + sizeof (struct ntlmv2_blobhdr); + blobnames = add_name_to_blob(blobnames, vcp, (uchar_t *)vcp->vc_domain, + domainlen, NAMETYPE_DOMAIN_NB, 1); + blobnames = add_name_to_blob(blobnames, vcp, (uchar_t *)vcp->vc_srvname, + srvlen, NAMETYPE_MACHINE_NB, 1); + blobnames = add_name_to_blob(blobnames, vcp, NULL, 0, NAMETYPE_EOL, 0); + diff = (intptr_t)blobnames - (intptr_t)blob; + ASSERT(diff == (ptrdiff_t)((size_t)diff)); + *bloblen = (size_t)diff; + return (blob); +} + +/* + * See radar 4134676. This define helps us avoid how a certain old server + * grants limited Guest access when we try NTLMv2, but works fine with NTLM. + * The fingerprint we are looking for here is DOS error codes and no-Unicode. + * Note XP grants Guest access but uses Unicode and NT error codes. + */ +#define smb_antique(rqp) (!((rqp)->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) && \ + !((rqp)->sr_rpflags2 & SMB_FLAGS2_UNICODE)) + +/* + * When not doing Kerberos, we can try, in order: + * + * NTLMv2 + * NTLM with the ASCII password not upper-cased + * NTLM with the ASCII password upper-cased + * + * if the server supports encrypted passwords, or + * + * plain-text with the ASCII password not upper-cased + * plain-text with the ASCII password upper-cased + * + * if it doesn't. + */ +#define STATE_NTLMV2 0 +#define STATE_NOUCPW 1 +#define STATE_UCPW 2 + +int +smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred) +{ + struct smb_rq *rqp; + struct mbchain *mbp; + struct mdchain *mdp; + u_int8_t wc; + int minauth; + smb_uniptr unipp = NULL, ntencpass = NULL; + char *pp = NULL, *up = NULL, *ucup = NULL, *ucdp = NULL; + char *pbuf = NULL; + char *encpass = NULL; + int error = 0; + size_t plen = 0, uniplen = 0, uniplen2 = 0, tmplen; + size_t ucup_sl = 0, ucdp_sl = 0; + int state; + size_t ntlmv2_bloblen; + uchar_t *ntlmv2_blob; + u_int64_t client_nonce; + u_int32_t caps; + u_int16_t bl; /* BLOB length */ + u_int16_t saveflags2 = vcp->vc_hflags2; + void * savetoserver = vcp->vc_toserver; + u_int16_t action; + int declinedguest = 0; + static const char NativeOS[] = "Solaris"; + static const char LanMan[] = "NETSMB"; + /* + * Most of the "capability" bits we offer should be copied + * from those offered by the server, with a mask applied. + * This is the mask of capabilies copied from the server. + * Some others get special handling below. + */ + static const uint32_t caps_mask = + SMB_CAP_UNICODE | + SMB_CAP_LARGE_FILES | + SMB_CAP_NT_SMBS | + SMB_CAP_STATUS32 | + SMB_CAP_LARGE_READX | + SMB_CAP_LARGE_WRITEX; + + caps = vcp->vc_sopt.sv_caps & caps_mask; + + /* No unicode unless server supports and encryption on */ + if (!((vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) && + (vcp->vc_flags & SMBV_UNICODE))) { + vcp->vc_hflags2 &= 0xffff - SMB_FLAGS2_UNICODE; + vcp->vc_toserver = 0; + } + + minauth = vcp->vc_vopt & SMBVOPT_MINAUTH; + if (vcp->vc_intok) { + if (vcp->vc_intoklen > 65536 || + !(vcp->vc_hflags2 & SMB_FLAGS2_EXT_SEC) || + SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) { + error = EINVAL; + goto ssn_exit; + } + vcp->vc_smbuid = 0; + } + + /* + * Try only plain text passwords. + */ + if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { + state = STATE_NTLMV2; /* try NTLMv2 first */ + } else { + state = STATE_NOUCPW; /* try plain-text mixed-case first */ + } +again: + + if (!vcp->vc_intok) + vcp->vc_smbuid = SMB_UID_UNKNOWN; + + if (!vcp->vc_intok) { + /* + * We're not doing extended security, which, for + * now, means we're not doing Kerberos. + * Fail if the minimum authentication level is + * Kerberos. + */ + if (minauth >= SMBVOPT_MINAUTH_KERBEROS) { + error = EAUTH; + goto ssn_exit; + } + if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { + /* + * Server wants encrypted passwords. + */ + if (state > STATE_NTLMV2) { + /* + * We tried NTLMv2 in STATE_NTLMV2. + * Shall we allow fallback? (to NTLM) + */ + if (minauth >= SMBVOPT_MINAUTH_NTLMV2) { + error = EAUTH; + goto ssn_exit; + } + } + if (state > STATE_NOUCPW) { + /* + * We tried NTLM in STATE_NOUCPW. + * No need to try it again. + */ + error = EAUTH; + goto ssn_exit; + } + } else { + /* + * Plain-text passwords. + * Fail if the minimum authentication level is + * LM or better. + */ + if (minauth > SMBVOPT_MINAUTH_NTLM) { + error = EAUTH; + goto ssn_exit; + } + } + } + + error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, + scred, &rqp); + if (error) + goto ssn_exit; + + /* + * Domain name must be upper-case, as that's what's used + * when computing LMv2 and NTLMv2 responses - and, for NTLMv2, + * the domain name in the request has to be upper-cased as well. + * (That appears not to be the case for the user name. Go + * figure.) + * + * don't need to uppercase domain string. It's already uppercase UTF-8. + */ + + ucdp_sl = strlen(vcp->vc_domain); + ucdp = kmem_zalloc(ucdp_sl + 1, KM_SLEEP); + memcpy(ucdp, vcp->vc_domain, ucdp_sl + 1); + + if (vcp->vc_intok) { + caps |= SMB_CAP_EXT_SECURITY; + } else if (!(vcp->vc_sopt.sv_sm & SMB_SM_USER)) { + /* + * In the share security mode password will be used + * only in the tree authentication + */ + pp = ""; + plen = 1; + unipp = &smb_unieol; + uniplen = sizeof (smb_unieol); + } else { + pbuf = kmem_alloc(SMB_MAXPASSWORDLEN + 1, KM_SLEEP); + if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { + if (state == STATE_NTLMV2) { + /* + * Compute the LMv2 and NTLMv2 responses, + * derived from the challenge, the user name, + * the domain/workgroup into which we're + * logging, and the Unicode password. + */ + + /* + * Construct the client nonce by getting + * a bunch of random data. + */ + (void) random_get_pseudo_bytes((void *) + &client_nonce, sizeof (client_nonce)); + + /* + * Convert the user name to upper-case, as + * that's what's used when computing LMv2 + * and NTLMv2 responses. + */ + ucup_sl = strlen(vcp->vc_username); + ucup = kmem_alloc(ucup_sl + 1, KM_SLEEP); + smb_toupper((const char *)vcp->vc_username, + ucup, ucup_sl); + ucup[ucup_sl] = '\0'; + + /* + * Compute the LMv2 response, derived + * from the server challenge, the + * user name, the domain/workgroup + * into which we're logging, the + * client nonce, and the NT hash. + */ + smb_ntlmv2response(vcp->vc_nthash, + (uchar_t *)ucup, (uchar_t *)ucdp, + vcp->vc_challenge, + (uchar_t *)&client_nonce, 8, + (uchar_t **)&encpass, &plen); + pp = encpass; + + /* + * Construct the blob. + */ + ntlmv2_blob = make_ntlmv2_blob(vcp, + client_nonce, &ntlmv2_bloblen); + + /* + * Compute the NTLMv2 response, derived + * from the server challenge, the + * user name, the domain/workgroup + * into which we're logging, the + * blob, and the NT hash. + */ + smb_ntlmv2response(vcp->vc_nthash, + (uchar_t *)ucup, (uchar_t *)ucdp, + vcp->vc_challenge, + ntlmv2_blob, ntlmv2_bloblen, + (uchar_t **)&ntencpass, &uniplen); + uniplen2 = uniplen; + unipp = ntencpass; + tmplen = plen; + + kmem_free(ucup, ucup_sl + 1); + kmem_free((char *)ntlmv2_blob, + sizeof (struct ntlmv2_blobhdr) + + 3 * sizeof (struct ntlmv2_namehdr) + + 4 + + 2 * strlen(vcp->vc_domain) + + 2 * strlen(vcp->vc_srvname)); + } else { + plen = 24; + encpass = kmem_zalloc(plen, KM_SLEEP); + /* + * Compute the LM response, derived + * from the challenge and the ASCII + * password. + */ + if (minauth < SMBVOPT_MINAUTH_NTLM) { + smb_lmresponse(vcp->vc_lmhash, + vcp->vc_challenge, + (uchar_t *)encpass); + } + pp = encpass; + + /* + * Compute the NTLM response, derived from + * the challenge and the NT hash. + */ + uniplen = 24; + uniplen2 = uniplen; + ntencpass = kmem_alloc(uniplen, KM_SLEEP); + smb_lmresponse(vcp->vc_nthash, + vcp->vc_challenge, + (uchar_t *)ntencpass); + unipp = ntencpass; + } + } else { + /* + * We try w/o uppercasing first so Samba mixed case + * passwords work. If that fails, we come back and + * try uppercasing to satisfy OS/2 and Windows for + * Workgroups. + */ + get_ascii_password(vcp, (state == STATE_UCPW), pbuf); + plen = strlen(pbuf) + 1; + pp = pbuf; + uniplen = plen * 2; + uniplen2 = uniplen; + ntencpass = kmem_alloc(uniplen, KM_SLEEP); + (void) smb_strtouni(ntencpass, smb_vc_getpass(vcp), + 0, 0); + plen--; + /* + * The uniplen is zeroed because Samba cannot deal + * with this 2nd cleartext password. This Samba + * "bug" is actually a workaround for problems in + * Microsoft clients. + */ + uniplen = 0; /* -= 2 */ + unipp = ntencpass; + } + } + smb_rq_wstart(rqp); + mbp = &rqp->sr_rq; + up = vcp->vc_username; + /* + * If userid is null we are attempting anonymous browse login + * so passwords must be zero length. + */ + if (*up == '\0') { + plen = uniplen = 0; + } + mb_put_uint8(mbp, 0xff); + mb_put_uint8(mbp, 0); + mb_put_uint16le(mbp, 0); + mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx); + mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux); + mb_put_uint16le(mbp, vcp->vc_number); + mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey); + if ((SMB_DIALECT(vcp)) < SMB_DIALECT_NTLM0_12) { + mb_put_uint16le(mbp, plen); + mb_put_uint32le(mbp, 0); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_mem(mbp, pp, plen, MB_MSYSTEM); + smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* user */ + smb_put_dstring(mbp, vcp, ucdp, SMB_CS_NONE); /* domain */ + } else { + if (vcp->vc_intok) { + mb_put_uint16le(mbp, vcp->vc_intoklen); + mb_put_uint32le(mbp, 0); /* reserved */ + mb_put_uint32le(mbp, caps); /* my caps */ + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_mem(mbp, vcp->vc_intok, vcp->vc_intoklen, + MB_MSYSTEM); /* security blob */ + } else { + mb_put_uint16le(mbp, plen); + mb_put_uint16le(mbp, uniplen); + mb_put_uint32le(mbp, 0); /* reserved */ + mb_put_uint32le(mbp, caps); /* my caps */ + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_mem(mbp, pp, plen, MB_MSYSTEM); /* password */ + mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM); + smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* user */ + smb_put_dstring(mbp, vcp, ucdp, SMB_CS_NONE); /* dom */ + } + } + smb_put_dstring(mbp, vcp, NativeOS, SMB_CS_NONE); /* OS */ + smb_put_dstring(mbp, vcp, LanMan, SMB_CS_NONE); /* LAN Mgr */ + smb_rq_bend(rqp); + if (ntencpass) { + kmem_free(ntencpass, uniplen2); + ntencpass = NULL; + } + if (encpass) { + kmem_free(encpass, 24); + encpass = NULL; + } + if (ucdp) { + kmem_free(ucdp, ucdp_sl + 1); + ucdp = NULL; + } + + /* + * This request should not wait for + * connection state changes, etc. + */ + rqp->sr_flags |= SMBR_INTERNAL; + error = smb_rq_simple_timed(rqp, SMBSSNSETUPTIMO); + SMBSDEBUG("%d\n", error); + if (error) { + if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnoaccess) + error = EAUTH; + if (!(rqp->sr_errclass == ERRDOS && + rqp->sr_serror == ERRmoredata)) + goto bad; + } + vcp->vc_smbuid = rqp->sr_rpuid; + smb_rq_getreply(rqp, &mdp); + do { + error = md_get_uint8(mdp, &wc); + if (error) + break; + error = EBADRPC; + if (vcp->vc_intok) { + if (wc != 4) + break; + } else if (wc != 3) + break; + md_get_uint8(mdp, NULL); /* secondary cmd */ + md_get_uint8(mdp, NULL); /* mbz */ + md_get_uint16le(mdp, NULL); /* andxoffset */ + md_get_uint16le(mdp, &action); /* action */ + if (vcp->vc_intok) + md_get_uint16le(mdp, &bl); /* ext security */ + md_get_uint16le(mdp, NULL); /* byte count */ + if (vcp->vc_intok) { + vcp->vc_outtoklen = bl; + vcp->vc_outtok = kmem_alloc(bl, KM_SLEEP); + error = md_get_mem(mdp, vcp->vc_outtok, bl, MB_MSYSTEM); + if (error) + break; + } + /* server OS, LANMGR, & Domain here */ + error = 0; + /*LINTED*/ + } while (0); +bad: + if (encpass) { + kmem_free(encpass, tmplen); + encpass = NULL; + } + if (pbuf) { + kmem_free(pbuf, SMB_MAXPASSWORDLEN + 1); + pbuf = NULL; + } + if (vcp->vc_sopt.sv_sm & SMB_SM_USER && !vcp->vc_intok && + (error || (*up != '\0' && action & SMB_ACT_GUEST && + state == STATE_NTLMV2 && smb_antique(rqp)))) { + /* + * We're doing user-level authentication (so we are actually + * sending authentication stuff over the wire), and we're + * not doing extended security, and the stuff we tried + * failed (or we we're trying to login a real user but + * got granted guest access instead.) + */ + if (!error) + declinedguest = 1; + /* + * Should we try the next type of authentication? + */ + if (state < STATE_UCPW) { + /* + * Yes, we still have more to try. + */ + state++; + smb_rq_done(rqp); + goto again; + } + } + smb_rq_done(rqp); + +ssn_exit: + if (error && declinedguest) + SMBERROR("we declined ntlmv2 guest access. errno will be %d\n", + error); + /* Restore things we changed and return */ + vcp->vc_hflags2 = saveflags2; + vcp->vc_toserver = savetoserver; + return (error); +} + +int +smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred) +{ + struct smb_rq *rqp; + struct mbchain *mbp; + int error; + + if (vcp->vc_smbuid == SMB_UID_UNKNOWN) + return (0); + + error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp); + if (error) + return (error); + mbp = &rqp->sr_rq; + smb_rq_wstart(rqp); + mb_put_uint8(mbp, 0xff); + mb_put_uint8(mbp, 0); + mb_put_uint16le(mbp, 0); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + smb_rq_bend(rqp); + /* + * Run this with a relatively short timeout. + * We don't really care about the result, + * as we're just trying to play nice and + * "say goodbye" before we hangup. + * XXX: Add SMBLOGOFFTIMO somewhere? + */ + error = smb_rq_simple_timed(rqp, 5); + SMBSDEBUG("%d\n", error); + smb_rq_done(rqp); + return (error); +} + +static char smb_any_share[] = "?????"; + +static char * +smb_share_typename(int stype) +{ + char *pp; + + switch (stype) { + case STYPE_DISKTREE: + pp = "A:"; + break; + case STYPE_PRINTQ: + pp = smb_any_share; /* can't use LPT: here... */ + break; + case STYPE_DEVICE: + pp = "COMM"; + break; + case STYPE_IPC: + pp = "IPC"; + break; + default: + pp = smb_any_share; + break; + } + return (pp); +} + +int +smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) +{ + struct smb_vc *vcp; + struct smb_rq rq, *rqp = &rq; + struct mbchain *mbp; + char *pp, *pbuf, *encpass; + const char *pw; + uchar_t hash[SMB_PWH_MAX]; + int error, plen, caseopt; + int upper = 0; + +again: + vcp = SSTOVC(ssp); + + /* + * Make this a "VC-level" request, so it will have + * rqp->sr_share == NULL, and smb_iod_sendrq() + * will send it with TID = SMB_TID_UNKNOWN + * + * This also serves to bypass the wait for + * share state changes, which this call is + * trying to carry out. + * + * No longer need to set ssp->ss_tid + * here, but it's harmless enough. + */ + ssp->ss_tid = SMB_TID_UNKNOWN; + error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_CONNECT_ANDX, + scred, &rqp); + if (error) + return (error); + caseopt = SMB_CS_NONE; + if (vcp->vc_sopt.sv_sm & SMB_SM_USER) { + plen = 1; + pp = ""; + pbuf = NULL; + encpass = NULL; + } else { + pbuf = kmem_alloc(SMB_MAXPASSWORDLEN + 1, KM_SLEEP); + encpass = kmem_alloc(24, KM_SLEEP); + pw = smb_share_getpass(ssp); + /* + * We try w/o uppercasing first so Samba mixed case + * passwords work. If that fails we come back and try + * uppercasing to satisfy OS/2 and Windows for Workgroups. + */ + if (upper++) { + smb_toupper(pw, pbuf, SMB_MAXPASSWORDLEN); + smb_oldlm_hash(pw, hash); + } else { + strncpy(pbuf, pw, SMB_MAXPASSWORDLEN); + smb_ntlmv1hash(pw, hash); + } + pbuf[SMB_MAXPASSWORDLEN] = '\0'; + +#ifdef NOICONVSUPPORT + /* + * We need to convert here to the server codeset. + * Initially we will send the same stuff and see what happens + * witout the conversion. REVISIT. + */ + iconv_convstr(vcp->vc_toserver, pbuf, pbuf, SMB_MAXPASSWORDLEN); +#endif + if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { + plen = 24; + smb_lmresponse(hash, + vcp->vc_challenge, + (uchar_t *)encpass); + pp = encpass; + } else { + plen = strlen(pbuf) + 1; + pp = pbuf; + } + } + mbp = &rqp->sr_rq; + smb_rq_wstart(rqp); + mb_put_uint8(mbp, 0xff); + mb_put_uint8(mbp, 0); + mb_put_uint16le(mbp, 0); + mb_put_uint16le(mbp, 0); /* Flags */ + mb_put_uint16le(mbp, plen); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + error = mb_put_mem(mbp, pp, plen, MB_MSYSTEM); + if (error) { + SMBSDEBUG("error %d from mb_put_mem for pp\n", error); + goto bad; + } + smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt, NULL); + pp = vcp->vc_srvname; + error = smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt, NULL); + if (error) { + SMBSDEBUG("error %d from smb_put_dmem for srvname\n", error); + goto bad; + } + smb_put_dmem(mbp, vcp, "\\", 1, caseopt, NULL); + pp = ssp->ss_name; + error = smb_put_dstring(mbp, vcp, pp, caseopt); + if (error) { + SMBSDEBUG("error %d from smb_put_dstring for ss_name\n", error); + goto bad; + } + /* The type name is always ASCII */ + pp = smb_share_typename(ssp->ss_type); + error = mb_put_mem(mbp, pp, strlen(pp) + 1, MB_MSYSTEM); + if (error) { + SMBSDEBUG("error %d from mb_put_mem for ss_type\n", error); + goto bad; + } + smb_rq_bend(rqp); + /* + * Don't want to risk missing a successful + * tree connect response. + */ + rqp->sr_flags |= SMBR_NOINTR_RECV; + error = smb_rq_simple(rqp); + SMBSDEBUG("%d\n", error); + if (error) + goto bad; + + /* Success! */ + SMB_SS_LOCK(ssp); + ssp->ss_tid = rqp->sr_rptid; + ssp->ss_vcgenid = vcp->vc_genid; + ssp->ss_flags |= SMBS_CONNECTED; + SMB_SS_UNLOCK(ssp); + +bad: + if (encpass) + kmem_free(encpass, 24); + if (pbuf) + kmem_free(pbuf, SMB_MAXPASSWORDLEN + 1); + smb_rq_done(rqp); + if (error && upper == 1) + goto again; + return (error); +} + +int +smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred) +{ + struct smb_vc *vcp; + struct smb_rq *rqp; + struct mbchain *mbp; + int error; + + if (ssp->ss_tid == SMB_TID_UNKNOWN) + return (0); + + /* + * Build this as a "VC-level" request, so it will + * avoid testing the _GONE flag on the share, + * which has already been set at this point. + * Add the share pointer "by hand" below, so + * smb_iod_sendrq will plug in the TID. + */ + vcp = SSTOVC(ssp); + error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_DISCONNECT, scred, &rqp); + if (error) + return (error); + rqp->sr_share = ssp; /* by hand */ + mbp = &rqp->sr_rq; +#ifdef lint + mbp = mbp; +#endif + smb_rq_wstart(rqp); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + smb_rq_bend(rqp); + + /* + * Run this with a relatively short timeout. (5 sec.) + * We don't really care about the result here, but we + * do need to make sure we send this out, or we could + * "leak" active tree IDs on interrupt or timeout. + * The NOINTR_SEND flag makes this request immune to + * interrupt or timeout until the send is done. + */ + rqp->sr_flags |= SMBR_NOINTR_SEND; + error = smb_rq_simple_timed(rqp, 5); + SMBSDEBUG("%d\n", error); + smb_rq_done(rqp); + ssp->ss_tid = SMB_TID_UNKNOWN; + return (error); +} + +static int +smb_smb_readx(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, + uio_t *uiop, struct smb_cred *scred, int timo) +{ + struct smb_vc *vcp = SSTOVC(ssp); + struct smb_rq *rqp; + struct mbchain *mbp; + struct mdchain *mdp; + u_int8_t wc; + int error; + u_int16_t residhi, residlo, off, doff; + u_int32_t resid; + + if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) == 0) { + /* Fall back to the old cmd. */ + return (smb_smb_read(ssp, fid, len, rresid, uiop, + scred, timo)); + } + if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0) { + /* Have ReadX but not large files? */ + if ((uiop->uio_loffset + *len) > UINT32_MAX) + return (EFBIG); + } + *len = min(*len, vcp->vc_rxmax); + + error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_uint8(mbp, 0xff); /* no secondary command */ + mb_put_uint8(mbp, 0); /* MBZ */ + mb_put_uint16le(mbp, 0); /* offset to secondary */ + mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM); + mb_put_uint32le(mbp, (u_int32_t)(uiop->uio_offset)); + mb_put_uint16le(mbp, (u_int16_t)*len); /* MaxCount */ + mb_put_uint16le(mbp, (u_int16_t)*len); /* MinCount */ + /* (only indicates blocking) */ + mb_put_uint32le(mbp, (unsigned)*len >> 16); /* MaxCountHigh */ + mb_put_uint16le(mbp, (u_int16_t)*len); /* Remaining ("obsolete") */ + mb_put_uint32le(mbp, (u_int32_t)((uiop->uio_loffset) >> 32)); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + smb_rq_bend(rqp); + do { + if (timo == 0) + timo = smb_timo_read; + error = smb_rq_simple_timed(rqp, timo); + if (error) + break; + smb_rq_getreply(rqp, &mdp); + off = SMB_HDRLEN; + md_get_uint8(mdp, &wc); + off++; + if (wc != 12) { + error = EBADRPC; + break; + } + md_get_uint8(mdp, NULL); + off++; + md_get_uint8(mdp, NULL); + off++; + md_get_uint16le(mdp, NULL); + off += 2; + md_get_uint16le(mdp, NULL); + off += 2; + md_get_uint16le(mdp, NULL); /* data compaction mode */ + off += 2; + md_get_uint16le(mdp, NULL); + off += 2; + md_get_uint16le(mdp, &residlo); + off += 2; + md_get_uint16le(mdp, &doff); /* data offset */ + off += 2; + md_get_uint16le(mdp, &residhi); + off += 2; + resid = (residhi << 16) | residlo; + md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); + off += 4*2; + md_get_uint16le(mdp, NULL); /* ByteCount */ + off += 2; + if (doff > off) /* pad byte(s)? */ + md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM); + if (resid == 0) { + *rresid = resid; + break; + } + error = md_get_uio(mdp, uiop, resid); + if (error) + break; + *rresid = resid; + /*LINTED*/ + } while (0); + smb_rq_done(rqp); + return (error); +} + +static int +smb_smb_writex(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, + uio_t *uiop, struct smb_cred *scred, int timo) +{ + struct smb_vc *vcp = SSTOVC(ssp); + struct smb_rq *rqp; + struct mbchain *mbp; + struct mdchain *mdp; + int error; + u_int8_t wc; + u_int16_t resid; + + if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) == 0) { + /* Fall back to the old cmd. */ + return (smb_smb_write(ssp, fid, len, rresid, uiop, + scred, timo)); + } + if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0) { + /* Have WriteX but not large files? */ + if ((uiop->uio_loffset + *len) > UINT32_MAX) + return (EFBIG); + } + *len = min(*len, vcp->vc_wxmax); + + error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_uint8(mbp, 0xff); /* no secondary command */ + mb_put_uint8(mbp, 0); /* MBZ */ + mb_put_uint16le(mbp, 0); /* offset to secondary */ + mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM); + mb_put_uint32le(mbp, (u_int32_t)(uiop->uio_offset)); + mb_put_uint32le(mbp, 0); /* MBZ (timeout) */ + mb_put_uint16le(mbp, 0); /* !write-thru */ + mb_put_uint16le(mbp, 0); + mb_put_uint16le(mbp, (u_int16_t)((unsigned)*len >> 16)); + mb_put_uint16le(mbp, (u_int16_t)*len); + mb_put_uint16le(mbp, 64); /* data offset from header start */ + mb_put_uint32le(mbp, (u_int32_t)((uiop->uio_loffset) >> 32)); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + do { + mb_put_uint8(mbp, 0xee); /* mimic xp pad byte! */ + error = mb_put_uio(mbp, uiop, *len); + if (error) + break; + smb_rq_bend(rqp); + if (timo == 0) + timo = smb_timo_write; + error = smb_rq_simple_timed(rqp, timo); + if (error) + break; + smb_rq_getreply(rqp, &mdp); + md_get_uint8(mdp, &wc); + if (wc != 6) { + error = EBADRPC; + break; + } + md_get_uint8(mdp, NULL); + md_get_uint8(mdp, NULL); + md_get_uint16le(mdp, NULL); + md_get_uint16le(mdp, &resid); /* actually is # written */ + *rresid = resid; + /* + * if LARGE_WRITEX then there's one more bit of # written + */ + if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)) { + md_get_uint16le(mdp, NULL); + md_get_uint16le(mdp, &resid); + *rresid |= (int)(resid & 1) << 16; + } + /*LINTED*/ + } while (0); + + smb_rq_done(rqp); + return (error); +} + +static int +smb_smb_read(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, + uio_t *uiop, struct smb_cred *scred, int timo) +{ + struct smb_rq *rqp; + struct mbchain *mbp; + struct mdchain *mdp; + u_int16_t resid, bc; + u_int8_t wc; + int error, rlen; + + /* This cmd is limited to 32-bit offsets. */ + if ((uiop->uio_loffset + *len) > UINT32_MAX) + return (EFBIG); + *len = rlen = min(*len, SSTOVC(ssp)->vc_rxmax); + + error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM); + mb_put_uint16le(mbp, (u_int16_t)rlen); + mb_put_uint32le(mbp, (u_int32_t)uiop->uio_offset); + mb_put_uint16le(mbp, (u_int16_t)min(uiop->uio_resid, 0xffff)); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + smb_rq_bend(rqp); + do { + if (timo == 0) + timo = smb_timo_read; + error = smb_rq_simple_timed(rqp, timo); + if (error) + break; + smb_rq_getreply(rqp, &mdp); + md_get_uint8(mdp, &wc); + if (wc != 5) { + error = EBADRPC; + break; + } + md_get_uint16le(mdp, &resid); + md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); + md_get_uint16le(mdp, &bc); + md_get_uint8(mdp, NULL); /* ignore buffer type */ + md_get_uint16le(mdp, &resid); + if (resid == 0) { + *rresid = resid; + break; + } + error = md_get_uio(mdp, uiop, resid); + if (error) + break; + *rresid = resid; + /*LINTED*/ + } while (0); + smb_rq_done(rqp); + return (error); +} + +static int +smb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, + uio_t *uiop, struct smb_cred *scred, int timo) +{ + struct smb_rq *rqp; + struct mbchain *mbp; + struct mdchain *mdp; + u_int16_t resid; + u_int8_t wc; + int error; + + /* This cmd is limited to 32-bit offsets. */ + if ((uiop->uio_loffset + *len) > UINT32_MAX) + return (EFBIG); + *len = resid = min(*len, SSTOVC(ssp)->vc_wxmax); + + error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM); + mb_put_uint16le(mbp, resid); + mb_put_uint32le(mbp, (u_int32_t)uiop->uio_offset); + mb_put_uint16le(mbp, (u_int16_t)min(uiop->uio_resid, 0xffff)); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint8(mbp, SMB_DT_DATA); + mb_put_uint16le(mbp, resid); + do { + error = mb_put_uio(mbp, uiop, resid); + if (error) + break; + smb_rq_bend(rqp); + if (timo == 0) + timo = smb_timo_write; + error = smb_rq_simple_timed(rqp, timo); + if (error) + break; + smb_rq_getreply(rqp, &mdp); + md_get_uint8(mdp, &wc); + if (wc != 1) { + error = EBADRPC; + break; + } + md_get_uint16le(mdp, &resid); + *rresid = resid; + /*LINTED*/ + } while (0); + smb_rq_done(rqp); + return (error); +} + +/* + * Common function for read/write with UIO. + * Called by netsmb smb_usr_rw, + * smbfs_readvnode, smbfs_writevnode + */ +int +smb_rwuio(struct smb_share *ssp, u_int16_t fid, uio_rw_t rw, + uio_t *uiop, struct smb_cred *scred, int timo) +{ + ssize_t old_resid, tsize; + offset_t old_offset; + int len, resid; + int error = 0; + + old_offset = uiop->uio_loffset; + old_resid = tsize = uiop->uio_resid; + + while (tsize > 0) { + /* Lint: tsize may be 64-bits */ + len = SMB_MAX_LARGE_RW_SIZE; + if (len > tsize) + len = (int)tsize; + + if (rw == UIO_READ) + error = smb_smb_readx(ssp, fid, &len, &resid, uiop, + scred, timo); + else + error = smb_smb_writex(ssp, fid, &len, &resid, uiop, + scred, timo); + if (error) + break; + + if (resid < len) { + error = EIO; + break; + } + + tsize -= resid; + timo = 0; /* only first write is special */ + } + + if (error) { + /* + * Errors can happen in copyin/copyout, the rpc, etc. so + * they imply resid is unreliable. The only safe thing is + * to pretend zero bytes made it. We needn't restore the + * iovs because callers don't depend on them in error + * paths - uio_resid and uio_offset are what matter. + */ + uiop->uio_loffset = old_offset; + uiop->uio_resid = old_resid; + } + + return (error); +} + + +static u_int32_t smbechoes = 0; + +int +smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo) +{ + struct smb_rq *rqp; + struct mbchain *mbp; + int error; + + error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp); + if (error) + return (error); + mbp = &rqp->sr_rq; + smb_rq_wstart(rqp); + mb_put_uint16le(mbp, 1); /* echo count */ + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes)); + smb_rq_bend(rqp); + /* + * Note: the IOD calls this, so + * this request must not wait for + * connection state changes, etc. + */ + rqp->sr_flags |= SMBR_INTERNAL; + error = smb_rq_simple_timed(rqp, timo); + SMBSDEBUG("%d\n", error); + smb_rq_done(rqp); + return (error); +} + +#ifdef APPLE +int +smb_smb_checkdir(struct smb_share *ssp, void *dnp, char *name, + int nmlen, struct smb_cred *scred) +{ + struct smb_rq *rqp; + struct mbchain *mbp; + int error; + + error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CHECK_DIRECTORY, scred, &rqp); + if (error) + return (error); + + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint8(mbp, SMB_DT_ASCII); + /* + * All we need to do is marshall the path: "\\" + * (the root of the share) into this request. + * We essentially in-line smbfs_fullpath() here, + * except no mb_put_padbyte (already aligned). + */ + smb_put_dstring(mbp, SSTOVC(ssp), "\\", SMB_CS_NONE); + smb_rq_bend(rqp); + + error = smb_rq_simple(rqp); + SMBSDEBUG("%d\n", error); + smb_rq_done(rqp); + + return (error); +} +#endif /* APPLE */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2000-2001, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_subr.h,v 1.13 2004/09/14 22:59:08 lindak Exp $ + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _NETSMB_SMB_SUBR_H_ +#define _NETSMB_SMB_SUBR_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/cmn_err.h> +#include <sys/lock.h> +#include <sys/note.h> + +/* Helper function for SMBERROR */ +/*PRINTFLIKE3*/ +extern void smb_errmsg(int, const char *, const char *, ...) + __KPRINTFLIKE(3); +void m_dumpm(mblk_t *m); + +/* + * Let's use C99 standard variadic macros! + * Also the C99 __func__ (function name) feature. + */ +#define SMBERROR(...) \ + smb_errmsg(CE_NOTE, __func__, __VA_ARGS__) +#define SMBPANIC(...) \ + smb_errmsg(CE_PANIC, __func__, __VA_ARGS__) +#define SMBSDEBUG(...) \ + smb_errmsg(CE_CONT, __func__, __VA_ARGS__) +#define SMBIODEBUG(...) \ + smb_errmsg(CE_CONT, __func__, __VA_ARGS__) +#define NBDEBUG(...) \ + smb_errmsg(CE_CONT, __func__, __VA_ARGS__) + +#if defined(DEBUG) || defined(lint) + +#define DEBUG_ENTER(str) debug_enter(str) + +#else /* DEBUG or lint */ + +#define DEBUG_ENTER(str) ((void)0) + +#endif /* DEBUG or lint */ + +#define SMB_SIGMASK \ + (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGKILL)| \ + sigmask(SIGHUP)|sigmask(SIGQUIT)) + +#define SMB_STRFREE(p) do { \ + if (p) \ + smb_strfree(p); \ + _NOTE(CONSTCOND) \ +} while (0) + +typedef uint16_t smb_unichar; +typedef smb_unichar *smb_uniptr; + +extern smb_unichar smb_unieol; + +struct mbchain; +struct smb_rq; +struct smb_vc; + +/* + * Tunable timeout values. See: smb_smb.c + */ +extern int smb_timo_notice; +extern int smb_timo_default; +extern int smb_timo_open; +extern int smb_timo_read; +extern int smb_timo_write; +extern int smb_timo_append; + +#define EMOREDATA (0x7fff) + +#ifdef APPLE +void smb_scred_init(struct smb_cred *scred, vfs_context_t vfsctx); +int smb_sigintr(vfs_context_t); +#endif +void smb_credinit(struct smb_cred *scred, struct proc *p, cred_t *cr); +void smb_credrele(struct smb_cred *scred); +char *smb_strdup(const char *s); +void *smb_memdup(const void *umem, int len); +char *smb_strdupin(char *s, int maxlen); +void *smb_memdupin(void *umem, int len); +size_t smb_strtouni(uint16_t *dst, const char *src, size_t inlen, int flags); +void smb_strfree(char *s); +void smb_memfree(void *s); +void *smb_zmalloc(unsigned long size); + +void smb_oldlm_hash(const char *apwd, uchar_t *hash); +void smb_ntlmv1hash(const char *apwd, uchar_t *hash); + +int smb_lmresponse(const uchar_t *hash, uchar_t *C8, uchar_t *RN); +int smb_ntlmresponse(const uchar_t *hash, uchar_t *C8, uchar_t *RN); +int smb_ntlmv2response(const uchar_t *hash, const uchar_t *user, + const uchar_t *destination, uchar_t *C8, const uchar_t *blob, + size_t bloblen, uchar_t **RN, size_t *RNlen); +int smb_maperror(int eclass, int eno); +uint32_t smb_maperr32(uint32_t eno); +int smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, + const char *src, int len, int caseopt, int *lenp); +int smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, + const char *src, int caseopt); +int smb_put_string(struct smb_rq *rqp, const char *src); +int smb_put_asunistring(struct smb_rq *rqp, const char *src); +int smb_checksmp(void); + +int smb_cmp_sockaddr(struct sockaddr *, struct sockaddr *); +struct sockaddr *smb_dup_sockaddr(struct sockaddr *sa); +void smb_free_sockaddr(struct sockaddr *sa); +int smb_toupper(const char *, char *, size_t); + +#endif /* !_NETSMB_SMB_SUBR_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,1179 @@ +/* + * Copyright (c) 2000-2001 Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_subr.c,v 1.27.108.1 2005/06/02 00:55:39 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kmem.h> +#include <sys/proc.h> +#include <sys/lock.h> +#include <sys/socket.h> +#include <sys/isa_defs.h> +#include <sys/stream.h> +#include <sys/strsun.h> +#include <sys/sunddi.h> +#include <sys/cmn_err.h> +#include <sys/sdt.h> +#include <sys/priv.h> +#include <sys/u8_textprep.h> + +#include <netsmb/smb_osdep.h> +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_rq.h> +#include <netsmb/smb_subr.h> + +/* + * XXX:This conversion might not be fully MS-Compatible + * for calculating hashes. The output length may differ + * for some locales and needs to be handled from where + * the call is made. + */ +int +smb_toupper(const char *inbuf, char *outbuf, size_t outlen) +{ + int err = 0; + size_t inlen, inrem, outrem; + + inrem = inlen = strlen(inbuf); + outrem = outlen; + (void) u8_textprep_str((char *)inbuf, &inrem, outbuf, &outrem, + U8_TEXTPREP_TOUPPER, U8_UNICODE_LATEST, &err); + /* inrem, outrem are bytes unused, remaining */ + if (inrem) { + SMBSDEBUG("input %d remains: %s\n", (int)inrem, inbuf); + inlen -= inrem; + } + if (outrem) { + outlen -= outrem; + outbuf[outlen] = '\0'; + } + if (outlen > inlen) { + SMBSDEBUG("outlen > inlen! (%d > %d)\n", + (int)outlen, (int)inlen); + /* Truncate to inlen here? */ + } + + return (err); +} + +void +smb_credinit(struct smb_cred *scred, struct proc *p, cred_t *icr) +{ + scred->vc_pid = p->p_pidp->pid_id; + if (!icr) + icr = p->p_cred; + if (is_system_labeled()) { + icr = crdup(icr); + (void) setpflags(NET_MAC_AWARE, 1, icr); + } else { + crhold(icr); + } + scred->vc_ucred = icr; +} + +void +smb_credrele(struct smb_cred *scred) +{ + crfree(scred->vc_ucred); + scred->vc_ucred = NULL; +} + +#ifdef APPLE +/*ARGSUSED*/ +int +smb_sigintr(vfs_context_t vfsctx) +{ + /* + * I cannot find something to match vfs_context_issignal. + * It calls proc_pendingsignals() in Darwin code. + */ + if (vfsctx && vfs_context_issignal(vfsctx, SMB_SIGMASK)) + return (EINTR); + return (0); +} +#endif + +char * +smb_strdup(const char *s) +{ + char *p; + int len; + + len = s ? strlen(s) + 1 : 1; + p = kmem_alloc(len, KM_SLEEP); + if (s) + bcopy(s, p, len); + else + *p = 0; + return (p); +} + +/* + * duplicate string from a user space. + */ +char * +smb_strdupin(char *s, int maxlen) +{ + char *p, bt; + int len = 0; + + for (p = s; ; p++) { + if (copyin(p, &bt, 1)) + return (NULL); + len++; + if (maxlen && len > maxlen) + return (NULL); + if (bt == 0) + break; + } + p = kmem_alloc(len, KM_SLEEP); + copyin(s, p, len); + return (p); +} + +/* + * duplicate memory block from a user space. + */ +void * +smb_memdupin(void *umem, int len) +{ + char *p; + + if (len > 32 * 1024) + return (NULL); + p = kmem_alloc(len, KM_SLEEP); + if (copyin(umem, p, len) == 0) + return (p); + kmem_free(p, len); + return (NULL); +} + +/* + * duplicate memory block in the kernel space. + */ +void * +smb_memdup(const void *umem, int len) +{ + char *p; + + if (len > 32 * 1024) + return (NULL); + p = kmem_alloc(len, KM_SLEEP); + if (p == NULL) + return (NULL); + bcopy(umem, p, len); + return (p); +} + +void +smb_strfree(char *s) +{ + kmem_free(s, strlen(s) + 1); +} + +void +smb_memfree(void *s) +{ + kmem_free(s, strlen(s)); +} + +void * +smb_zmalloc(unsigned long size) +{ + void *p = kmem_zalloc(size, KM_SLEEP); + return (p); +} + +size_t +smb_strtouni(u_int16_t *dst, const char *src, size_t inlen, int flags) +{ + size_t outlen = 0; + + if (!inlen) + inlen = strlen(src); + + /* Force output format to little-endian. */ + flags &= ~UCONV_OUT_BIG_ENDIAN; + flags |= UCONV_OUT_LITTLE_ENDIAN; + + outlen = inlen * 2; + if (uconv_u8tou16((uchar_t *)src, &inlen, dst, &outlen, flags) != 0) { + outlen = 0; + } + return (outlen * 2); +} + +/* + * Helper for the SMBERROR macro, etc. + * This is also a good place for a breakpoint + * or a dtrace probe, i.e. fbt:nsmb:smb_errmsg + */ +void +smb_errmsg(int cel, const char *func_name, const char *fmt, ...) +{ + va_list adx; + char buf[100]; + + va_start(adx, fmt); + if (cel == CE_CONT) { + /* + * This is one of our xxxDEBUG macros. + * Don't bother to log these, but just + * fire a dtrace probe with the message. + */ + vsnprintf(buf, sizeof (buf), fmt, adx); + DTRACE_PROBE2(debugmsg2, + (char *), func_name, + (char *), buf); + } else { + /* + * This is one of our xxxERROR macros. + * Add a prefix to the fmt string, + * then let vcmn_err do the args. + */ + snprintf(buf, sizeof (buf), "?%s: %s", func_name, fmt); + DTRACE_PROBE3(debugmsg3, + (char *), func_name, + (char *), buf, + va_list, adx); + vcmn_err(cel, buf, adx); + } + va_end(adx); +} + +#if 1 /* def SMB_SOCKETDATA_DEBUG */ +void +m_dumpm(mblk_t *m) +{ + int len, seg; + + len = msgdsize(m); + DTRACE_PROBE2(dsize, int, len, (mblk_t *), m); + + for (seg = 0; m; seg++) { + DTRACE_PROBE2(mblk, int, seg, (mblk_t *), m); + m = m->b_cont; + } +} +#endif + +/* all these need review XXX */ +#ifndef EPROTO +#define EPROTO ECONNABORTED +#endif +#ifndef ELIBACC +#define ELIBACC ENOENT +#endif +#ifndef ENODATA +#define ENODATA EINVAL +#endif +#ifndef ENOTUNIQ +#define ENOTUNIQ EADDRINUSE +#endif +#ifndef ECOMM +#define ECOMM EIO +#endif +#ifndef ENOMEDIUM +#define ENOMEDIUM EIO +#endif +#ifndef ETIME +#define ETIME ETIMEDOUT +#endif + +static struct { + unsigned nterr; + unsigned errno; +} nt2errno[] = { + {NT_STATUS_ACCESS_DENIED, EACCES}, + {NT_STATUS_ACCESS_VIOLATION, EACCES}, + {NT_STATUS_ACCOUNT_DISABLED, EACCES}, + {NT_STATUS_ACCOUNT_RESTRICTION, EACCES}, + {NT_STATUS_ADDRESS_ALREADY_EXISTS, EADDRINUSE}, + {NT_STATUS_BAD_NETWORK_NAME, ENOENT}, + {NT_STATUS_BUFFER_TOO_SMALL, EMOREDATA}, + {NT_STATUS_CANNOT_DELETE, EACCES}, + {NT_STATUS_CONFLICTING_ADDRESSES, EADDRINUSE}, + {NT_STATUS_CONNECTION_ABORTED, ECONNABORTED}, + {NT_STATUS_CONNECTION_DISCONNECTED, ECONNABORTED}, + {NT_STATUS_CONNECTION_REFUSED, ECONNREFUSED}, + {NT_STATUS_CONNECTION_RESET, ENETRESET}, + {NT_STATUS_DEVICE_DOES_NOT_EXIST, ENODEV}, + {NT_STATUS_DEVICE_PROTOCOL_ERROR, EPROTO}, + {NT_STATUS_DIRECTORY_NOT_EMPTY, ENOTEMPTY}, + {NT_STATUS_DISK_FULL, ENOSPC}, + {NT_STATUS_DLL_NOT_FOUND, ELIBACC}, + {NT_STATUS_END_OF_FILE, ENODATA}, + {NT_STATUS_FILE_IS_A_DIRECTORY, EISDIR}, + {NT_STATUS_FLOAT_INEXACT_RESULT, ERANGE}, + {NT_STATUS_FLOAT_OVERFLOW, ERANGE}, + {NT_STATUS_FLOAT_UNDERFLOW, ERANGE}, + {NT_STATUS_HOST_UNREACHABLE, EHOSTUNREACH}, + {NT_STATUS_ILL_FORMED_PASSWORD, EACCES}, + {NT_STATUS_INTEGER_OVERFLOW, ERANGE}, + {NT_STATUS_INVALID_HANDLE, EBADF}, + {NT_STATUS_INVALID_LOGON_HOURS, EACCES}, + {NT_STATUS_INVALID_PARAMETER, EINVAL}, + {NT_STATUS_INVALID_PIPE_STATE, EPIPE}, + {NT_STATUS_INVALID_WORKSTATION, EACCES}, + {NT_STATUS_IN_PAGE_ERROR, EFAULT}, + {NT_STATUS_IO_TIMEOUT, ETIMEDOUT}, + {NT_STATUS_IP_ADDRESS_CONFLICT1, ENOTUNIQ}, + {NT_STATUS_IP_ADDRESS_CONFLICT2, ENOTUNIQ}, + {NT_STATUS_LICENSE_QUOTA_EXCEEDED, EDQUOT}, + {NT_STATUS_LOGON_FAILURE, EACCES}, + {NT_STATUS_MEDIA_WRITE_PROTECTED, EROFS}, + {NT_STATUS_MEMORY_NOT_ALLOCATED, EFAULT}, + {NT_STATUS_NAME_TOO_LONG, ENAMETOOLONG}, + {NT_STATUS_NETWORK_ACCESS_DENIED, EACCES}, + {NT_STATUS_NETWORK_BUSY, EBUSY}, + {NT_STATUS_NETWORK_UNREACHABLE, ENETUNREACH}, + {NT_STATUS_NET_WRITE_FAULT, ECOMM}, + {NT_STATUS_NONEXISTENT_SECTOR, ESPIPE}, + {NT_STATUS_NOT_A_DIRECTORY, ENOTDIR}, + {NT_STATUS_NOT_IMPLEMENTED, ENOSYS}, + {NT_STATUS_NOT_MAPPED_VIEW, EINVAL}, + {NT_STATUS_NOT_SUPPORTED, ENOSYS}, + {NT_STATUS_NO_MEDIA, ENOMEDIUM}, + {NT_STATUS_NO_MEDIA_IN_DEVICE, ENOMEDIUM}, + {NT_STATUS_NO_MEMORY, ENOMEM}, + {NT_STATUS_NO_SUCH_DEVICE, ENODEV}, + {NT_STATUS_NO_SUCH_FILE, ENOENT}, + {NT_STATUS_OBJECT_NAME_COLLISION, EEXIST}, + {NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT}, + {NT_STATUS_OBJECT_PATH_INVALID, ENOTDIR}, + {NT_STATUS_PAGEFILE_QUOTA, EDQUOT}, + {NT_STATUS_PASSWORD_EXPIRED, EACCES}, + {NT_STATUS_PASSWORD_RESTRICTION, EACCES}, + {NT_STATUS_PATH_NOT_COVERED, ENOENT}, + {NT_STATUS_PIPE_BROKEN, EPIPE}, + {NT_STATUS_PIPE_BUSY, EPIPE}, + {NT_STATUS_PIPE_CONNECTED, EISCONN}, + {NT_STATUS_PIPE_DISCONNECTED, EPIPE}, + {NT_STATUS_PIPE_NOT_AVAILABLE, ENOSYS}, + {NT_STATUS_PORT_CONNECTION_REFUSED, ECONNREFUSED}, + {NT_STATUS_PORT_MESSAGE_TOO_LONG, EMSGSIZE}, + {NT_STATUS_PORT_UNREACHABLE, EHOSTUNREACH}, + {NT_STATUS_PROTOCOL_UNREACHABLE, ENOPROTOOPT}, + {NT_STATUS_QUOTA_EXCEEDED, EDQUOT}, + {NT_STATUS_REGISTRY_QUOTA_LIMIT, EDQUOT}, + {NT_STATUS_REMOTE_DISCONNECT, ESHUTDOWN}, + {NT_STATUS_REMOTE_NOT_LISTENING, ECONNREFUSED}, + {NT_STATUS_REQUEST_NOT_ACCEPTED, EACCES}, + {NT_STATUS_RETRY, EAGAIN}, + {NT_STATUS_SHARING_VIOLATION, EBUSY}, + {NT_STATUS_TIMER_NOT_CANCELED, ETIME}, + {NT_STATUS_TOO_MANY_LINKS, EMLINK}, + {NT_STATUS_TOO_MANY_OPENED_FILES, EMFILE}, + {NT_STATUS_UNABLE_TO_FREE_VM, EADDRINUSE}, + {NT_STATUS_UNSUCCESSFUL, EINVAL}, + {NT_STATUS_WRONG_PASSWORD, EACCES}, + {0, 0} +}; + +static struct { + unsigned dclass; + unsigned derr; + unsigned nterr; +} nt2doserr[] = { + {ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, + {ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_INFO_CLASS}, + {ERRDOS, ERRbadlength, NT_STATUS_INFO_LENGTH_MISMATCH}, + {ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION}, + {ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR}, + {ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA}, + {ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE}, + {ERRHRD, ERRgeneral, NT_STATUS_BAD_INITIAL_STACK}, + {ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_CID}, + {ERRHRD, ERRgeneral, NT_STATUS_TIMER_NOT_CANCELED}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER}, + {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE}, + {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE}, + {ERRDOS, ERRbadfunc, NT_STATUS_INVALID_DEVICE_REQUEST}, + {ERRDOS, ERRhandleeof, NT_STATUS_END_OF_FILE}, + {ERRDOS, ERRwrongdisk, NT_STATUS_WRONG_VOLUME}, + {ERRDOS, ERRnotready, NT_STATUS_NO_MEDIA_IN_DEVICE}, + {ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_MEDIA}, + {ERRDOS, ERRsectornotfound, NT_STATUS_NONEXISTENT_SECTOR}, + {ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY}, + {ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES}, + {ERRDOS, 487, NT_STATUS_NOT_MAPPED_VIEW}, + {ERRDOS, ERRinvalidparam, NT_STATUS_UNABLE_TO_FREE_VM}, + {ERRDOS, ERRinvalidparam, NT_STATUS_UNABLE_TO_DELETE_SECTION}, + {ERRDOS, 2142, NT_STATUS_INVALID_SYSTEM_SERVICE}, + {ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_INSTRUCTION}, + {ERRDOS, ERRnoaccess, NT_STATUS_INVALID_LOCK_SEQUENCE}, + {ERRDOS, ERRnoaccess, NT_STATUS_INVALID_VIEW_SIZE}, + {ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION}, + {ERRDOS, ERRnoaccess, NT_STATUS_ALREADY_COMMITTED}, + {ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED}, + {ERRDOS, 111, NT_STATUS_BUFFER_TOO_SMALL}, + {ERRDOS, ERRbadfid, NT_STATUS_OBJECT_TYPE_MISMATCH}, + {ERRHRD, ERRgeneral, NT_STATUS_NONCONTINUABLE_EXCEPTION}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_DISPOSITION}, + {ERRHRD, ERRgeneral, NT_STATUS_UNWIND}, + {ERRHRD, ERRgeneral, NT_STATUS_BAD_STACK}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_UNWIND_TARGET}, + {ERRDOS, 158, NT_STATUS_NOT_LOCKED}, + {ERRHRD, ERRgeneral, NT_STATUS_PARITY_ERROR}, + {ERRDOS, 487, NT_STATUS_UNABLE_TO_DECOMMIT_VM}, + {ERRDOS, 487, NT_STATUS_NOT_COMMITTED}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_PORT_ATTRIBUTES}, + {ERRHRD, ERRgeneral, NT_STATUS_PORT_MESSAGE_TOO_LONG}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER_MIX}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_QUOTA_LOWER}, + {ERRHRD, ERRgeneral, NT_STATUS_DISK_CORRUPT_ERROR}, + {ERRDOS, ERRinvalidname, NT_STATUS_OBJECT_NAME_INVALID}, + {ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND}, + {ERRDOS, 183, NT_STATUS_OBJECT_NAME_COLLISION}, + {ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE}, + {ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED}, + {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED}, + {ERRDOS, 161, NT_STATUS_OBJECT_PATH_INVALID}, + {ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND}, + {ERRDOS, 161, NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, + {ERRHRD, ERRgeneral, NT_STATUS_DATA_OVERRUN}, + {ERRHRD, ERRgeneral, NT_STATUS_DATA_LATE_ERROR}, + {ERRDOS, ERRcrc, NT_STATUS_DATA_ERROR}, + {ERRDOS, ERRcrc, NT_STATUS_CRC_ERROR}, + {ERRDOS, ERRnomem, NT_STATUS_SECTION_TOO_BIG}, + {ERRDOS, ERRnoaccess, NT_STATUS_PORT_CONNECTION_REFUSED}, + {ERRDOS, ERRbadfid, NT_STATUS_INVALID_PORT_HANDLE}, + {ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION}, + {ERRHRD, ERRgeneral, NT_STATUS_QUOTA_EXCEEDED}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PAGE_PROTECTION}, + {ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED}, + {ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED}, + {ERRDOS, ERRinvalidparam, NT_STATUS_PORT_ALREADY_SET}, + {ERRDOS, ERRinvalidparam, NT_STATUS_SECTION_NOT_IMAGE}, + {ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED}, + {ERRDOS, ERRnoaccess, NT_STATUS_THREAD_IS_TERMINATING}, + {ERRDOS, ERRinvalidparam, NT_STATUS_BAD_WORKING_SET_LIMIT}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INCOMPATIBLE_FILE_MAP}, + {ERRDOS, ERRinvalidparam, NT_STATUS_SECTION_PROTECTION}, + {ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED}, + {ERRDOS, 255, NT_STATUS_EA_TOO_LARGE}, + {ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE}, + {ERRHRD, ERRgeneral, NT_STATUS_EA_CORRUPT_ERROR}, + {ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT}, + {ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED}, + {ERRDOS, ERRnoaccess, NT_STATUS_DELETE_PENDING}, + {ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED}, + {ERRHRD, ERRgeneral, NT_STATUS_UNKNOWN_REVISION}, + {ERRHRD, ERRgeneral, NT_STATUS_REVISION_MISMATCH}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_OWNER}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_PRIMARY_GROUP}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_IMPERSONATION_TOKEN}, + {ERRHRD, ERRgeneral, NT_STATUS_CANT_DISABLE_MANDATORY}, + {ERRDOS, 2215, NT_STATUS_NO_LOGON_SERVERS}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_LOGON_SESSION}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PRIVILEGE}, + {ERRDOS, ERRnoaccess, NT_STATUS_PRIVILEGE_NOT_HELD}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME}, + {ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS}, + {ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, + {ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP}, + {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP}, + {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_GROUP}, + {ERRHRD, ERRgeneral, NT_STATUS_LAST_ADMIN}, + {ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD}, + {ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_PASSWORD}, + {ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION}, + {ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE}, + {ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, + {ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, + {ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, + {ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, + {ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, + {ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, + {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, + {ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SUB_AUTHORITY}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACL}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SID}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SECURITY_DESCR}, + {ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND}, + {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_FORMAT}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_TOKEN}, + {ERRHRD, ERRgeneral, NT_STATUS_BAD_INHERITANCE_ACL}, + {ERRDOS, 158, NT_STATUS_RANGE_NOT_LOCKED}, + {ERRDOS, 112, NT_STATUS_DISK_FULL}, + {ERRHRD, ERRgeneral, NT_STATUS_SERVER_DISABLED}, + {ERRHRD, ERRgeneral, NT_STATUS_SERVER_NOT_DISABLED}, + {ERRDOS, ERRtoomanynames, NT_STATUS_TOO_MANY_GUIDS_REQUESTED}, + {ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ID_AUTHORITY}, + {ERRDOS, 259, NT_STATUS_AGENTS_EXHAUSTED}, + {ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL}, + {ERRDOS, ERRoutofmem, NT_STATUS_SECTION_NOT_EXTENDED}, + {ERRDOS, 487, NT_STATUS_NOT_MAPPED_DATA}, + {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_DATA_NOT_FOUND}, + {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_TYPE_NOT_FOUND}, + {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_NAME_NOT_FOUND}, + {ERRHRD, ERRgeneral, NT_STATUS_ARRAY_BOUNDS_EXCEEDED}, + {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DENORMAL_OPERAND}, + {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DIVIDE_BY_ZERO}, + {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INEXACT_RESULT}, + {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INVALID_OPERATION}, + {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_OVERFLOW}, + {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_STACK_CHECK}, + {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_UNDERFLOW}, + {ERRHRD, ERRgeneral, NT_STATUS_INTEGER_DIVIDE_BY_ZERO}, + {ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW}, + {ERRHRD, ERRgeneral, NT_STATUS_PRIVILEGED_INSTRUCTION}, + {ERRDOS, ERRnomem, NT_STATUS_TOO_MANY_PAGING_FILES}, + {ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, + {ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED}, + {ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, + {ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, + {ERRDOS, ERRcrc, NT_STATUS_DEVICE_DATA_ERROR}, + {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_CONNECTED}, + {ERRDOS, ERRnotready, NT_STATUS_DEVICE_POWER_FAILURE}, + {ERRDOS, 487, NT_STATUS_FREE_VM_NOT_AT_BASE}, + {ERRDOS, 487, NT_STATUS_MEMORY_NOT_ALLOCATED}, + {ERRHRD, ERRgeneral, NT_STATUS_WORKING_SET_QUOTA}, + {ERRDOS, ERRwriteprotect, NT_STATUS_MEDIA_WRITE_PROTECTED}, + {ERRDOS, ERRnotready, NT_STATUS_DEVICE_NOT_READY}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_GROUP_ATTRIBUTES}, + {ERRHRD, ERRgeneral, NT_STATUS_BAD_IMPERSONATION_LEVEL}, + {ERRHRD, ERRgeneral, NT_STATUS_CANT_OPEN_ANONYMOUS}, + {ERRHRD, ERRgeneral, NT_STATUS_BAD_VALIDATION_CLASS}, + {ERRHRD, ERRgeneral, NT_STATUS_BAD_TOKEN_TYPE}, + {ERRDOS, ERRinvalidparam, NT_STATUS_BAD_MASTER_BOOT_RECORD}, + {ERRHRD, ERRgeneral, NT_STATUS_INSTRUCTION_MISALIGNMENT}, + {ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE}, + {ERRDOS, ERRpipebusy, NT_STATUS_PIPE_NOT_AVAILABLE}, + {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PIPE_STATE}, + {ERRDOS, ERRpipebusy, NT_STATUS_PIPE_BUSY}, + {ERRDOS, ERRbadfunc, NT_STATUS_ILLEGAL_FUNCTION}, + {ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED}, + {ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING}, + {ERRHRD, ERRgeneral, NT_STATUS_PIPE_CONNECTED}, + {ERRHRD, ERRgeneral, NT_STATUS_PIPE_LISTENING}, + {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_READ_MODE}, + {ERRDOS, 121, NT_STATUS_IO_TIMEOUT}, + {ERRDOS, ERRhandleeof, NT_STATUS_FILE_FORCED_CLOSED}, + {ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STARTED}, + {ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STOPPED}, + {ERRHRD, ERRgeneral, NT_STATUS_COULD_NOT_INTERPRET}, + {ERRDOS, ERRnoaccess, NT_STATUS_FILE_IS_A_DIRECTORY}, + {ERRDOS, ERRunsup, NT_STATUS_NOT_SUPPORTED}, + {ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING}, + {ERRDOS, 52, NT_STATUS_DUPLICATE_NAME}, + {ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH}, + {ERRDOS, 54, NT_STATUS_NETWORK_BUSY}, + {ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST}, + {ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS}, + {ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR}, + {ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE}, + {ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR}, + {ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER}, + {ERRDOS, 61, NT_STATUS_PRINT_QUEUE_FULL}, + {ERRDOS, 62, NT_STATUS_NO_SPOOL_SPACE}, + {ERRDOS, 63, NT_STATUS_PRINT_CANCELLED}, + {ERRDOS, 64, NT_STATUS_NETWORK_NAME_DELETED}, + {ERRDOS, 65, NT_STATUS_NETWORK_ACCESS_DENIED}, + {ERRDOS, 66, NT_STATUS_BAD_DEVICE_TYPE}, + {ERRDOS, ERRnosuchshare, NT_STATUS_BAD_NETWORK_NAME}, + {ERRDOS, 68, NT_STATUS_TOO_MANY_NAMES}, + {ERRDOS, 69, NT_STATUS_TOO_MANY_SESSIONS}, + {ERRDOS, 70, NT_STATUS_SHARING_PAUSED}, + {ERRDOS, 71, NT_STATUS_REQUEST_NOT_ACCEPTED}, + {ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED}, + {ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT}, + {ERRHRD, ERRgeneral, NT_STATUS_PROFILING_AT_LIMIT}, + {ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE}, + {ERRDOS, ERRnoaccess, NT_STATUS_FILE_RENAMED}, + {ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_SECURITY_ON_OBJECT}, + {ERRHRD, ERRgeneral, NT_STATUS_CANT_WAIT}, + {ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_EMPTY}, + {ERRHRD, ERRgeneral, NT_STATUS_CANT_ACCESS_DOMAIN_INFO}, + {ERRHRD, ERRgeneral, NT_STATUS_CANT_TERMINATE_SELF}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SERVER_STATE}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_STATE}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_ROLE}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_DOMAIN}, + {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_EXISTS}, + {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_LIMIT_EXCEEDED}, + {ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED}, + {ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL}, + {ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_CORRUPTION}, + {ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_ERROR}, + {ERRHRD, ERRgeneral, NT_STATUS_GENERIC_NOT_MAPPED}, + {ERRHRD, ERRgeneral, NT_STATUS_BAD_DESCRIPTOR_FORMAT}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_USER_BUFFER}, + {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_IO_ERROR}, + {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_CREATE_ERR}, + {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_MAP_ERROR}, + {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_EXTEND_ERR}, + {ERRHRD, ERRgeneral, NT_STATUS_NOT_LOGON_PROCESS}, + {ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_EXISTS}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER_1}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER_2}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER_3}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER_4}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER_5}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER_6}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER_7}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER_8}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER_9}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER_10}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER_11}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER_12}, + {ERRDOS, ERRbadpath, NT_STATUS_REDIRECTOR_NOT_STARTED}, + {ERRHRD, ERRgeneral, NT_STATUS_REDIRECTOR_STARTED}, + {ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PACKAGE}, + {ERRHRD, ERRgeneral, NT_STATUS_BAD_FUNCTION_TABLE}, + {ERRDOS, 203, NT_STATUS_VARIABLE_NOT_FOUND}, + {ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY}, + {ERRHRD, ERRgeneral, NT_STATUS_FILE_CORRUPT_ERROR}, + {ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY}, + {ERRHRD, ERRgeneral, NT_STATUS_BAD_LOGON_SESSION_STATE}, + {ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_COLLISION}, + {ERRDOS, 206, NT_STATUS_NAME_TOO_LONG}, + {ERRDOS, 2401, NT_STATUS_FILES_OPEN}, + {ERRDOS, 2404, NT_STATUS_CONNECTION_IN_USE}, + {ERRHRD, ERRgeneral, NT_STATUS_MESSAGE_NOT_FOUND}, + {ERRDOS, ERRnoaccess, NT_STATUS_PROCESS_IS_TERMINATING}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LOGON_TYPE}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION}, + {ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE}, + {ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED}, + {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT}, + {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST}, + {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED}, + {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER}, + {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND}, + {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID}, + {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE}, + {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_LDT}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_DESCRIPTOR}, + {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NE_FORMAT}, + {ERRHRD, ERRgeneral, NT_STATUS_RXACT_INVALID_STATE}, + {ERRHRD, ERRgeneral, NT_STATUS_RXACT_COMMIT_FAILURE}, + {ERRHRD, ERRgeneral, NT_STATUS_MAPPED_FILE_SIZE_ZERO}, + {ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES}, + {ERRHRD, ERRgeneral, NT_STATUS_CANCELLED}, + {ERRDOS, ERRnoaccess, NT_STATUS_CANNOT_DELETE}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_COMPUTER_NAME}, + {ERRDOS, ERRnoaccess, NT_STATUS_FILE_DELETED}, + {ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_ACCOUNT}, + {ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_GROUP}, + {ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_USER}, + {ERRHRD, ERRgeneral, NT_STATUS_MEMBERS_PRIMARY_GROUP}, + {ERRDOS, ERRbadfid, NT_STATUS_FILE_CLOSED}, + {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_THREADS}, + {ERRHRD, ERRgeneral, NT_STATUS_THREAD_NOT_IN_PROCESS}, + {ERRHRD, ERRgeneral, NT_STATUS_TOKEN_ALREADY_IN_USE}, + {ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA_EXCEEDED}, + {ERRHRD, ERRgeneral, NT_STATUS_COMMITMENT_LIMIT}, + {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_LE_FORMAT}, + {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NOT_MZ}, + {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_PROTECT}, + {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_WIN_16}, + {ERRHRD, ERRgeneral, NT_STATUS_LOGON_SERVER_CONFLICT}, + {ERRHRD, ERRgeneral, NT_STATUS_TIME_DIFFERENCE_AT_DC}, + {ERRHRD, ERRgeneral, NT_STATUS_SYNCHRONIZATION_REQUIRED}, + {ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND}, + {ERRHRD, ERRgeneral, NT_STATUS_OPEN_FAILED}, + {ERRHRD, ERRgeneral, NT_STATUS_IO_PRIVILEGE_FAILED}, + {ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND}, + {ERRDOS, 127, NT_STATUS_ENTRYPOINT_NOT_FOUND}, + {ERRHRD, ERRgeneral, NT_STATUS_CONTROL_C_EXIT}, + {ERRDOS, 64, NT_STATUS_LOCAL_DISCONNECT}, + {ERRDOS, 64, NT_STATUS_REMOTE_DISCONNECT}, + {ERRDOS, 51, NT_STATUS_REMOTE_RESOURCES}, + {ERRDOS, 59, NT_STATUS_LINK_FAILED}, + {ERRDOS, 59, NT_STATUS_LINK_TIMEOUT}, + {ERRDOS, 59, NT_STATUS_INVALID_CONNECTION}, + {ERRDOS, 59, NT_STATUS_INVALID_ADDRESS}, + {ERRHRD, ERRgeneral, NT_STATUS_DLL_INIT_FAILED}, + {ERRHRD, ERRgeneral, NT_STATUS_MISSING_SYSTEMFILE}, + {ERRHRD, ERRgeneral, NT_STATUS_UNHANDLED_EXCEPTION}, + {ERRHRD, ERRgeneral, NT_STATUS_APP_INIT_FAILURE}, + {ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_CREATE_FAILED}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_PAGEFILE}, + {ERRDOS, 124, NT_STATUS_INVALID_LEVEL}, + {ERRDOS, 86, NT_STATUS_WRONG_PASSWORD_CORE}, + {ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_FLOAT_CONTEXT}, + {ERRDOS, 109, NT_STATUS_PIPE_BROKEN}, + {ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_CORRUPT}, + {ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_IO_FAILED}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_EVENT_PAIR}, + {ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_VOLUME}, + {ERRHRD, ERRgeneral, NT_STATUS_SERIAL_NO_DEVICE_INITED}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_ALIAS}, + {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_ALIAS}, + {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_ALIAS}, + {ERRHRD, ERRgeneral, NT_STATUS_ALIAS_EXISTS}, + {ERRHRD, ERRgeneral, NT_STATUS_LOGON_NOT_GRANTED}, + {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SECRETS}, + {ERRHRD, ERRgeneral, NT_STATUS_SECRET_TOO_LONG}, + {ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_ERROR}, + {ERRHRD, ERRgeneral, NT_STATUS_FULLSCREEN_MODE}, + {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_CONTEXT_IDS}, + {ERRDOS, ERRnoaccess, NT_STATUS_LOGON_TYPE_NOT_GRANTED}, + {ERRHRD, ERRgeneral, NT_STATUS_NOT_REGISTRY_FILE}, + {ERRHRD, ERRgeneral, NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED}, + {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR}, + {ERRHRD, ERRgeneral, NT_STATUS_FT_MISSING_MEMBER}, + {ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_SERVICE_ENTRY}, + {ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_CHARACTER}, + {ERRHRD, ERRgeneral, NT_STATUS_UNMAPPABLE_CHARACTER}, + {ERRHRD, ERRgeneral, NT_STATUS_UNDEFINED_CHARACTER}, + {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_VOLUME}, + {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND}, + {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_WRONG_CYLINDER}, + {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_UNKNOWN_ERROR}, + {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_BAD_REGISTERS}, + {ERRHRD, ERRgeneral, NT_STATUS_DISK_RECALIBRATE_FAILED}, + {ERRHRD, ERRgeneral, NT_STATUS_DISK_OPERATION_FAILED}, + {ERRHRD, ERRgeneral, NT_STATUS_DISK_RESET_FAILED}, + {ERRHRD, ERRgeneral, NT_STATUS_SHARED_IRQ_BUSY}, + {ERRHRD, ERRgeneral, NT_STATUS_FT_ORPHANING}, + {ERRHRD, ERRgeneral, NT_STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT}, + {ERRHRD, ERRgeneral, NT_STATUS_16F}, + {ERRHRD, ERRgeneral, NT_STATUS_170}, + {ERRHRD, ERRgeneral, NT_STATUS_171}, + {ERRHRD, ERRgeneral, NT_STATUS_PARTITION_FAILURE}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_BLOCK_LENGTH}, + {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_PARTITIONED}, + {ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_LOCK_MEDIA}, + {ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_UNLOAD_MEDIA}, + {ERRHRD, ERRgeneral, NT_STATUS_EOM_OVERFLOW}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_MEDIA}, + {ERRHRD, ERRgeneral, NT_STATUS_179}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_MEMBER}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_MEMBER}, + {ERRHRD, ERRgeneral, NT_STATUS_KEY_DELETED}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_LOG_SPACE}, + {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SIDS}, + {ERRHRD, ERRgeneral, NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED}, + {ERRHRD, ERRgeneral, NT_STATUS_KEY_HAS_CHILDREN}, + {ERRHRD, ERRgeneral, NT_STATUS_CHILD_MUST_BE_VOLATILE}, + {ERRDOS, ERRinvalidparam, NT_STATUS_DEVICE_CONFIGURATION_ERROR}, + {ERRHRD, ERRgeneral, NT_STATUS_DRIVER_INTERNAL_ERROR}, + {ERRDOS, ERRbadcmd, NT_STATUS_INVALID_DEVICE_STATE}, + {ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR}, + {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_PROTOCOL_ERROR}, + {ERRHRD, ERRgeneral, NT_STATUS_BACKUP_CONTROLLER}, + {ERRHRD, ERRgeneral, NT_STATUS_LOG_FILE_FULL}, + {ERRDOS, ERRwriteprotect, NT_STATUS_TOO_LATE}, + {ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET}, + {ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, + {ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, + {ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE}, + {ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CORRUPT}, + {ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START}, + {ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, + {ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, + {ERRDOS, ERRinvgroup, NT_STATUS_NETLOGON_NOT_STARTED}, + {ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED}, + {ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, + {ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, + {ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT}, + {ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CHANGED}, + {ERRDOS, ERRnoaccess, + NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, + {ERRDOS, ERRnoaccess, + NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, + {ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT}, + {ERRDOS, ERRnoaccess, NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, + {ERRHRD, ERRgeneral, NT_STATUS_FS_DRIVER_REQUIRED}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_USER_SESSION_KEY}, + {ERRDOS, 59, NT_STATUS_USER_SESSION_DELETED}, + {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_LANG_NOT_FOUND}, + {ERRDOS, ERRnomem, NT_STATUS_INSUFF_SERVER_RESOURCES}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_BUFFER_SIZE}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_COMPONENT}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_WILDCARD}, + {ERRDOS, 68, NT_STATUS_TOO_MANY_ADDRESSES}, + {ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_EXISTS}, + {ERRDOS, 64, NT_STATUS_ADDRESS_CLOSED}, + {ERRDOS, 64, NT_STATUS_CONNECTION_DISCONNECTED}, + {ERRDOS, 64, NT_STATUS_CONNECTION_RESET}, + {ERRDOS, 68, NT_STATUS_TOO_MANY_NODES}, + {ERRDOS, 59, NT_STATUS_TRANSACTION_ABORTED}, + {ERRDOS, 59, NT_STATUS_TRANSACTION_TIMED_OUT}, + {ERRDOS, 59, NT_STATUS_TRANSACTION_NO_RELEASE}, + {ERRDOS, 59, NT_STATUS_TRANSACTION_NO_MATCH}, + {ERRDOS, 59, NT_STATUS_TRANSACTION_RESPONDED}, + {ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_ID}, + {ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_TYPE}, + {ERRDOS, ERRunsup, NT_STATUS_NOT_SERVER_SESSION}, + {ERRDOS, ERRunsup, NT_STATUS_NOT_CLIENT_SESSION}, + {ERRHRD, ERRgeneral, NT_STATUS_CANNOT_LOAD_REGISTRY_FILE}, + {ERRHRD, ERRgeneral, NT_STATUS_DEBUG_ATTACH_FAILED}, + {ERRHRD, ERRgeneral, NT_STATUS_SYSTEM_PROCESS_TERMINATED}, + {ERRHRD, ERRgeneral, NT_STATUS_DATA_NOT_ACCEPTED}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_BROWSER_SERVERS_FOUND}, + {ERRHRD, ERRgeneral, NT_STATUS_VDM_HARD_ERROR}, + {ERRHRD, ERRgeneral, NT_STATUS_DRIVER_CANCEL_TIMEOUT}, + {ERRHRD, ERRgeneral, NT_STATUS_REPLY_MESSAGE_MISMATCH}, + {ERRHRD, ERRgeneral, NT_STATUS_MAPPED_ALIGNMENT}, + {ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, + {ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, + {ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, + {ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE}, + {ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, + {ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, + {ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, + {ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW_READ}, + {ERRHRD, ERRgeneral, NT_STATUS_FAIL_CHECK}, + {ERRHRD, ERRgeneral, NT_STATUS_DUPLICATE_OBJECTID}, + {ERRHRD, ERRgeneral, NT_STATUS_OBJECTID_EXISTS}, + {ERRHRD, ERRgeneral, NT_STATUS_CONVERT_TO_LARGE}, + {ERRHRD, ERRgeneral, NT_STATUS_RETRY}, + {ERRHRD, ERRgeneral, NT_STATUS_FOUND_OUT_OF_SCOPE}, + {ERRHRD, ERRgeneral, NT_STATUS_ALLOCATE_BUCKET}, + {ERRHRD, ERRgeneral, NT_STATUS_PROPSET_NOT_FOUND}, + {ERRHRD, ERRgeneral, NT_STATUS_MARSHALL_OVERFLOW}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_VARIANT}, + {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND}, + {ERRDOS, ERRnoaccess, NT_STATUS_ACCOUNT_LOCKED_OUT}, + {ERRDOS, ERRbadfid, NT_STATUS_HANDLE_NOT_CLOSABLE}, + {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_REFUSED}, + {ERRHRD, ERRgeneral, NT_STATUS_GRACEFUL_DISCONNECT}, + {ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED}, + {ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_NOT_ASSOCIATED}, + {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_INVALID}, + {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ACTIVE}, + {ERRHRD, ERRgeneral, NT_STATUS_NETWORK_UNREACHABLE}, + {ERRHRD, ERRgeneral, NT_STATUS_HOST_UNREACHABLE}, + {ERRHRD, ERRgeneral, NT_STATUS_PROTOCOL_UNREACHABLE}, + {ERRHRD, ERRgeneral, NT_STATUS_PORT_UNREACHABLE}, + {ERRHRD, ERRgeneral, NT_STATUS_REQUEST_ABORTED}, + {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ABORTED}, + {ERRHRD, ERRgeneral, NT_STATUS_BAD_COMPRESSION_BUFFER}, + {ERRHRD, ERRgeneral, NT_STATUS_USER_MAPPED_FILE}, + {ERRHRD, ERRgeneral, NT_STATUS_AUDIT_FAILED}, + {ERRHRD, ERRgeneral, NT_STATUS_TIMER_RESOLUTION_NOT_SET}, + {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_COUNT_LIMIT}, + {ERRHRD, ERRgeneral, NT_STATUS_LOGIN_TIME_RESTRICTION}, + {ERRHRD, ERRgeneral, NT_STATUS_LOGIN_WKSTA_RESTRICTION}, + {ERRDOS, 193, NT_STATUS_IMAGE_MP_UP_MISMATCH}, + {ERRHRD, ERRgeneral, 0x000024a}, + {ERRHRD, ERRgeneral, 0x000024b}, + {ERRHRD, ERRgeneral, 0x000024c}, + {ERRHRD, ERRgeneral, 0x000024d}, + {ERRHRD, ERRgeneral, 0x000024e}, + {ERRHRD, ERRgeneral, 0x000024f}, + {ERRHRD, ERRgeneral, NT_STATUS_INSUFFICIENT_LOGON_INFO}, + {ERRHRD, ERRgeneral, NT_STATUS_BAD_DLL_ENTRYPOINT}, + {ERRHRD, ERRgeneral, NT_STATUS_BAD_SERVICE_ENTRYPOINT}, + {ERRHRD, ERRgeneral, NT_STATUS_LPC_REPLY_LOST}, + {ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT1}, + {ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT2}, + {ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_QUOTA_LIMIT}, + {ERRSRV, ERRbadtype, NT_STATUS_PATH_NOT_COVERED}, + {ERRHRD, ERRgeneral, NT_STATUS_NO_CALLBACK_ACTIVE}, + {ERRHRD, ERRgeneral, NT_STATUS_LICENSE_QUOTA_EXCEEDED}, + {ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_SHORT}, + {ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_RECENT}, + {ERRHRD, ERRgeneral, NT_STATUS_PWD_HISTORY_CONFLICT}, + {ERRHRD, ERRgeneral, 0x000025d}, + {ERRHRD, ERRgeneral, NT_STATUS_PLUGPLAY_NO_DEVICE}, + {ERRHRD, ERRgeneral, NT_STATUS_UNSUPPORTED_COMPRESSION}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_HW_PROFILE}, + {ERRHRD, ERRgeneral, NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH}, + {ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, + {ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, + {ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED}, + {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS}, + {ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT}, + {ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE}, + {ERRDOS, ERRnotready, NT_STATUS_VOLUME_DISMOUNTED}, + {ERRDOS, 161, NT_STATUS_DIRECTORY_IS_A_REPARSE_POINT}, + {ERRDOS, ERRnoaccess, NT_STATUS_ENCRYPTION_FAILED}, + {ERRDOS, ERRnoaccess, NT_STATUS_DECRYPTION_FAILED}, + {ERRHRD, ERRgeneral, NT_STATUS_RANGE_NOT_FOUND}, + {ERRDOS, ERRnoaccess, NT_STATUS_NO_RECOVERY_POLICY}, + {ERRDOS, ERRnoaccess, NT_STATUS_NO_EFS}, + {ERRDOS, ERRnoaccess, NT_STATUS_WRONG_EFS}, + {ERRDOS, ERRnoaccess, NT_STATUS_NO_USER_KEYS}, + {ERRDOS, ERRbadfunc, NT_STATUS_VOLUME_NOT_UPGRADED}, +}; + +u_int32_t +smb_maperr32(u_int32_t eno) +{ + int i; + unsigned orig = eno; + + /* + * Hi two bits are "severity". Ignore "success" (0) and + * "informational" (1) values. + */ + if (!(eno & 0x80000000)) + return (0); + /* mask off "severity" and the "component" bit */ + eno &= ~(0xe0000000); + + /* first try direct map to unix */ + for (i = 0; nt2errno[i].errno; i++) + if (nt2errno[i].nterr == eno) + return (nt2errno[i].errno); + SMBERROR("no direct map for 32 bit server error (0x%x)\n", orig); + + /* ok, then try mapping to dos to unix */ + for (i = 0; nt2doserr[i].derr; i++) + if (nt2doserr[i].nterr == eno) + return (smb_maperror(nt2doserr[i].dclass, + nt2doserr[i].derr)); + return (smb_maperror(ERRHRD, ERRgeneral)); +} + + +int +smb_maperror(int eclass, int eno) +{ + if (eclass == 0 && eno == 0) + return (0); + switch (eclass) { + case ERRDOS: + switch (eno) { + case ERRbadfunc: + case ERRbadenv: + case ERRbadformat: + case ERRremcd: + case ERRrmuns: + return (EINVAL); + case ERRbadfile: + case ERRbadpath: + case ERRnoipc: + case ERRnosuchshare: + return (ENOENT); + case ERRnofids: + return (EMFILE); + case ERRnoaccess: + /* + * XXX CSM Reported on samba-technical 12/7/2002 + * + * There is a case for which server(s) return + * ERRnoaccess but should return ERRdiskfull: When + * the offset for a write is exactly the server + * file size limit then Samba (at least) thinks + * the reason for zero bytes having been written + * must have been "access denied" from the local + * filesystem. This cannot be easily worked + * around since the server behaviour is + * indistinguishable from actual access denied. + * An incomplete workaround: attempt a 2 byte write + * from "offset-1". (That may require reading at + * offset-1 first.) The flaw is that reading or + * writing at offset-1 could cause an + * unrelated error (due to a byte range lock + * for instance) and we can't presume the + * order servers check errors in. + */ + case ERRbadaccess: + return (EACCES); + case ERRbadshare: + return (EBUSY); + case ERRbadfid: + return (EBADF); + case ERRbadmcb: + return (EIO); + case ERRnomem: + return (ENOMEM); /* actually remote no mem... */ + case ERRbadmem: + return (EFAULT); + case ERRbaddata: + return (E2BIG); + case ERRbaddrive: + case ERRnotready: /* nt */ + return (ENXIO); + case ERRdiffdevice: + return (EXDEV); + case ERRnofiles: + return (0); /* eeof ? */ + case ERRlock: + return (EDEADLK); + case ERRfilexists: + return (EEXIST); + case ERRinvalidname: /* samba maps as noent */ + return (ENOENT); + case ERRdirnotempty: /* samba */ + return (ENOTEMPTY); + case ERRnotlocked: + return (0); /* 0 since bsd unlocks on any close */ + case ERRrename: + return (EEXIST); + case ERRmoredata: + return (EMOREDATA); + } + break; + case ERRSRV: + switch (eno) { + case ERRerror: + return (EINVAL); + case ERRbadpw: + return (EAUTH); + case ERRaccess: + case ERRbaduid: + return (EACCES); + case ERRinvnid: + return (ENETRESET); + case ERRinvnetname: + SMBERROR("NetBIOS name is invalid: %d\n", + ERRinvnetname); + return (EAUTH); + case ERRbadtype: /* reserved and returned */ + return (EIO); + case ERRacctexpired: /* NT: account exists but disabled */ + return (EPERM); + } + break; + case ERRHRD: + switch (eno) { + case ERRnowrite: + return (EROFS); + case ERRbadunit: + return (ENODEV); + case ERRbadreq: + return (EBADRPC); + case ERRbadshare: + return (ETXTBSY); + case ERRlock: + return (EDEADLK); + case ERRdiskfull: + return (EFBIG); + case ERRnotready: + case ERRbadcmd: + case ERRdata: + case ERRgeneral: + return (EIO); + default: + SMBERROR("Unmapped DOS error %d:%d\n", eclass, eno); + return (EIO); + } + } + SMBERROR("Unmapped DOS error %d:%d\n", eclass, eno); + return (EBADRPC); +} + +#if defined(NOICONVSUPPORT) || defined(lint) +extern int iconv_conv(void *handle, const char **inbuf, + size_t *inbytesleft, char **outbuf, size_t *outbytesleft); +#endif + +#define SMALL_CONV 256 + +/*ARGSUSED*/ +int +smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src, + int size, int caseopt, int *lenp) +{ + uint16_t convbuf[SMALL_CONV]; + uint16_t *cbuf; + size_t cbufalloc, inlen, outlen; + int error; + + if (size <= 0) + return (0); + + /* + * Handle the easy case (non-unicode). + * XXX: Technically, we should convert + * the string to OEM codeset first... + * Modern servers all use Unicode, so + * this is good enough. + */ + if (SMB_UNICODE_STRINGS(vcp) == 0) { + error = mb_put_mem(mbp, src, size, MB_MSYSTEM); + if (!error && lenp) + *lenp += size; + return (error); + } + + /* + * Convert to UCS-2 (really UTF-16). + * Use stack buffer if the string is + * small enough, else allocate. + */ + if (size <= SMALL_CONV) { + cbufalloc = 0; + outlen = SMALL_CONV; + cbuf = convbuf; + } else { + outlen = size; /* in utf-16 characters */ + cbufalloc = outlen * 2; + cbuf = kmem_alloc(cbufalloc, KM_SLEEP); + } + + inlen = size; + error = uconv_u8tou16((uchar_t *)src, &inlen, cbuf, &outlen, + UCONV_OUT_LITTLE_ENDIAN | UCONV_IGNORE_NULL); + outlen *= 2; /* convert to bytes */ + + if (!error) { + (void) mb_put_padbyte(mbp); /* align */ + error = mb_put_mem(mbp, (char *)cbuf, outlen, MB_MSYSTEM); + } + if (!error && lenp) + *lenp += outlen; + + if (cbufalloc) + kmem_free(cbuf, cbufalloc); + + return (error); +} + +int +smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src, + int caseopt) +{ + int error, len; + + /* + * Let smb_put_dmem put both the string + * and the terminating null. + */ + len = strlen(src) + 1; + error = smb_put_dmem(mbp, vcp, src, len, caseopt, NULL); + if (error) + return (error); + + return (error); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,138 @@ +/* + * 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. + * + * Selected code from smb_conn.c + */ + +#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Helper functions for smb_trantcp.c + * (and maybe future transports) + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kmem.h> +#include <sys/cmn_err.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> + +/* Like smb_dev.h, this knows about all our sockaddr formats. */ +#include <netsmb/netbios.h> + +#ifdef APPLE +#include <sys/smb_apple.h> +#else +#include <netsmb/smb_osdep.h> +#endif + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> +#include <netsmb/smb_tran.h> + +/* + * Return the length of a sockaddr structure. + * Only needs to handle the address formats + * used by smb_dup_sockaddr. + */ +static size_t +SA_LEN(struct sockaddr *sa) +{ + size_t len; + + switch (sa->sa_family) { + case AF_INET: + len = sizeof (struct sockaddr_in); + break; + case AF_INET6: + len = sizeof (struct sockaddr_in6); + break; + case AF_NETBIOS: + len = sizeof (struct sockaddr_nb); + break; + default: + SMBSDEBUG("invalid address family %d\n", sa->sa_family); + len = sizeof (struct sockaddr); + break; + } + + return (len); +} + +/* + * Compare two sockaddr contents + * Return zero if identical. + */ +int +smb_cmp_sockaddr(struct sockaddr *a1, struct sockaddr *a2) +{ + size_t l1, l2; + + l1 = SA_LEN(a1); + l2 = SA_LEN(a2); + + if (l1 != l2) + return (-1); + + return (bcmp(a1, a2, l1)); +} + +/* + * Copy a socket address of varying size. + */ +struct sockaddr * +smb_dup_sockaddr(struct sockaddr *sa) +{ + struct sockaddr *sa2; + size_t len; + + /* Get the length (varies per family) */ + len = SA_LEN(sa); + + sa2 = kmem_alloc(len, KM_SLEEP); + if (sa2) + bcopy(sa, sa2, len); + + return (sa2); +} + +void +smb_free_sockaddr(struct sockaddr *sa) +{ + size_t len; + + /* Get the length (varies per family) */ + len = SA_LEN(sa); + + kmem_free(sa, len); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2000-2001, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_tran.h,v 1.2 2001/12/21 02:41:30 conrad Exp $ + */ + +#ifndef _NETSMB_SMB_TRAN_H_ +#define _NETSMB_SMB_TRAN_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/socket.h> + +/* + * Known transports + */ +#define SMBT_NBTCP 1 + +/* + * Transport parameters + */ +#define SMBTP_SNDSZ 1 /* R - int */ +#define SMBTP_RCVSZ 2 /* R - int */ +#define SMBTP_TIMEOUT 3 /* RW - struct timespec */ +#ifndef __sun +#define SMBTP_SELECTID 4 /* RW - (void *) */ +#define SMBTP_UPCALL 5 /* RW - (* void)(void *) */ +#endif + +struct smb_tran_ops; + +struct smb_tran_desc { + sa_family_t tr_type; + int (*tr_create)(struct smb_vc *vcp, struct proc *p); + int (*tr_done)(struct smb_vc *vcp, struct proc *p); + int (*tr_bind)(struct smb_vc *vcp, struct sockaddr *sap, + struct proc *p); + int (*tr_connect)(struct smb_vc *vcp, struct sockaddr *sap, + struct proc *p); + int (*tr_disconnect)(struct smb_vc *vcp, struct proc *p); + int (*tr_send)(struct smb_vc *vcp, mblk_t *m0, struct proc *p); + int (*tr_recv)(struct smb_vc *vcp, mblk_t **mpp, struct proc *p); + int (*tr_poll)(struct smb_vc *vcp, int ticks, struct proc *p); + int (*tr_getparam)(struct smb_vc *vcp, int param, void *data); + int (*tr_setparam)(struct smb_vc *vcp, int param, void *data); + int (*tr_fatal)(struct smb_vc *vcp, int error); +#ifdef notyet + int (*tr_cmpaddr)(void *addr1, void *addr2); +#endif + LIST_ENTRY(smb_tran_desc) tr_link; +}; +typedef struct smb_tran_desc smb_tran_desc_t; + +#define SMB_TRAN_CREATE(vcp, p) (vcp)->vc_tdesc->tr_create(vcp, p) +#define SMB_TRAN_DONE(vcp, p) (vcp)->vc_tdesc->tr_done(vcp, p) +#define SMB_TRAN_BIND(vcp, sap, p) (vcp)->vc_tdesc->tr_bind(vcp, sap, p) +#define SMB_TRAN_CONNECT(vcp, sap, p) (vcp)->vc_tdesc->tr_connect(vcp, sap, p) +#define SMB_TRAN_DISCONNECT(vcp, p) (vcp)->vc_tdesc->tr_disconnect(vcp, p) +#define SMB_TRAN_SEND(vcp, m0, p) (vcp)->vc_tdesc->tr_send(vcp, m0, p) +#define SMB_TRAN_RECV(vcp, m, p) (vcp)->vc_tdesc->tr_recv(vcp, m, p) +#define SMB_TRAN_POLL(vcp, t, p) (vcp)->vc_tdesc->tr_poll(vcp, t, p) +#define SMB_TRAN_GETPARAM(vcp, par, data) \ + (vcp)->vc_tdesc->tr_getparam(vcp, par, data) +#define SMB_TRAN_SETPARAM(vcp, par, data) \ + (vcp)->vc_tdesc->tr_setparam(vcp, par, data) +#define SMB_TRAN_FATAL(vcp, error) (vcp)->vc_tdesc->tr_fatal(vcp, error) + +/* Ops vectors for each transport. */ +extern struct smb_tran_desc smb_tran_nbtcp_desc; + +#endif /* _NETSMB_SMB_TRAN_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,1221 @@ +/* + * Copyright (c) 2000-2001 Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_trantcp.c,v 1.39 2005/03/02 01:27:44 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/autoconf.h> +#include <sys/sysmacros.h> +#include <sys/sunddi.h> +#include <sys/kmem.h> +#include <sys/proc.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/poll.h> +#include <sys/stream.h> +#include <sys/strsubr.h> +#include <sys/strsun.h> +#include <sys/stropts.h> +#include <sys/cmn_err.h> +#include <sys/tihdr.h> +#include <sys/tiuser.h> +#include <sys/t_kuser.h> +#include <sys/priv.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> + +#ifdef APPLE +#include <sys/smb_apple.h> +#else +#include <netsmb/smb_osdep.h> +#endif + +#include <netsmb/mchain.h> +#include <netsmb/netbios.h> + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> +#include <netsmb/smb_tran.h> +#include <netsmb/smb_trantcp.h> + +/* + * SMB messages are up to 64K. + * Let's leave room for two. + */ +static int smb_tcpsndbuf = 0x20000; +static int smb_tcprcvbuf = 0x20000; + +static dev_t smb_tcp_dev; + +static int nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp, + uint8_t *rpcodep, struct proc *p); +static int nb_disconnect(struct nbpcb *nbp); + +static int +nb_wait_ack(TIUSER *tiptr, t_scalar_t ack_prim, int fmode) +{ + int msgsz; + union T_primitives *pptr; + mblk_t *bp; + ptrdiff_t diff; + int error; + + /* + * wait for ack + */ + bp = NULL; + if ((error = tli_recv(tiptr, &bp, fmode)) != 0) + return (error); + + /*LINTED*/ + diff = MBLKL(bp); + ASSERT(diff == (ptrdiff_t)((int)diff)); + msgsz = (int)diff; + + if (msgsz < sizeof (int)) { + freemsg(bp); + return (EPROTO); + } + + /*LINTED*/ + pptr = (union T_primitives *)bp->b_rptr; + if (pptr->type == ack_prim) + error = 0; /* Success */ + else if (pptr->type == T_ERROR_ACK) { + if (pptr->error_ack.TLI_error == TSYSERR) + error = pptr->error_ack.UNIX_error; + else + error = t_tlitosyserr(pptr->error_ack.TLI_error); + } else + error = EPROTO; + + freemsg(bp); + return (error); +} + +/* + * Internal set sockopt for int-sized options. + * Is there a common Solaris function for this? + * Code from uts/common/rpc/clnt_cots.c + */ +static int +nb_setsockopt_int(TIUSER *tiptr, int level, int name, int val) +{ + int fmode; + mblk_t *mp; + struct opthdr *opt; + struct T_optmgmt_req *tor; + int *valp; + int error, mlen; + + mlen = (sizeof (struct T_optmgmt_req) + + sizeof (struct opthdr) + sizeof (int)); + if (!(mp = allocb_wait(mlen, BPRI_LO, STR_NOSIG, &error))) + return (error); + + mp->b_datap->db_type = M_PROTO; + /*LINTED*/ + tor = (struct T_optmgmt_req *)mp->b_wptr; + tor->PRIM_type = T_SVR4_OPTMGMT_REQ; + tor->MGMT_flags = T_NEGOTIATE; + tor->OPT_length = sizeof (struct opthdr) + sizeof (int); + tor->OPT_offset = sizeof (struct T_optmgmt_req); + mp->b_wptr += sizeof (struct T_optmgmt_req); + + /*LINTED*/ + opt = (struct opthdr *)mp->b_wptr; + opt->level = level; + opt->name = name; + opt->len = sizeof (int); + mp->b_wptr += sizeof (struct opthdr); + + /* LINTED */ + valp = (int *)mp->b_wptr; + *valp = val; + mp->b_wptr += sizeof (int); + + fmode = tiptr->fp->f_flag; + if ((error = tli_send(tiptr, mp, fmode)) != 0) + return (error); + + fmode = 0; /* need to block */ + error = nb_wait_ack(tiptr, T_OPTMGMT_ACK, fmode); + return (error); +} + +/* + * Get mblks into *mpp until the data length is at least mlen. + * Note that *mpp may already contain a fragment. + * + * If we ever have to wait more than 15 sec. to read a message, + * return ETIME. (Caller will declare the VD dead.) + */ +static int +nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen) +{ + mblk_t *im, *tm; + union T_primitives *pptr; + size_t dlen; + int events, fmode, timo, waitflg; + int error = 0; + + /* + * Get the first message (fragment) if + * we don't already have a left-over. + */ + dlen = msgdsize(*mpp); /* *mpp==null is OK */ + while (dlen < mlen) { + + /* + * I think we still want this to return ETIME + * if nothing arrives for SMB_NBTIMO (15) sec. + * so we can report "server not responding". + * We _could_ just block here now that our + * IOD is just a reader. + */ +#if 1 + /* Wait with timeout... */ + events = 0; + waitflg = READWAIT; + timo = SEC_TO_TICK(SMB_NBTIMO); + error = t_kspoll(nbp->nbp_tiptr, timo, waitflg, &events); + if (!error && !events) + error = ETIME; + if (error) + break; + /* file mode for recv is: */ + fmode = FNDELAY; /* non-blocking */ +#else + fmode = 0; /* normal (blocking) */ +#endif + + /* Get some more... */ + tm = NULL; + error = tli_recv(nbp->nbp_tiptr, &tm, fmode); + if (error == EAGAIN) + continue; + if (error) + break; + + /* + * Normally get M_DATA messages here, + * but have to check for other types. + */ + switch (tm->b_datap->db_type) { + case M_DATA: + break; + case M_PROTO: + case M_PCPROTO: + /*LINTED*/ + pptr = (union T_primitives *)tm->b_rptr; + switch (pptr->type) { + case T_DATA_IND: + /* remove 1st mblk, keep the rest. */ + im = tm->b_cont; + tm->b_cont = NULL; + freeb(tm); + tm = im; + break; + case T_DISCON_IND: + /* Peer disconnected. */ + NBDEBUG("T_DISCON_IND: reason=%d", + pptr->discon_ind.DISCON_reason); + goto discon; + case T_ORDREL_IND: + /* Peer disconnecting. */ + NBDEBUG("T_ORDREL_IND"); + goto discon; + case T_OK_ACK: + switch (pptr->ok_ack.CORRECT_prim) { + case T_DISCON_REQ: + NBDEBUG("T_OK_ACK/T_DISCON_REQ"); + goto discon; + default: + NBDEBUG("T_OK_ACK/prim=%d", + pptr->ok_ack.CORRECT_prim); + goto discon; + } + default: + NBDEBUG("M_PROTO/type=%d", pptr->type); + goto discon; + } + break; /* M_PROTO, M_PCPROTO */ + + default: + NBDEBUG("unexpected msg type=%d", + tm->b_datap->db_type); + /*FALLTHROUGH*/ +discon: + /* + * The connection is no longer usable. + * Drop this message and disconnect. + * + * Note: nb_disconnect only does t_snddis + * on the first call, but does important + * cleanup and state change on any call. + */ + freemsg(tm); + nb_disconnect(nbp); + return (ENOTCONN); + } + + /* + * If we have a data message, append it to + * the previous chunk(s) and update dlen + */ + if (!tm) + continue; + if (*mpp == NULL) { + *mpp = tm; + } else { + /* Append */ + for (im = *mpp; im->b_cont; im = im->b_cont) + ; + im->b_cont = tm; + } + dlen += msgdsize(tm); + } + + return (error); +} + +/* + * Send a T_DISCON_REQ (disconnect) + */ +static int +nb_snddis(TIUSER *tiptr) +{ + mblk_t *mp; + struct T_discon_req *dreq; + int error, fmode, mlen; + + mlen = sizeof (struct T_discon_req); + if (!(mp = allocb_wait(mlen, BPRI_LO, STR_NOSIG, &error))) + return (error); + + mp->b_datap->db_type = M_PROTO; + /*LINTED*/ + dreq = (struct T_discon_req *)mp->b_wptr; + dreq->PRIM_type = T_DISCON_REQ; + dreq->SEQ_number = -1; + mp->b_wptr += sizeof (struct T_discon_req); + + fmode = tiptr->fp->f_flag; + if ((error = tli_send(tiptr, mp, fmode)) != 0) + return (error); + +#if 0 /* Now letting the IOD recv this. */ + fmode = 0; /* need to block */ + error = nb_wait_ack(tiptr, T_OK_ACK, fmode); +#endif + return (error); +} + +#ifdef APPLE +static int +nb_intr(struct nbpcb *nbp, struct proc *p) +{ + return (0); +} +#endif + +/* + * Stuff the NetBIOS header into space already prepended. + */ +static int +nb_sethdr(mblk_t *m, uint8_t type, uint32_t len) +{ + uint32_t *p; + + len &= 0x1FFFF; + len |= (type << 24); + + /*LINTED*/ + p = (uint32_t *)m->b_rptr; + *p = htonl(len); + return (0); +} + +/* + * Note: Moved name encoding into here. + */ +static int +nb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb) +{ + int i, len; + uchar_t ch, *p; + + /* + * Do the NetBIOS "first-level encoding" here. + * (RFC1002 explains this wierdness...) + * See similar code in smbfs library: + * lib/libsmbfs/smb/nb_name.c + * + * Here is what we marshall: + * uint8_t NAME_LENGTH (always 32) + * uint8_t ENCODED_NAME[32] + * uint8_t SCOPE_LENGTH + * XXX Scope should follow here, then another null, + * if and when we support NetBIOS scopes. + */ + len = 1 + (2 * NB_NAMELEN) + 1; + + p = mb_reserve(mbp, len); + if (!p) + return (ENOSR); + + /* NAME_LENGTH */ + *p++ = (2 * NB_NAMELEN); + + /* ENCODED_NAME */ + for (i = 0; i < NB_NAMELEN; i++) { + ch = (uchar_t)snb->snb_name[i]; + *p++ = 'A' + ((ch >> 4) & 0xF); + *p++ = 'A' + ((ch) & 0xF); + } + + /* SCOPE_LENGTH */ + *p++ = 0; + + return (0); +} + +static int +nb_tcpopen(struct nbpcb *nbp, struct proc *p) +{ + TIUSER *tiptr; + int err, oflags = FREAD|FWRITE; + cred_t *cr = p->p_cred; + + if (!smb_tcp_dev) { + smb_tcp_dev = makedevice( + clone_major, ddi_name_to_major("tcp")); + } + + /* + * This magic arranges for our network endpoint + * to have the right "label" for operation in a + * "trusted extensions" environment. + */ + if (is_system_labeled()) { + cr = crdup(cr); + (void) setpflags(NET_MAC_AWARE, 1, cr); + } else { + crhold(cr); + } + err = t_kopen(NULL, smb_tcp_dev, oflags, &tiptr, cr); + crfree(cr); + if (err) + return (err); + + /* Note: I_PUSH "timod" is done by t_kopen */ + + /* Save the TPI handle we use everywhere. */ + nbp->nbp_tiptr = tiptr; + + /* + * Internal ktli calls need the "fmode" flags + * from the t_kopen call. XXX: Not sure if the + * flags have the right bits set, or if we + * always want the same block/non-block flags. + * XXX: Look into this... + */ + nbp->nbp_fmode = tiptr->fp->f_flag; + return (0); +} + +/*ARGSUSED*/ +static int +nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct proc *p) +{ + int error; + TIUSER *tiptr = NULL; + struct t_call call; + + tiptr = nbp->nbp_tiptr; + if (tiptr == NULL) + return (EBADF); + if (nbp->nbp_flags & NBF_CONNECTED) + return (EISCONN); + + /* + * Set various socket/TCP options. + * Failures here are not fatal - + * just log a complaint. + * + * We don't need these two: + * SO_RCVTIMEO, SO_SNDTIMEO + */ + + error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_SNDBUF, + nbp->nbp_sndbuf); + if (error) + NBDEBUG("nb_connect_in: set SO_SNDBUF"); + + error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_RCVBUF, + nbp->nbp_rcvbuf); + if (error) + NBDEBUG("nb_connect_in: set SO_RCVBUF"); + + error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_KEEPALIVE, 1); + if (error) + NBDEBUG("nb_connect_in: set SO_KEEPALIVE"); + + error = nb_setsockopt_int(tiptr, IPPROTO_TCP, TCP_NODELAY, 1); + if (error) + NBDEBUG("nb_connect_in: set TCP_NODELAY"); + + /* Do local bind (any address) */ + if ((error = t_kbind(tiptr, NULL, NULL)) != 0) { + NBDEBUG("nb_connect_in: bind local"); + return (error); + } + + /* + * Setup (snd)call address (connect to). + * Just pass NULL for the (rcv)call. + */ + bzero(&call, sizeof (call)); + call.addr.len = sizeof (*to); + call.addr.buf = (char *)to; + /* call.opt - none */ + /* call.udata -- XXX: Should put NB session req here! */ + + /* Send the connect, wait... */ + error = t_kconnect(tiptr, &call, NULL); + if (error) { + NBDEBUG("nb_connect_in: connect %d error", error); + /* + * XXX: t_kconnect returning EPROTO here instead of ETIMEDOUT + * here. Temporarily return ETIMEDOUT error if we get EPROTO. + */ + if (error == EPROTO) + error = ETIMEDOUT; + } else { + mutex_enter(&nbp->nbp_lock); + nbp->nbp_flags |= NBF_CONNECTED; + mutex_exit(&nbp->nbp_lock); + } + + return (error); +} + +static int +nbssn_rq_request(struct nbpcb *nbp, struct proc *p) +{ + struct mbchain mb, *mbp = &mb; + struct mdchain md, *mdp = &md; + mblk_t *m0; + struct sockaddr_in sin; + ushort_t port; + uint8_t rpcode; + int error, rplen; + + error = mb_init(mbp); + if (error) + return (error); + + /* + * Put a zero for the 4-byte NetBIOS header, + * then let nb_sethdr() overwrite it. + */ + mb_put_uint32le(mbp, 0); + nb_put_name(mbp, nbp->nbp_paddr); + nb_put_name(mbp, nbp->nbp_laddr); + nb_sethdr(mbp->mb_top, NB_SSN_REQUEST, mb_fixhdr(mbp) - 4); + + m0 = mb_detach(mbp); + error = tli_send(nbp->nbp_tiptr, m0, nbp->nbp_fmode); + m0 = NULL; /* Note: _always_ consumed by tli_send */ + mb_done(mbp); + if (error) + return (error); + + nbp->nbp_state = NBST_RQSENT; + error = nbssn_recv(nbp, &m0, &rplen, &rpcode, p); + if (error == EWOULDBLOCK) { /* Timeout */ + NBDEBUG("initial request timeout\n"); + return (ETIMEDOUT); + } + if (error) { + NBDEBUG("recv() error %d\n", error); + return (error); + } + /* + * Process NETBIOS reply + */ + if (m0) + md_initm(mdp, m0); + + error = 0; + if (rpcode == NB_SSN_POSRESP) { + mutex_enter(&nbp->nbp_lock); + nbp->nbp_state = NBST_SESSION; + mutex_exit(&nbp->nbp_lock); + goto out; + } + if (rpcode != NB_SSN_RTGRESP) { + error = ECONNABORTED; + goto out; + } + if (rplen != 6) { + error = ECONNABORTED; + goto out; + } + md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM); + md_get_uint16(mdp, &port); + sin.sin_port = port; + nbp->nbp_state = NBST_RETARGET; + nb_disconnect(nbp); + error = nb_connect_in(nbp, &sin, p); + if (!error) + error = nbssn_rq_request(nbp, p); + if (error) { + nb_disconnect(nbp); + } + +out: + if (m0) + md_done(mdp); + return (error); +} + +/* + * Wait for up to 15 sec. for the next packet. + * Often return ETIME and do nothing else. + * When a packet header is available, check + * the header and get the length, but don't + * consume it. No side effects here except + * for the pullupmsg call. + */ +static int +nbssn_peekhdr(struct nbpcb *nbp, size_t *lenp, uint8_t *rpcodep) +{ + uint32_t len, *hdr; + int error; + + /* + * Get the first message (fragment) if + * we don't already have a left-over. + */ + error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, sizeof (len)); + if (error) + return (error); + + if (!pullupmsg(nbp->nbp_frag, sizeof (len))) + return (ENOSR); + + /* + * Check the NetBIOS header. + * (NOT consumed here) + */ + /*LINTED*/ + hdr = (uint32_t *)nbp->nbp_frag->b_rptr; + + len = ntohl(*hdr); + if ((len >> 16) & 0xFE) { + NBDEBUG("bad nb header received 0x%x (MBZ flag set)\n", len); + return (EPIPE); + } + *rpcodep = (len >> 24) & 0xFF; + switch (*rpcodep) { + case NB_SSN_MESSAGE: + case NB_SSN_REQUEST: + case NB_SSN_POSRESP: + case NB_SSN_NEGRESP: + case NB_SSN_RTGRESP: + case NB_SSN_KEEPALIVE: + break; + default: + NBDEBUG("bad nb header received 0x%x (bogus type)\n", len); + return (EPIPE); + } + len &= 0x1ffff; + if (len > SMB_MAXPKTLEN) { + NBDEBUG("packet too long (%d)\n", len); + return (EFBIG); + } + *lenp = len; + return (0); +} + +/* + * Receive a NetBIOS message. This may block to wait for the entire + * message to arrive. The caller knows there is (or should be) a + * message to be read. When we receive and drop a keepalive or + * zero-length message, return EAGAIN so the caller knows that + * something was received. This avoids false triggering of the + * "server not responding" state machine. + */ +/*ARGSUSED*/ +static int +nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp, + uint8_t *rpcodep, struct proc *p) +{ + TIUSER *tiptr = nbp->nbp_tiptr; + mblk_t *m0; + uint8_t rpcode; + int error; + size_t rlen, len; + + /* We should be the only reader. */ + ASSERT(nbp->nbp_flags & NBF_RECVLOCK); + + if (tiptr == NULL) + return (EBADF); + if (mpp) { + if (*mpp) { + NBDEBUG("*mpp not 0 - leak?"); + } + *mpp = NULL; + } + m0 = NULL; + + /* + * Get the NetBIOS header (not consumed yet) + */ + error = nbssn_peekhdr(nbp, &len, &rpcode); + if (error) { + if (error != ETIME) + NBDEBUG("peekhdr, error=%d\n", error); + return (error); + } + NBDEBUG("Have pkt, type=0x%x len=0x%x\n", + (int)rpcode, (int)len); + + /* + * Block here waiting for the whole packet to arrive. + * If we get a timeout, return without side effects. + * The data length we wait for here includes both the + * NetBIOS header and the payload. + */ + error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, len + 4); + if (error) { + NBDEBUG("getmsg(body), error=%d\n", error); + return (error); + } + + /* + * We now have an entire NetBIOS message. + * Trim off the NetBIOS header and consume it. + * Note: _peekhdr has done pullupmsg for us, + * so we know it's safe to advance b_rptr. + */ + m0 = nbp->nbp_frag; + m0->b_rptr += 4; + + /* + * There may be more data after the message + * we're about to return, in which case we + * split it and leave the remainder. + */ + rlen = msgdsize(m0); + ASSERT(rlen >= len); + nbp->nbp_frag = NULL; + if (rlen > len) + nbp->nbp_frag = m_split(m0, len, 1); + + if (nbp->nbp_state != NBST_SESSION) { + /* + * No session is established. + * Return whatever packet we got. + */ + goto out; + } + + /* + * A session is established; the only packets + * we should see are session message and + * keep-alive packets. Drop anything else. + */ + switch (rpcode) { + + case NB_SSN_KEEPALIVE: + /* + * It's a keepalive. Discard any data in it + * (there's not supposed to be any, but that + * doesn't mean some server won't send some) + */ + if (len) + NBDEBUG("Keepalive with data %d\n", (int)len); + error = EAGAIN; + break; + + case NB_SSN_MESSAGE: + /* + * Session message. Does it have any data? + */ + if (len == 0) { + /* + * No data - treat as keepalive (drop). + */ + error = EAGAIN; + break; + } + /* + * Yes, has data. Return it. + */ + error = 0; + break; + + default: + /* + * Drop anything else. + */ + NBDEBUG("non-session packet %x\n", rpcode); + error = EAGAIN; + break; + } + +out: + if (error) { + if (m0) + m_freem(m0); + return (error); + } + if (mpp) + *mpp = m0; + else + m_freem(m0); + *lenp = (int)len; + *rpcodep = rpcode; + return (0); +} + +/* + * SMB transport interface + */ +static int +smb_nbst_create(struct smb_vc *vcp, struct proc *p) +{ + struct nbpcb *nbp; + int error; + + nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP); + + /* + * We don't keep reference counts or otherwise + * prevent nbp->nbp_tiptr from going away, so + * do the TLI open here and keep it until the + * last ref calls smb_nbst_done. + * This does t_kopen (open endpoint) + */ + error = nb_tcpopen(nbp, p); + if (error) { + kmem_free(nbp, sizeof (*nbp)); + return (error); + } + + nbp->nbp_timo.tv_sec = SMB_NBTIMO; + nbp->nbp_state = NBST_CLOSED; /* really IDLE */ + nbp->nbp_vc = vcp; + nbp->nbp_sndbuf = smb_tcpsndbuf; + nbp->nbp_rcvbuf = smb_tcprcvbuf; + mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL); + vcp->vc_tdata = nbp; + return (0); +} + +/*ARGSUSED*/ +static int +smb_nbst_done(struct smb_vc *vcp, struct proc *p) +{ + struct nbpcb *nbp = vcp->vc_tdata; + + if (nbp == NULL) + return (ENOTCONN); + vcp->vc_tdata = NULL; + + /* + * Don't really need to disconnect here, + * because the close following will do it. + * But it's harmless. + */ + if (nbp->nbp_flags & NBF_CONNECTED) + nb_disconnect(nbp); + if (nbp->nbp_tiptr) + t_kclose(nbp->nbp_tiptr, 1); + if (nbp->nbp_laddr) + smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr); + if (nbp->nbp_paddr) + smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr); + mutex_destroy(&nbp->nbp_lock); + kmem_free(nbp, sizeof (*nbp)); + return (0); +} + +/*ARGSUSED*/ +static int +smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p) +{ + struct nbpcb *nbp = vcp->vc_tdata; + struct sockaddr_nb *snb; + int error; + + NBDEBUG("\n"); + error = EINVAL; + + if (nbp->nbp_flags & NBF_LOCADDR) + goto out; + + /* + * Null name is an "anonymous" (NULL) bind request. + * (Let the transport pick a local name.) + * This transport does not support NULL bind. + */ + if (sap == NULL) + goto out; + + /*LINTED*/ + snb = (struct sockaddr_nb *)smb_dup_sockaddr(sap); + if (snb == NULL) { + error = ENOMEM; + goto out; + } + mutex_enter(&nbp->nbp_lock); + nbp->nbp_laddr = snb; + nbp->nbp_flags |= NBF_LOCADDR; + mutex_exit(&nbp->nbp_lock); + error = 0; + +out: + return (error); +} + +static int +smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p) +{ + struct nbpcb *nbp = vcp->vc_tdata; + struct sockaddr_in sin; + struct sockaddr_nb *snb; + struct timespec ts1, ts2; + int error; + + NBDEBUG("\n"); + if (nbp->nbp_tiptr == NULL) + return (EBADF); + if (nbp->nbp_laddr == NULL) + return (EINVAL); + + /* + * Note: nbssn_rq_request() will call nbssn_recv(), + * so set the RECVLOCK flag here. Otherwise we'll + * hit an ASSERT for this flag in nbssn_recv(). + */ + mutex_enter(&nbp->nbp_lock); + if (nbp->nbp_flags & NBF_RECVLOCK) { + NBDEBUG("attempt to reenter session layer!\n"); + mutex_exit(&nbp->nbp_lock); + return (EWOULDBLOCK); + } + nbp->nbp_flags |= NBF_RECVLOCK; + mutex_exit(&nbp->nbp_lock); + + /*LINTED*/ + snb = (struct sockaddr_nb *)smb_dup_sockaddr(sap); + if (snb == NULL) { + error = ENOMEM; + goto out; + } + if (nbp->nbp_paddr) + smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr); + nbp->nbp_paddr = snb; + + /* Setup the remote IP address. */ + bzero(&sin, sizeof (sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(SMB_TCP_PORT); + sin.sin_addr.s_addr = snb->snb_ipaddr; + + /* + * For our general timeout we use the greater of + * the default (15 sec) and 4 times the time it + * took for the first round trip. We used to use + * just the latter, but sometimes if the first + * round trip is very fast the subsequent 4 sec + * timeouts are simply too short. + */ + gethrestime(&ts1); + error = nb_connect_in(nbp, &sin, p); + if (error) + goto out; + gethrestime(&ts2); + timespecsub(&ts2, &ts1); + timespecadd(&ts2, &ts2); + timespecadd(&ts2, &ts2); /* * 4 */ + /*CSTYLED*/ + if (timespeccmp(&ts2, (&(nbp->nbp_timo)), >)) + nbp->nbp_timo = ts2; + error = nbssn_rq_request(nbp, p); + if (error) + nb_disconnect(nbp); +out: + mutex_enter(&nbp->nbp_lock); + nbp->nbp_flags &= ~NBF_RECVLOCK; + mutex_exit(&nbp->nbp_lock); + + return (error); +} + +/*ARGSUSED*/ +static int +smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p) +{ + struct nbpcb *nbp = vcp->vc_tdata; + + if (nbp == NULL) + return (ENOTCONN); + + return (nb_disconnect(nbp)); +} + +static int +nb_disconnect(struct nbpcb *nbp) +{ + TIUSER *tiptr; + int save_flags; + + tiptr = nbp->nbp_tiptr; + if (tiptr == NULL) + return (EBADF); + + mutex_enter(&nbp->nbp_lock); + save_flags = nbp->nbp_flags; + nbp->nbp_flags &= ~NBF_CONNECTED; + if (nbp->nbp_frag) { + freemsg(nbp->nbp_frag); + nbp->nbp_frag = NULL; + } + mutex_exit(&nbp->nbp_lock); + + if (save_flags & NBF_CONNECTED) + nb_snddis(tiptr); + + if (nbp->nbp_state != NBST_RETARGET) { + nbp->nbp_state = NBST_CLOSED; /* really IDLE */ + } + return (0); +} + +/* + * Always consume the message. + * (On error too!) + */ +/*ARGSUSED*/ +static int +smb_nbst_send(struct smb_vc *vcp, mblk_t *m, struct proc *p) +{ + struct nbpcb *nbp = vcp->vc_tdata; + ptrdiff_t diff; + uint32_t mlen; + int error; + + if (nbp == NULL || nbp->nbp_tiptr == NULL) { + error = EBADF; + goto errout; + } + + /* + * Get the message length, which + * does NOT include the NetBIOS header + */ + mlen = msgdsize(m); + + /* + * Normally, mb_init() will have left space + * for us to prepend the NetBIOS header in + * the data block of the first mblk. + * However, we have to check in case other + * code did not leave this space, or if the + * message is from dupmsg (db_ref > 1) + * + * If don't find room in the first data block, + * we have to allocb a new message and link it + * on the front of the chain. We try not to + * do this becuase it's less efficient. Also, + * some network drivers will apparently send + * each mblk in the chain as separate frames. + * (That's arguably a driver bug.) + */ + + /* LINTED */ + diff = MBLKHEAD(m); + if (diff == 4 && DB_REF(m) == 1) { + /* We can use the first dblk. */ + m->b_rptr -= 4; + } else { + /* Link a new mblk on the head. */ + mblk_t *m0; + + /* M_PREPEND */ + m0 = allocb_wait(4, BPRI_LO, STR_NOSIG, &error); + if (!m0) + goto errout; + + m0->b_wptr += 4; + m0->b_cont = m; + m = m0; + } + + nb_sethdr(m, NB_SSN_MESSAGE, mlen); + error = tli_send(nbp->nbp_tiptr, m, 0); + return (error); + +errout: + if (m) + m_freem(m); + return (error); +} + + +static int +smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp, struct proc *p) +{ + struct nbpcb *nbp = vcp->vc_tdata; + uint8_t rpcode; + int error, rplen; + + mutex_enter(&nbp->nbp_lock); + if (nbp->nbp_flags & NBF_RECVLOCK) { + NBDEBUG("attempt to reenter session layer!\n"); + mutex_exit(&nbp->nbp_lock); + return (EWOULDBLOCK); + } + nbp->nbp_flags |= NBF_RECVLOCK; + mutex_exit(&nbp->nbp_lock); + error = nbssn_recv(nbp, mpp, &rplen, &rpcode, p); + mutex_enter(&nbp->nbp_lock); + nbp->nbp_flags &= ~NBF_RECVLOCK; + mutex_exit(&nbp->nbp_lock); + return (error); +} + +/* + * Wait for up to "ticks" clock ticks for input on vcp. + * Returns zero if input is available, otherwise ETIME + * indicating time expired, or other error codes. + */ +/*ARGSUSED*/ +static int +smb_nbst_poll(struct smb_vc *vcp, int ticks, struct proc *p) +{ + int error; + int events = 0; + int waitflg = READWAIT; + struct nbpcb *nbp = vcp->vc_tdata; + + error = t_kspoll(nbp->nbp_tiptr, ticks, waitflg, &events); + if (!error && !events) + error = ETIME; + + return (error); +} + +static int +smb_nbst_getparam(struct smb_vc *vcp, int param, void *data) +{ + struct nbpcb *nbp = vcp->vc_tdata; + + switch (param) { + case SMBTP_SNDSZ: + *(int *)data = nbp->nbp_sndbuf; + break; + case SMBTP_RCVSZ: + *(int *)data = nbp->nbp_rcvbuf; + break; + case SMBTP_TIMEOUT: + *(struct timespec *)data = nbp->nbp_timo; + break; +#ifdef SMBTP_SELECTID + case SMBTP_SELECTID: + *(void **)data = nbp->nbp_selectid; + break; +#endif +#ifdef SMBTP_UPCALL + case SMBTP_UPCALL: + *(void **)data = nbp->nbp_upcall; + break; +#endif + default: + return (EINVAL); + } + return (0); +} + +/*ARGSUSED*/ +static int +smb_nbst_setparam(struct smb_vc *vcp, int param, void *data) +{ + return (EINVAL); +} + +/* + * Check for fatal errors + */ +/*ARGSUSED*/ +static int +smb_nbst_fatal(struct smb_vc *vcp, int error) +{ + switch (error) { + case ENOTCONN: + case ENETRESET: + case ECONNABORTED: + case EPIPE: + return (1); + } + return (0); +} + + +struct smb_tran_desc smb_tran_nbtcp_desc = { + SMBT_NBTCP, + smb_nbst_create, + smb_nbst_done, + smb_nbst_bind, + smb_nbst_connect, + smb_nbst_disconnect, + smb_nbst_send, + smb_nbst_recv, + smb_nbst_poll, + smb_nbst_getparam, + smb_nbst_setparam, + smb_nbst_fatal, + {NULL, NULL} +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2000-2001, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_trantcp.h,v 1.8 2004/08/03 23:50:01 lindak Exp $ + */ +#ifndef _NETSMB_SMB_TRANTCP_H_ +#define _NETSMB_SMB_TRANTCP_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +enum nbstate { + NBST_CLOSED, + NBST_RQSENT, + NBST_SESSION, + NBST_RETARGET, + NBST_REFUSED +}; + + +/* + * socket specific data + */ +struct nbpcb { + struct smb_vc *nbp_vc; + struct tiuser *nbp_tiptr; /* KTLI transport handle... */ + ushort_t nbp_fmode; + mblk_t *nbp_frag; /* left-over from last recv */ + + struct sockaddr_nb *nbp_laddr; /* local address */ + struct sockaddr_nb *nbp_paddr; /* peer address */ + + int nbp_flags; +#define NBF_LOCADDR 0x0001 /* has local addr */ +#define NBF_CONNECTED 0x0002 +#define NBF_RECVLOCK 0x0004 +#define NBF_UPCALLED 0x0010 + + enum nbstate nbp_state; + struct timespec nbp_timo; + int nbp_sndbuf; + int nbp_rcvbuf; + void *nbp_selectid; + kmutex_t nbp_lock; +}; +typedef struct nbpcb nbpcb_t; + +/* + * Nominal space allocated per a NETBIOS socket. + */ +#define NB_SNDQ (10 * 1024) +#define NB_RCVQ (20 * 1024) + +/* + * TCP slowstart presents a problem in conjunction with large + * reads. To ensure a steady stream of ACKs while reading using + * large transaction sizes, we call soreceive() with a smaller + * buffer size. See nbssn_recv(). + */ +#define NB_SORECEIVE_CHUNK (8 * 1024) + +#define SMBSBTIMO 15 /* seconds for sockbuf timeouts */ + +#endif /* !_NETSMB_SMB_TRANTCP_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2000-2001 Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_usr.c,v 1.15 2004/12/13 00:25:18 lindak Exp $ + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/kmem.h> +#include <sys/systm.h> +#include <sys/policy.h> +#include <sys/conf.h> +#include <sys/proc.h> +#include <sys/fcntl.h> +#include <sys/socket.h> +#include <sys/cmn_err.h> + +#ifdef APPLE +#include <sys/smb_apple.h> +#include <sys/smb_iconv.h> +#else +#include <netsmb/smb_osdep.h> +#endif + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_rq.h> +#include <netsmb/smb_subr.h> +#include <netsmb/smb_dev.h> + +/* + * helpers for nsmb device. Can be moved to the smb_dev.c file. + */ +static void smb_usr_vcspec_free(struct smb_vcspec *spec); + +/* + * Moved the access checks here, just becuase + * this was a more convenient place to do it + * than in every function calling this. + */ +static int +smb_usr_ioc2vcspec(struct smbioc_ossn *dp, struct smb_vcspec *spec) +{ + cred_t *cr = CRED(); + uid_t realuid; + + /* + * Only superuser can specify a UID or GID. + */ + realuid = crgetruid(cr); + if (dp->ioc_owner == SMBM_ANY_OWNER) + spec->owner = realuid; + else { + /* + * Do we have the privilege to create with the + * specified uid? (does uid == cr->cr_uid, etc.) + * MacOS would want suser(), or similar here. + */ + if (secpolicy_vnode_owner(cr, dp->ioc_owner)) + return (EPERM); + spec->owner = dp->ioc_owner; + } + if (dp->ioc_group == SMBM_ANY_GROUP) + spec->group = crgetgid(cr); + else { + /* + * Do we have the privilege to create with the + * specified gid? (one of our groups?) + */ + if (groupmember(dp->ioc_group, cr) || + secpolicy_vnode_create_gid(cr) == 0) + spec->group = dp->ioc_group; + else + return (EPERM); + } + + /* + * Valid codesets? XXX + */ + if (dp->ioc_localcs[0] == 0) { + spec->localcs = "ISO8859-1"; +#ifdef NOTYETRESOLVED + SMBERROR("no local charset ? dp->ioc_localcs[0]: %d\n", + dp->ioc_localcs[0]); + return (EINVAL); +#endif + } else + spec->localcs = spec->localcs; + + /* + * Check for valid sa_family. + * XXX: Just NetBIOS for now. + */ + if (dp->ioc_server.sa.sa_family != AF_NETBIOS) + return (EINVAL); + spec->sap = &dp->ioc_server.sa; + + if (dp->ioc_local.sa.sa_family) { + /* If specified, local AF must be the same. */ + if (dp->ioc_local.sa.sa_family != + dp->ioc_server.sa.sa_family) + return (EINVAL); + spec->lap = &dp->ioc_local.sa; + } + + if (dp->ioc_intok) { + spec->tok = smb_memdupin(dp->ioc_intok, dp->ioc_intoklen); + if (spec->tok == NULL) + return (EFAULT); + spec->toklen = dp->ioc_intoklen; + } + + spec->srvname = dp->ioc_srvname; + spec->pass = dp->ioc_password; + spec->domain = dp->ioc_workgroup; + spec->username = dp->ioc_user; + spec->mode = dp->ioc_mode; + spec->rights = dp->ioc_rights; + spec->servercs = dp->ioc_servercs; + spec->optflags = dp->ioc_opt; + + return (0); +} + +static void +smb_usr_shspec_free(struct smb_sharespec *sspec) +{ + kmem_free(sspec, sizeof (struct smb_sharespec)); +} + +static void +smb_usr_vcspec_free(struct smb_vcspec *spec) +{ + + if (spec->tok) { + kmem_free(spec->tok, spec->toklen); + } + kmem_free(spec, sizeof (*spec)); +} + +static int +smb_usr_ioc2sharespec(struct smbioc_oshare *dp, struct smb_sharespec *spec) +{ + bzero(spec, sizeof (*spec)); + spec->name = dp->ioc_share; + spec->pass = dp->ioc_password; + spec->mode = dp->ioc_mode; + spec->rights = dp->ioc_rights; + spec->owner = dp->ioc_owner; + spec->group = dp->ioc_group; + spec->stype = dp->ioc_stype; + spec->optflags = dp->ioc_opt; + return (0); +} + +int +smb_usr_negotiate(struct smbioc_lookup *dp, struct smb_cred *scred, + struct smb_vc **vcpp) +{ + struct smb_vc *vcp = NULL; + struct smb_vcspec *vspec = NULL; + struct smb_sharespec *sspecp = NULL; + int error = 0; + + if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE) + return (EINVAL); + vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP); + error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec); + if (error) + return (error); + if (dp->ioc_flags & SMBLK_CREATE) + vspec->optflags |= SMBVOPT_CREATE; + if (dp->ioc_level >= SMBL_SHARE) { + sspecp = kmem_alloc(sizeof (*sspecp), KM_SLEEP); + error = smb_usr_ioc2sharespec(&dp->ioc_sh, sspecp); + if (error) + goto out; + } + error = smb_sm_negotiate(vspec, scred, &vcp); + if (error == 0) { + *vcpp = vcp; + /* + * Used to copyout ioc_outtok, outtoklen here, + * but that's now in smb_dev. (our caller) + * + * If this call asked for extended security and + * the server does not support it, clear the + * flag so the caller knows this. + * + * XXX: Should just add sv_caps to ioc_ssn, + * set the new sv_caps field here, and let + * let the copyout of ioc_ssn handle it. + */ + if (!(vcp->vc_sopt.sv_caps & SMB_CAP_EXT_SECURITY) && + (dp->ioc_ssn.ioc_opt & SMBVOPT_EXT_SEC)) { + dp->ioc_ssn.ioc_opt &= ~SMBVOPT_EXT_SEC; + SMBSDEBUG("turned off extended security"); + } + } +out: + smb_usr_vcspec_free(vspec); + smb_usr_shspec_free(sspecp); + return (error); +} + +int +smb_usr_ssnsetup(struct smbioc_lookup *dp, struct smb_cred *scred, + struct smb_vc *vcp) +{ + struct smb_vcspec *vspec = NULL; + int error; + + if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE) + return (EINVAL); + + vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP); + error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec); + if (error) + goto out; + + error = smb_sm_ssnsetup(vspec, scred, vcp); + /* + * Moved the copyout of ioc_outtok to + * smb_dev.c (our caller) + */ + +out: + smb_usr_vcspec_free(vspec); + return (error); +} + + +int +smb_usr_tcon(struct smbioc_lookup *dp, struct smb_cred *scred, + struct smb_vc *vcp, struct smb_share **sspp) +{ + struct smb_sharespec *sspecp = NULL; + int error; + + if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE) + return (EINVAL); + + if (dp->ioc_level >= SMBL_SHARE) { + sspecp = kmem_alloc(sizeof (*sspecp), KM_SLEEP); + error = smb_usr_ioc2sharespec(&dp->ioc_sh, sspecp); + if (error) + goto out; + } + error = smb_sm_tcon(sspecp, scred, vcp, sspp); + +out: + if (sspecp) + smb_usr_shspec_free(sspecp); + + return (error); +} + +/* + * Connect to the resource specified by smbioc_ossn structure. + * It may either find an existing connection or try to establish a new one. + * If no errors occured smb_vc returned locked and referenced. + */ + +int +smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp, + struct smb_cred *scred) +{ + struct smb_rq rq, *rqp = &rq; + struct mbchain *mbp; + struct mdchain *mdp; + char *p; + size_t wc2; + u_int8_t wc; + u_int16_t bc; + int error; + + switch (dp->ioc_cmd) { + case SMB_COM_TRANSACTION2: + case SMB_COM_TRANSACTION2_SECONDARY: + case SMB_COM_CLOSE_AND_TREE_DISC: + case SMB_COM_TREE_CONNECT: + case SMB_COM_TREE_DISCONNECT: + case SMB_COM_NEGOTIATE: + case SMB_COM_SESSION_SETUP_ANDX: + case SMB_COM_LOGOFF_ANDX: + case SMB_COM_TREE_CONNECT_ANDX: + return (EPERM); + } + error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred); + if (error) + return (error); + mbp = &rqp->sr_rq; + smb_rq_wstart(rqp); + error = mb_put_mem(mbp, dp->ioc_twords, + dp->ioc_twc * 2, MB_MUSER); + if (error) + goto bad; + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + error = mb_put_mem(mbp, dp->ioc_tbytes, + dp->ioc_tbc, MB_MUSER); + if (error) + goto bad; + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + if (error) + goto bad; + mdp = &rqp->sr_rp; + md_get_uint8(mdp, &wc); + dp->ioc_rwc = wc; + wc2 = wc * 2; + if (wc2 > dp->ioc_rpbufsz) { + error = EBADRPC; + goto bad; + } + error = md_get_mem(mdp, dp->ioc_rpbuf, wc2, MB_MUSER); + if (error) + goto bad; + md_get_uint16le(mdp, &bc); + if ((wc2 + bc) > dp->ioc_rpbufsz) { + error = EBADRPC; + goto bad; + } + dp->ioc_rbc = bc; + p = dp->ioc_rpbuf; + error = md_get_mem(mdp, p + wc2, bc, MB_MUSER); +bad: + dp->ioc_errclass = rqp->sr_errclass; + dp->ioc_serror = rqp->sr_serror; + dp->ioc_error = rqp->sr_error; + smb_rq_done(rqp); + return (error); + +} + +static int +smb_cpdatain(struct mbchain *mbp, int len, char *data) +{ + int error; + + if (len == 0) + return (0); + error = mb_init(mbp); + if (error) + return (error); + return (mb_put_mem(mbp, data, len, MB_MUSER)); +} + +int +smb_usr_t2request(struct smb_share *ssp, smbioc_t2rq_t *dp, + struct smb_cred *scred) +{ + struct smb_t2rq t2, *t2p = &t2; + struct mdchain *mdp; + int error, len; + + if (dp->ioc_setupcnt > SMB_MAXSETUPWORDS) + return (EINVAL); + + t2p = (struct smb_t2rq *)kmem_alloc(sizeof (struct smb_t2rq), KM_SLEEP); + if (t2p == NULL) + return (ENOMEM); + error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup, dp->ioc_setupcnt, + scred); + if (error) + return (error); + len = t2p->t2_setupcount = dp->ioc_setupcnt; + if (len > 1) + t2p->t2_setupdata = dp->ioc_setup; + if (dp->ioc_name) { + bcopy(dp->ioc_name, t2p->t_name, 128); + if (t2p->t_name == NULL) { + error = ENOMEM; + goto bad; + } + } + t2p->t2_maxscount = 0; + t2p->t2_maxpcount = dp->ioc_rparamcnt; + t2p->t2_maxdcount = dp->ioc_rdatacnt; + error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt, + dp->ioc_tparam); + if (error) + goto bad; + error = smb_cpdatain(&t2p->t2_tdata, + dp->ioc_tdatacnt, dp->ioc_tdata); + if (error) + goto bad; + error = smb_t2_request(t2p); + dp->ioc_errclass = t2p->t2_sr_errclass; + dp->ioc_serror = t2p->t2_sr_serror; + dp->ioc_error = t2p->t2_sr_error; + dp->ioc_rpflags2 = t2p->t2_sr_rpflags2; + if (error) + goto bad; + mdp = &t2p->t2_rparam; + if (mdp->md_top) { + mblk_t *m = mdp->md_top; +#ifdef lint + m = m; +#endif + len = m_fixhdr(mdp->md_top); + if (len > dp->ioc_rparamcnt) { + error = EMSGSIZE; + goto bad; + } + dp->ioc_rparamcnt = (ushort_t)len; + error = md_get_mem(mdp, dp->ioc_rparam, + len, MB_MUSER); + if (error) { + goto bad; + } + } else + dp->ioc_rparamcnt = 0; + mdp = &t2p->t2_rdata; + if (mdp->md_top) { + mblk_t *m = mdp->md_top; +#ifdef lint + m = m; +#endif + len = m_fixhdr(mdp->md_top); + if (len > dp->ioc_rdatacnt) { + error = EMSGSIZE; + goto bad; + } + dp->ioc_rdatacnt = (ushort_t)len; + error = md_get_mem(mdp, dp->ioc_rdata, + len, MB_MUSER); + if (error) { + goto bad; + } + } else + dp->ioc_rdatacnt = 0; +bad: + smb_t2_done(t2p); + return (error); +} + +/* + * Helper for nsmb_ioctl cases + * SMBIOC_READ, SMBIOC_WRITE + */ +int +smb_usr_rw(struct smb_share *ssp, smbioc_rw_t *rwrq, + int cmd, struct smb_cred *scred) +{ + struct iovec aiov[1]; + struct uio auio; + u_int16_t fh; + int error; + uio_rw_t rw; + + switch (cmd) { + case SMBIOC_READ: + rw = UIO_READ; + break; + case SMBIOC_WRITE: + rw = UIO_WRITE; + break; + default: + return (ENODEV); + } + + fh = htoles(rwrq->ioc_fh); + + aiov[0].iov_base = rwrq->ioc_base; + aiov[0].iov_len = (size_t)rwrq->ioc_cnt; + + auio.uio_iov = aiov; + auio.uio_iovcnt = 1; + auio.uio_loffset = rwrq->ioc_offset; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_fmode = 0; + auio.uio_resid = (size_t)rwrq->ioc_cnt; + + error = smb_rwuio(ssp, fh, rw, &auio, scred, 0); + + /* + * On return ioc_cnt holds the + * number of bytes transferred. + */ + rwrq->ioc_cnt -= auio.uio_resid; + + return (error); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,990 @@ +/* + * 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. + * + * $FreeBSD: src/sys/kern/subr_mchain.c,v 1.1 2001/02/24 15:44:29 bp Exp $ + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/uio.h> +#include <sys/types.h> +#include <sys/stream.h> +#include <sys/strsun.h> +#include <sys/strsubr.h> +#include <sys/cmn_err.h> + +#ifdef APPLE +#include <sys/smb_apple.h> +#else +#include <netsmb/smb_osdep.h> +#endif + +#include <netsmb/mchain.h> + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> + +/* BEGIN CSTYLED */ +/* + * BSD-style mbufs, vs SysV-style mblks: + * One big difference: the mbuf payload is: + * m_data ... (m_data + m_len) + * In Unix STREAMS, the mblk payload is: + * b_rptr ... b_wptr + * + * Here are some handy conversion notes: + * + * struct mbuf struct mblk + * m->m_next m->b_cont + * m->m_nextpkt m->b_next + * m->m_data m->b_rptr + * m->m_len MBLKL(m) + * m->m_dat[] m->b_datap->db_base + * &m->m_dat[MLEN] m->b_datap->db_lim + * M_TRAILINGSPACE(m) MBLKTAIL(m) + * m_freem(m) freemsg(m) + * + * Note that mbufs chains also have a special "packet" header, + * which has the length of the whole message. In STREAMS one + * typically just calls msgdsize(m) to get that. + */ +/* END CSTYLED */ + + +/* + * + * MODULE_VERSION(libmchain, 1); + */ + +#ifdef __GNUC__ +#define MBERROR(format, args...) printf("%s(%d): "format, \ + __FUNCTION__, __LINE__, ## args) +#define MBPANIC(format, args...) printf("%s(%d): "format, \ + __FUNCTION__, __LINE__, ## args) +#else +#define MBERROR(...) \ + smb_errmsg(CE_NOTE, __func__, __VA_ARGS__) +#define MBPANIC(...) \ + smb_errmsg(CE_PANIC, __func__, __VA_ARGS__) +#endif + +/* + * MLEN: The smallest mblk we'll allocate. + * + * There's more to MLEN than you might think. + * Some ethernet drivers may send each mblk as a + * separate frame, so we want MLEN at least 1K. + * We could have used 1K here, but that might + * hurt transports that support larger frames. + * 4K fits nicely in 3 Ethernet frames (3 * 1500) + * leaving about 500 bytes for protocol headers. + * + * XXX: Would Ethernet drivers be happier + * (more efficient) if we used 1K here? + */ +#define MLEN 4096 + + +/* + * Some UIO routines. + * Taken from Darwin Sourcecs. + */ + +/* + * uio_isuserspace - return non zero value if the address space + * flag is for a user address space (could be 32 or 64 bit). + */ +int +uio_isuserspace(uio_t *a_uio) +{ + if (a_uio->uio_segflg == UIO_USERSPACE) { + return (1); + } + return (0); +} + +/* + * uio_curriovbase - return the base address of the current iovec associated + * with the given uio_t. May return 0. + */ +caddr_t +uio_curriovbase(uio_t *a_uio) +{ + if (a_uio->uio_iovcnt < 1) { + return (0); + } + return ((caddr_t)((uintptr_t)a_uio->uio_iov->iov_base)); +} + +/* + * uio_curriovlen - return the length value of the current iovec associated + * with the given uio_t. + */ +size_t +uio_curriovlen(uio_t *a_uio) +{ + if (a_uio->uio_iovcnt < 1) { + return (0); + } + return ((size_t)a_uio->uio_iov->iov_len); +} + + +/* + * uio_update - update the given uio_t for a_count of completed IO. + * This call decrements the current iovec length and residual IO value + * and increments the current iovec base address and offset value. + * If the current iovec length is 0 then advance to the next + * iovec (if any). + * If the a_count passed in is 0, than only do the advancement + * over any 0 length iovec's. + */ +void +uio_update(uio_t *a_uio, size_t a_count) +{ + if (a_uio->uio_iovcnt < 1) { + return; + } + + /* + * if a_count == 0, then we are asking to skip over + * any empty iovs + */ + if (a_count) { + if (a_count > a_uio->uio_iov->iov_len) { + a_uio->uio_iov->iov_base += a_uio->uio_iov->iov_len; + a_uio->uio_iov->iov_len = 0; + } else { + a_uio->uio_iov->iov_base += a_count; + a_uio->uio_iov->iov_len -= a_count; + } + if (a_uio->uio_resid < 0) { + a_uio->uio_resid = 0; + } + if (a_count > (size_t)a_uio->uio_resid) { + a_uio->uio_offset += a_uio->uio_resid; + a_uio->uio_resid = 0; + } else { + a_uio->uio_offset += a_count; + a_uio->uio_resid -= a_count; + } + } + /* + * advance to next iovec if current one is totally consumed + */ + while (a_uio->uio_iovcnt > 0 && a_uio->uio_iov->iov_len == 0) { + a_uio->uio_iovcnt--; + if (a_uio->uio_iovcnt > 0) { + a_uio->uio_iov++; + } + } +} + + +/*ARGSUSED*/ +mblk_t * +m_getblk(int size, int type) +{ + mblk_t *mblk; + int error; + + /* Make size at least MLEN. */ + if (size < MLEN) + size = MLEN; + mblk = allocb_wait(size, BPRI_LO, STR_NOSIG, &error); + ASSERT(mblk); + return (mblk); +} + +void +mb_done(struct mbchain *mbp) +{ + if (mbp->mb_top) { + freemsg(mbp->mb_top); + mbp->mb_top = NULL; + } + /* Avoid dangling references */ + mbp->mb_cur = NULL; +} + +unsigned int +m_length(mblk_t *mblk) +{ + uint64_t diff; + + diff = (uintptr_t)mblk->b_datap->db_lim - + (uintptr_t)mblk->b_datap->db_base; + ASSERT(diff == (uint64_t)((unsigned int)diff)); + return ((unsigned int)diff); +} + +void +mb_initm(struct mbchain *mbp, mblk_t *m) +{ + bzero(mbp, sizeof (*mbp)); + mbp->mb_top = mbp->mb_cur = m; +} + + +int +mb_init(struct mbchain *mbp) +{ + mblk_t *mblk; + + mblk = m_getblk(MLEN, 1); + if (mblk == NULL) { + return (ENOSR); + } + + /* + * Leave room in this first mblk so we can + * prepend a 4-byte NetBIOS header. + * See smb_nbst_send() + */ + mblk->b_wptr += 4; + mblk->b_rptr = mblk->b_wptr; + + mb_initm(mbp, mblk); + return (0); +} + + +/* + * mb_detach() function returns the value of mbp->mb_top field + * and sets its * value to NULL. + */ + +mblk_t * +mb_detach(struct mbchain *mbp) +{ + mblk_t *m; + + m = mbp->mb_top; + mbp->mb_top = mbp->mb_cur = NULL; + return (m); +} + +/* + * Returns the length of the mblk_t data. + * + */ +int +m_fixhdr(mblk_t *m0) +{ + size_t dsz; + + dsz = msgdsize(m0); + return ((int)dsz); +} + +/* + * BSD code set the message header length here, and + * returned the length. We don't have that field, so + * just return the message length. + */ +int +mb_fixhdr(struct mbchain *mbp) +{ + return (m_fixhdr(mbp->mb_top)); +} + + +/* + * Check if object of size 'size' fit to the current position and + * allocate new mbuf if not. Advance pointers and increase len. of mbuf(s). + * Return pointer to the object placeholder or NULL if any error occured. + * Note: size should be <= MLEN + */ +void * +mb_reserve(struct mbchain *mbp, int size) +{ + mblk_t *m, *mn; + void *bpos; + + m = mbp->mb_cur; + /* + * If the requested size is more than the space left. + * Allocate and appenad a new mblk. + */ + /*LINTED*/ + if (MBLKTAIL(m) < size) { + mn = m_getblk(size, 1); + if (mn == NULL) + return (NULL); + mbp->mb_cur = m->b_cont = mn; + m = mn; + } + /* + * If 'size' bytes fits into the buffer, then + * 1. increment the write pointer to the size. + * 2. return the position from where the memory is reserved. + */ + bpos = m->b_wptr; + m->b_wptr += size; + mbp->mb_count += size; + return (bpos); +} + +/* + * All mb_put_*() functions perform an actual copy of the data into mbuf + * chain. Functions which have le or be suffixes will perform conversion to + * the little- or big-endian data formats. + * XXX: Assumes total data length in previous mblks is EVEN. + * XXX: Might need to compute the offset from mb_top instead. + */ +int +mb_put_padbyte(struct mbchain *mbp) +{ + caddr_t dst; + char x = 0; + + dst = (caddr_t)mbp->mb_cur->b_wptr; + + /* only add padding if address is odd */ + if ((long)dst & 1) + return (mb_put_mem(mbp, (caddr_t)&x, 1, MB_MSYSTEM)); + else + return (0); +} + +int +mb_put_uint8(struct mbchain *mbp, u_int8_t x) +{ + return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM)); +} + +int +mb_put_uint16be(struct mbchain *mbp, u_int16_t x) +{ + x = htobes(x); + return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM)); +} + +int +mb_put_uint16le(struct mbchain *mbp, u_int16_t x) +{ + x = htoles(x); + return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM)); +} + +int +mb_put_uint32be(struct mbchain *mbp, u_int32_t x) +{ + x = htobel(x); + return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM)); +} + +int +mb_put_uint32le(struct mbchain *mbp, u_int32_t x) +{ + x = htolel(x); + return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM)); +} + +int +mb_put_uint64be(struct mbchain *mbp, u_int64_t x) +{ + x = htobeq(x); + return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM)); +} + +int +mb_put_uint64le(struct mbchain *mbp, u_int64_t x) +{ + x = htoleq(x); + return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM)); +} + +/* + * mb_put_mem() function copies size bytes of data specified by the source + * argument to an mbuf chain. The type argument specifies the method used + * to perform a copy + */ +int +mb_put_mem(struct mbchain *mbp, c_caddr_t source, int size, int type) +{ + mblk_t *m, *n; + caddr_t dst; + c_caddr_t src; + int cplen, error, mleft, count; + uint64_t diff; + + m = mbp->mb_cur; + + /*LINTED*/ + diff = MBLKTAIL(m); + ASSERT(diff == (uint64_t)((int)diff)); + mleft = (int)diff; + + while (size > 0) { + if (mleft == 0) { + if (m->b_cont == NULL) { + /* + * Changed m_getm() to m_getblk() + * with the requested size, so we + * don't need m_getm() anymore. + */ + n = m_getblk(size, 1); + if (n == NULL) + return (ENOBUFS); + m->b_cont = n; + } + m = m->b_cont; + /*LINTED*/ + diff = MBLKTAIL(m); + ASSERT(diff == (uint64_t)((int)diff)); + mleft = (int)diff; + continue; + } + cplen = mleft > size ? size : mleft; + dst = (caddr_t)m->b_wptr; + switch (type) { + case MB_MINLINE: + for (src = source, count = cplen; count; count--) + *dst++ = *src++; + break; + case MB_MSYSTEM: + /* + * Try copying the raw bytes instead of using bcopy() + */ + bcopy(source, dst, cplen); + break; + case MB_MUSER: + error = copyin((void *)source, dst, cplen); + if (error) + return (error); + break; + case MB_MZERO: + bzero(dst, cplen); + break; + } + size -= cplen; + source += cplen; + mleft -= cplen; + m->b_wptr += cplen; + mbp->mb_count += cplen; + } + mbp->mb_cur = m; + return (0); +} + +/* + * Append an mblk to the chain. + */ +int +mb_put_mbuf(struct mbchain *mbp, mblk_t *m) +{ + mblk_t *mb; + + /* See: linkb(9f) */ + for (mb = mbp->mb_cur; mb->b_cont; mb = mb->b_cont) + ; + mb->b_cont = m; + mbp->mb_cur = m; + mbp->mb_count += msgdsize(m); + + return (0); +} + +/* + * copies a uio scatter/gather list to an mbuf chain. + */ +int +mb_put_uio(struct mbchain *mbp, uio_t *uiop, int size) +{ + int left; + int mtype, error; + + mtype = (uio_isuserspace(uiop) ? MB_MUSER : MB_MSYSTEM); + + while (size > 0 && uiop->uio_resid) { + if (uiop->uio_iovcnt <= 0 || uio_curriovbase(uiop) == + USER_ADDR_NULL) + return (EFBIG); + left = uio_curriovlen(uiop); + if (left > size) + left = size; + error = mb_put_mem(mbp, CAST_DOWN(caddr_t, + uio_curriovbase(uiop)), left, mtype); + if (error) + return (error); + uio_update(uiop, left); + size -= left; + } + return (0); +} + +/* + * Routines for fetching data from an mbuf chain + */ +int +md_init(struct mdchain *mdp) +{ + mblk_t *m; + + m = m_getblk(MLEN, 1); + if (m == NULL) + return (ENOBUFS); + md_initm(mdp, m); + return (0); +} + +void +md_initm(struct mdchain *mdp, mblk_t *m) +{ + bzero(mdp, sizeof (*mdp)); + mdp->md_top = mdp->md_cur = m; + mdp->md_pos = m->b_rptr; +} + +void +md_done(struct mdchain *mdp) +{ + mblk_t *m; + + /* + * Deal with the fact that we can error out of + * smb_t2_reply or smb_nt_reply without using up + * all the "records" added by md_append_record(). + */ + while ((m = mdp->md_top) != NULL) { + mdp->md_top = m->b_next; + m->b_next = NULL; + freemsg(m); + } + /* Avoid dangling references */ + mdp->md_cur = NULL; + mdp->md_pos = NULL; +} + +/* + * Append a new message (separate mbuf chain). + * It is caller responsibility to prevent + * multiple calls to fetch/record routines. + * XXX: Note (mis)use of mblk->b_next here. + */ +void +md_append_record(struct mdchain *mdp, mblk_t *top) +{ + mblk_t *m; + + top->b_next = NULL; + if (mdp->md_top == NULL) { + md_initm(mdp, top); + return; + } + m = mdp->md_top; + /* Get to last message (not b_cont chain) */ + while (m->b_next) + m = m->b_next; + m->b_next = top; +} + +/* + * Advance mdp->md_top to the next message. + * XXX: Note (mis)use of mblk->b_next here. + */ +int +md_next_record(struct mdchain *mdp) +{ + mblk_t *m; + + if (mdp->md_top == NULL) + return (ENOENT); + /* Get to next message (not b_cont chain) */ + m = mdp->md_top->b_next; + mdp->md_top->b_next = NULL; + md_done(mdp); + if (m == NULL) + return (ENOENT); + md_initm(mdp, m); + return (0); +} + +int +md_get_uint8(struct mdchain *mdp, u_int8_t *x) +{ + return (md_get_mem(mdp, (char *)x, 1, MB_MINLINE)); +} + +int +md_get_uint16(struct mdchain *mdp, u_int16_t *x) +{ + return (md_get_mem(mdp, (char *)x, 2, MB_MINLINE)); +} + +int +md_get_uint16le(struct mdchain *mdp, u_int16_t *x) +{ + u_int16_t v; + int error = md_get_uint16(mdp, &v); + + if (x) + *x = letohs(v); + return (error); +} + +int +md_get_uint16be(struct mdchain *mdp, u_int16_t *x) { + u_int16_t v; + int error = md_get_uint16(mdp, &v); + + if (x) + *x = betohs(v); + return (error); +} + +int +md_get_uint32(struct mdchain *mdp, u_int32_t *x) +{ + return (md_get_mem(mdp, (caddr_t)x, 4, MB_MINLINE)); +} + +int +md_get_uint32be(struct mdchain *mdp, u_int32_t *x) +{ + u_int32_t v; + int error; + + error = md_get_uint32(mdp, &v); + if (x) + *x = betohl(v); + return (error); +} + +int +md_get_uint32le(struct mdchain *mdp, u_int32_t *x) +{ + u_int32_t v; + int error; + + error = md_get_uint32(mdp, &v); + if (x) + *x = letohl(v); + return (error); +} + +int +md_get_uint64(struct mdchain *mdp, u_int64_t *x) +{ + return (md_get_mem(mdp, (caddr_t)x, 8, MB_MINLINE)); +} + +int +md_get_uint64be(struct mdchain *mdp, u_int64_t *x) +{ + u_int64_t v; + int error; + + error = md_get_uint64(mdp, &v); + if (x) + *x = betohq(v); + return (error); +} + +int +md_get_uint64le(struct mdchain *mdp, u_int64_t *x) +{ + u_int64_t v; + int error; + + error = md_get_uint64(mdp, &v); + if (x) + *x = letohq(v); + return (error); +} + +int +md_get_mem(struct mdchain *mdp, caddr_t target, int size, int type) +{ + mblk_t *m = mdp->md_cur; + int error; + int count; + unsigned char *s; + uint64_t diff; + + while (size > 0) { + if (m == NULL) { + SMBSDEBUG("incomplete copy\n"); + return (EBADRPC); + } + + /* + * Offset in the current MBUF. + */ + s = mdp->md_pos; + ASSERT((m->b_rptr <= s) && (s <= m->b_wptr)); + + /* Data remaining. */ + diff = (uintptr_t)m->b_wptr - (uintptr_t)s; + ASSERT(diff == (uint64_t)((int)diff)); + count = (int)diff; + + /* + * Check if the no. of bytes remaining is less than + * the bytes requested. + */ + if (count == 0) { + m = m->b_cont; + if (m) { + mdp->md_cur = m; + mdp->md_pos = s = m->b_rptr; + } + continue; + } + if (count > size) + count = size; + size -= count; + mdp->md_pos += count; + if (target == NULL) + continue; + switch (type) { + case MB_MUSER: + error = copyout(s, (void *)target, count); + if (error) + return (error); + break; + case MB_MSYSTEM: + bcopy(s, target, count); + break; + case MB_MINLINE: + while (count--) + *target++ = *s++; + continue; + } + target += count; + } + return (0); +} + +/* + * Get the next SIZE bytes as a separate mblk. + */ +int +md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret) +{ + mblk_t *m, *rm; + + unsigned char *s; + uint64_t diff; + int off; + + /* + * Offset in the current MBUF. + */ + m = mdp->md_cur; + s = mdp->md_pos; + ASSERT((m->b_rptr <= s) && (s <= m->b_wptr)); + diff = (uintptr_t)s - (uintptr_t)m->b_rptr; + ASSERT(diff == (uint64_t)((int)diff)); + off = (int)diff; + + rm = m_copym(m, off, size, M_WAITOK); + if (rm == NULL) + return (EBADRPC); + + *ret = rm; + return (0); +} + +int +md_get_uio(struct mdchain *mdp, uio_t *uiop, int size) +{ + size_t left; + int mtype, error; + + mtype = (uio_isuserspace(uiop) ? MB_MUSER : MB_MSYSTEM); + while (size > 0 && uiop->uio_resid) { + if (uiop->uio_iovcnt <= 0 || + uio_curriovbase(uiop) == USER_ADDR_NULL) + return (EFBIG); + left = uio_curriovlen(uiop); + if (left > size) + left = size; + error = md_get_mem(mdp, CAST_DOWN(caddr_t, + uio_curriovbase(uiop)), left, mtype); + if (error) + return (error); + uio_update(uiop, left); + size -= left; + } + return (0); +} + +/* + * Additions for Solaris + */ + +/* + * concatenate mblk chain n to m. + * go till end of data in m. + * then add the link of b_cont to n. + * See: linkb(9f) + */ + +void m_cat( + mblk_t *m, + mblk_t *n) +{ + if (!n) + return; + while (m->b_cont) { + m = m->b_cont; + } + m->b_cont = n; +} + +/*ARGSUSED*/ +mblk_t * +m_copym(mblk_t *m, int off, int len, int wait) +{ + mblk_t *n; + size_t dsz; + ssize_t adj; + + dsz = msgdsize(m); + if (len == M_COPYALL) { + if (off > dsz) + return (0); + } else { + if ((off + len) > dsz) + return (0); + } + + if ((n = dupmsg(m)) == NULL) + return (0); + + /* trim from head */ + adj = off; + if (!adjmsg(n, adj)) { + freemsg(n); + return (0); + } + + /* trim from tail */ + if (len != M_COPYALL) { + dsz = msgdsize(n); + ASSERT(len <= dsz); + if (len < dsz) { + adj = (ssize_t)len - (ssize_t)dsz; + ASSERT(adj < 0); + adjmsg(n, adj); + } + } + + return (n); +} + +/* + * Get "rqlen" contiguous bytes into the first mblk of a chain. + */ +mblk_t * +m_pullup( + mblk_t *m, + int rqlen) +{ + ptrdiff_t diff; + + /*LINTED*/ + diff = MBLKL(m); + ASSERT(diff == (ptrdiff_t)((int)diff)); + if ((int)diff < rqlen) { + /* This should be rare. */ + if (!pullupmsg(m, rqlen)) { + SMBSDEBUG("pullupmsg failed!\n"); + freemsg(m); + return (NULL); + } + } + return (m); +} + + +/* + * m_split : split the mblk from the offset(len0) to the end. + * Partition an mbuf chain in two pieces, returning the tail -- + * all but the first len0 bytes. In case of failure, it returns NULL and + * attempts to restore the chain to its original state. + * Similar to dupmsg() + adjmsg() on Solaris. + */ +/*ARGSUSED*/ +mblk_t * +m_split( + mblk_t *m0, + int len0, + int wait) +{ + mblk_t *m, *n; + int mbl, len = len0; + ptrdiff_t diff; + +#if 0 /* If life were simple, this would be: */ + for (m = m0; m && len > MBLKL(m); m = m->b_cont) + len -= MBLKL(m); +#else /* but with LP64 and picky lint we have: */ + for (m = m0; m; m = m->b_cont) { + /*LINTED*/ + diff = MBLKL(m); + ASSERT(diff == (ptrdiff_t)((int)diff)); + mbl = (int)diff; + if (len <= mbl) + break; + len -= mbl; + } +#endif + + if (m == 0) + return (0); + + /* This is the one to split (dupb, adjust) */ + if ((n = dupb(m)) == 0) + return (0); + + /*LINTED*/ + ASSERT(len <= MBLKL(m)); + + m->b_wptr = m->b_rptr + len; + n->b_rptr += len; + + /* Move any b_cont (tail) to the new head. */ + n->b_cont = m->b_cont; + m->b_cont = NULL; + + return (n); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,136 @@ +/* + * 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: smbfs.h,v 1.30.100.1 2005/05/27 02:35:28 lindak Exp $ + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SMBFS_SMBFS_H +#define _SMBFS_SMBFS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * FS-specific VFS structures for smbfs. + * (per-mount stuff, etc.) + * + * This file used to have mount args stuff, + * but that's now in sys/fs/smbfs_mount.h + */ + +#include <sys/list.h> +#include <sys/vfs.h> +#include <sys/fs/smbfs_mount.h> + + +/* + * SM_MAX_STATFSTIME is the maximum time to cache statvfs data. Since this + * should be a fast call on the server, the time the data cached is short. + * That lets the cache handle bursts of statvfs() requests without generating + * lots of network traffic. + */ +#define SM_MAX_STATFSTIME 2 + +/* Mask values for smbmount structure sm_status field */ +#define SM_STATUS_STATFS_BUSY 0x00000001 /* statvfs is in progress */ +#define SM_STATUS_STATFS_WANT 0x00000002 /* statvfs wakeup is wanted */ +#define SM_STATUS_TIMEO 0x00000004 /* this mount is not responding */ +#define SM_STATUS_DEAD 0x00000010 /* connection gone - unmount this */ + +extern const struct fs_operation_def smbfs_vnodeops_template[]; +extern struct vnodeops *smbfs_vnodeops; + +struct smbnode; +struct smb_share; + +/* + * The values for smi_flags. + */ +#define SMI_INT 0x01 /* interrupts allowed */ +#define SMI_DEAD 0x02 /* zone shutting down */ +#define SMI_LLOCK 0x80 /* local locking only */ + +/* + * Corresponds to Darwin: struct smbmount + */ +typedef struct smbmntinfo { + struct vfs *smi_vfsp; /* mount back pointer to vfs */ + struct smbnode *smi_root; /* the root node */ + struct smb_share *smi_share; /* netsmb SMB share conn data */ + kmutex_t smi_lock; /* mutex for flags, etc. */ + uint32_t smi_flags; /* NFS-derived flag bits */ + uint32_t smi_fsattr; /* acls & streams opts */ + uint32_t smi_status; /* status bits for this mount */ + hrtime_t smi_statfstime; /* sm_statvfsbuf cache time */ + statvfs64_t smi_statvfsbuf; /* cached statvfs data */ + kcondvar_t smi_statvfs_cv; + + /* + * Kstat statistics + */ + struct kstat *smi_io_kstats; + struct kstat *smi_ro_kstats; + + /* + * Zones support. + */ + struct zone *smi_zone; /* Zone mounted in */ + list_node_t smi_zone_node; /* Link to per-zone smi list */ + /* Lock for the list is: smi_globals_t -> smg_lock */ + + /* + * Copy of the args from mount. + */ + struct smbfs_args smi_args; +} smbmntinfo_t; + +typedef struct smbfattr { + int fa_attr; + len_t fa_size; + struct timespec fa_atime; + struct timespec fa_ctime; + struct timespec fa_mtime; + ino64_t fa_ino; + struct timespec fa_reqtime; +} smbfattr_t; + +/* + * vnode pointer to mount info + */ +#define VTOSMI(vp) ((smbmntinfo_t *)(((vp)->v_vfsp)->vfs_data)) +#define VFTOSMI(vfsp) ((smbmntinfo_t *)((vfsp)->vfs_data)) +#define SMBINTR(vp) (VTOSMI(vp)->smi_flags & SMI_INT) + +#endif /* _SMBFS_SMBFS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,288 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/thread.h> +#include <sys/t_lock.h> +#include <sys/time.h> +#include <sys/vnode.h> +#include <sys/vfs.h> +#include <sys/errno.h> +#include <sys/buf.h> +#include <sys/stat.h> +#include <sys/cred.h> +#include <sys/kmem.h> +#include <sys/debug.h> +#include <sys/dnlc.h> +#include <sys/vmsystm.h> +#include <sys/flock.h> +#include <sys/share.h> +#include <sys/cmn_err.h> +#include <sys/tiuser.h> +#include <sys/sysmacros.h> +#include <sys/callb.h> +#include <sys/acl.h> +#include <sys/kstat.h> +#include <sys/signal.h> +#include <sys/list.h> +#include <sys/zone.h> + +#include <netsmb/smb_conn.h> + +#include <smbfs/smbfs.h> +#include <smbfs/smbfs_node.h> +#include <smbfs/smbfs_subr.h> + +#include <vm/hat.h> +#include <vm/as.h> +#include <vm/page.h> +#include <vm/pvn.h> +#include <vm/seg.h> +#include <vm/seg_map.h> +#include <vm/seg_vn.h> + +/* + * The following code provide zone support in order to perform an action + * for each smbfs mount in a zone. This is also where we would add + * per-zone globals and kernel threads for the smbfs module (since + * they must be terminated by the shutdown callback). + */ + +struct smi_globals { + kmutex_t smg_lock; /* lock protecting smg_list */ + list_t smg_list; /* list of SMBFS mounts in zone */ + boolean_t smg_destructor_called; +}; +typedef struct smi_globals smi_globals_t; + +static zone_key_t smi_list_key; + +/* ARGSUSED */ +static void * +smbfs_zone_init(zoneid_t zoneid) +{ + smi_globals_t *smg; + + smg = kmem_alloc(sizeof (*smg), KM_SLEEP); + mutex_init(&smg->smg_lock, NULL, MUTEX_DEFAULT, NULL); + list_create(&smg->smg_list, sizeof (smbmntinfo_t), + offsetof(smbmntinfo_t, smi_zone_node)); + smg->smg_destructor_called = B_FALSE; + return (smg); +} + +/* + * Callback routine to tell all SMBFS mounts in the zone to stop creating new + * threads. Existing threads should exit. + */ +/* ARGSUSED */ +static void +smbfs_zone_shutdown(zoneid_t zoneid, void *data) +{ + smi_globals_t *smg = data; + smbmntinfo_t *smi; + + ASSERT(smg != NULL); +again: + mutex_enter(&smg->smg_lock); + for (smi = list_head(&smg->smg_list); smi != NULL; + smi = list_next(&smg->smg_list, smi)) { + + /* + * If we've done the shutdown work for this FS, skip. + * Once we go off the end of the list, we're done. + */ + if (smi->smi_flags & SMI_DEAD) + continue; + + /* + * We will do work, so not done. Get a hold on the FS. + */ + VFS_HOLD(smi->smi_vfsp); + + /* + * purge the DNLC for this filesystem + */ + (void) dnlc_purge_vfsp(smi->smi_vfsp, 0); + + mutex_enter(&smi->smi_lock); + smi->smi_flags |= SMI_DEAD; + mutex_exit(&smi->smi_lock); + + /* + * Drop lock and release FS, which may change list, then repeat. + * We're done when every mi has been done or the list is empty. + */ + mutex_exit(&smg->smg_lock); + VFS_RELE(smi->smi_vfsp); + goto again; + } + mutex_exit(&smg->smg_lock); +} + +static void +smbfs_zone_free_globals(smi_globals_t *smg) +{ + list_destroy(&smg->smg_list); /* makes sure the list is empty */ + mutex_destroy(&smg->smg_lock); + kmem_free(smg, sizeof (*smg)); + +} + +/* ARGSUSED */ +static void +smbfs_zone_destroy(zoneid_t zoneid, void *data) +{ + smi_globals_t *smg = data; + + ASSERT(smg != NULL); + mutex_enter(&smg->smg_lock); + if (list_head(&smg->smg_list) != NULL) { + /* Still waiting for VFS_FREEVFS() */ + smg->smg_destructor_called = B_TRUE; + mutex_exit(&smg->smg_lock); + return; + } + smbfs_zone_free_globals(smg); +} + +/* + * Add an SMBFS mount to the per-zone list of SMBFS mounts. + */ +void +smbfs_zonelist_add(smbmntinfo_t *smi) +{ + smi_globals_t *smg; + + smg = zone_getspecific(smi_list_key, smi->smi_zone); + mutex_enter(&smg->smg_lock); + list_insert_head(&smg->smg_list, smi); + mutex_exit(&smg->smg_lock); +} + +/* + * Remove an SMBFS mount from the per-zone list of SMBFS mounts. + */ +void +smbfs_zonelist_remove(smbmntinfo_t *smi) +{ + smi_globals_t *smg; + + smg = zone_getspecific(smi_list_key, smi->smi_zone); + mutex_enter(&smg->smg_lock); + list_remove(&smg->smg_list, smi); + /* + * We can be called asynchronously by VFS_FREEVFS() after the zone + * shutdown/destroy callbacks have executed; if so, clean up the zone's + * smi_globals. + */ + if (list_head(&smg->smg_list) == NULL && + smg->smg_destructor_called == B_TRUE) { + smbfs_zone_free_globals(smg); + return; + } + mutex_exit(&smg->smg_lock); +} + + +#ifdef NEED_SMBFS_CALLBACKS +/* + * Call-back hooks for netsmb, in case we want them. + * Apple's VFS wants them. We may not need them. + * + * I thought I could use the "dead" callback from netsmb + * to set the SMI_DEAD flag, but that looks like it will + * interfere with the zone shutdown mechanisms. + */ +static void smbfs_dead(smb_share_t *ssp) +{ +#if 0 /* see above */ + smbmntinfo_t *smi = ssp->ss_mount; + if (smi) { + mutex_enter(&smi->smi_lock); + smi->smi_flags |= SMI_DEAD; + mutex_exit(&smi->smi_lock); + } +#endif +} + +static void smbfs_down(smb_share_t *ss) +{ + /* no-op */ +} + +static void smbfs_up(smb_share_t *ss) +{ + /* no-op */ +} + +smb_fscb_t smbfs_cb = { + .fscb_dead = smbfs_dead, + .fscb_down = smbfs_down, + .fscb_up = smbfs_up }; + +#endif /* NEED_SMBFS_CALLBACKS */ + +/* + * SMBFS Client initialization routine. This routine should only be called + * once. It performs the following tasks: + * - Initalize all global locks + * - Call sub-initialization routines (localize access to variables) + */ +int +smbfs_clntinit(void) +{ + int error; + + error = smbfs_subrinit(); + if (error) + return (error); + zone_key_create(&smi_list_key, smbfs_zone_init, smbfs_zone_shutdown, + smbfs_zone_destroy); +#ifdef NEED_SMBFS_CALLBACKS + smb_fscb_set(&smbfs_cb); +#endif /* NEED_SMBFS_CALLBACKS */ + return (0); +} + +/* + * This routine is called when the modunload is called. This will cleanup + * the previously allocated/initialized nodes. + */ +void +smbfs_clntfini(void) +{ +#ifdef NEED_SMBFS_CALLBACKS + smb_fscb_set(NULL); +#endif /* NEED_SMBFS_CALLBACKS */ + (void) zone_key_delete(smi_list_key); + smbfs_subrfini(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_io.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,206 @@ +/* + * 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: smbfs_io.c,v 1.41.38.1 2005/05/27 02:35:28 lindak Exp $ + * + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/vnode.h> +#include <sys/proc.h> +#include <sys/fcntl.h> +#include <sys/mount.h> +#include <sys/dirent.h> +#include <sys/syslog.h> +#include <sys/file.h> + +#ifdef APPLE +#include <sys/smb_apple.h> +#else +#include <netsmb/smb_osdep.h> +#endif + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> + +#include <smbfs/smbfs.h> +#include <smbfs/smbfs_node.h> +#include <smbfs/smbfs_subr.h> + +/* XXX: This file should go away, after more work in _vnops.c */ + +int +smbfs_readvnode(vnode_t *vp, uio_t *uiop, cred_t *cr, + struct vattr *vap) +{ + smbmntinfo_t *smp = VTOSMI(vp); + struct smbnode *np = VTOSMB(vp); + struct smb_cred scred; + int error; + int requestsize; + size_t remainder; + + /* shared lock for n_fid use in smb_rwuio */ + ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); + + if (vp->v_type != VREG) { + SMBVDEBUG("only VREG supported\n"); + return (EIO); + } + if (uiop->uio_resid == 0) + return (0); + if (uiop->uio_loffset < 0) + return (EINVAL); +#ifdef NOT_YET + if ((uiop->uio_loffset + uiop->uio_resid) > smp->nm_maxfilesize) + return (EFBIG); +#endif + + smb_credinit(&scred, curproc, cr); + + /* XXX: Update n_size maybe? */ + (void) smbfs_smb_flush(np, &scred); + + if (uiop->uio_loffset >= vap->va_size) { + /* if offset is beyond EOF, read nothing */ + error = 0; + goto out; + } + + /* pin requestsize to EOF */ + requestsize = min(uiop->uio_resid, + (vap->va_size - uiop->uio_loffset)); + + /* subtract requestSize from uio_resid and save remainder */ + remainder = uiop->uio_resid - requestsize; + + /* adjust size of read */ + uiop->uio_resid = requestsize; + + error = smb_rwuio(smp->smi_share, np->n_fid, UIO_READ, uiop, + &scred, smb_timo_read); + + /* set remaining uio_resid */ + uiop->uio_resid = uiop->uio_resid + remainder; + +out: + smb_credrele(&scred); + + return (error); +} + +int +smbfs_writevnode(vnode_t *vp, uio_t *uiop, + cred_t *cr, int ioflag, int timo) +{ + smbmntinfo_t *smp = VTOSMI(vp); + struct smbnode *np = VTOSMB(vp); + struct smb_cred scred; + int error = 0; + + /* shared lock for n_fid use in smb_rwuio */ + ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); + + if (vp->v_type != VREG) { + SMBVDEBUG("only VREG supported\n"); + return (EIO); + } + SMBVDEBUG("ofs=%lld,resid=%d\n", uiop->uio_loffset, + (int)uiop->uio_resid); + if (uiop->uio_loffset < 0) + return (EINVAL); +#ifdef NOT_YET + if (uiop->uio_loffset + uiop->uio_resid > smp->nm_maxfilesize) + return (EFBIG); +#endif + if (ioflag & (FAPPEND | FSYNC)) { + if (np->n_flag & NMODIFIED) { + smbfs_attr_cacheremove(np); + /* XXX: smbfs_vinvalbuf? */ + } + if (ioflag & FAPPEND) { + struct vattr vattr; + /* + * File size can be changed by another client + */ + error = smbfsgetattr(vp, &vattr, cr); + if (error) + return (error); + mutex_enter(&np->r_statelock); + uiop->uio_loffset = np->n_size; + mutex_exit(&np->r_statelock); + } + } + if (uiop->uio_resid == 0) + return (0); + + smb_credinit(&scred, curproc, cr); + + /* + * Darwin had code here to zero-extend using + * smb_write requests. Not needed. + * + * Use a longer timeout when appending. + * This ignores the passed-in timo value, + * but that was just a constant anyway. + * XXX: remove passed in timo arg later. + */ + timo = smb_timo_write; + if ((uiop->uio_loffset + uiop->uio_resid) > np->n_size) + timo = smb_timo_append; + error = smb_rwuio(smp->smi_share, np->n_fid, UIO_WRITE, uiop, + &scred, timo); + + mutex_enter(&np->r_statelock); + np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); + mutex_exit(&np->r_statelock); + + smb_credrele(&scred); + + SMBVDEBUG("after: ofs=%lld,resid=%d\n", uiop->uio_loffset, + (int)uiop->uio_resid); + if (!error) { + mutex_enter(&np->r_statelock); + if (uiop->uio_loffset > (offset_t)np->n_size) + np->n_size = (len_t)uiop->uio_loffset; + mutex_exit(&np->r_statelock); + } + return (error); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,489 @@ +/* + * 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: smbfs_node.c,v 1.54.52.1 2005/05/27 02:35:28 lindak Exp $ + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/cred.h> +#include <sys/vfs.h> +#include <sys/vnode.h> +#include <sys/kmem.h> +#include <sys/stat.h> +#include <sys/atomic.h> +#include <sys/cmn_err.h> +#include <sys/sysmacros.h> +#include <sys/bitmap.h> + +#ifdef APPLE +#include <sys/smb_apple.h> +#else +#include <netsmb/smb_osdep.h> +#endif + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> + +#include <smbfs/smbfs.h> +#include <smbfs/smbfs_node.h> +#include <smbfs/smbfs_subr.h> + +#if defined(DEBUG) || defined(lint) +#define SMBFS_NAME_DEBUG +#endif + +/* + * Lack of inode numbers leads us to the problem of generating them. + * Partially this problem can be solved by having a dir/file cache + * with inode numbers generated from the incremented by one counter. + * However this way will require too much kernel memory, gives all + * sorts of locking and consistency problems, not to mentinon counter + * overflows. So, I'm decided to use a hash function to generate + * pseudo random (and [often?] unique) inode numbers. + */ + +/* Magic constants for name hashing. */ +#define FNV_32_PRIME ((uint32_t)0x01000193UL) +#define FNV1_32_INIT ((uint32_t)33554467UL) + +uint32_t +smbfs_hash3(uint32_t ival, const char *name, int nmlen) +{ + uint32_t v; + + for (v = ival; nmlen; name++, nmlen--) { + v *= FNV_32_PRIME; + v ^= (uint32_t)*name; + } + return (v); +} + +uint32_t +smbfs_hash(const char *name, int nmlen) +{ + uint32_t v; + + v = smbfs_hash3(FNV1_32_INIT, name, nmlen); + return (v); +} + +/* + * This is basically a hash of the full path name, but + * computed without having the full path contiguously. + * The path building logic needs to match what + * smbfs_fullpath does. + * + * Note that smbfs_make_node computes inode numbers by + * calling smbfs_hash on the full path name. This will + * compute the same result given the directory path and + * the last component separately. + */ +uint32_t +smbfs_getino(struct smbnode *dnp, const char *name, int nmlen) +{ + uint32_t ino; + + /* Start with directory hash */ + ino = (uint32_t)dnp->n_ino; + + /* + * If not the root, hash a slash. + */ + if (dnp->n_rplen > 1) + ino = smbfs_hash3(ino, "\\", 1); + + /* Now hash this component. */ + ino = smbfs_hash3(ino, name, nmlen); + + return (ino); +} + +#define CHAR_FC '\374' /* 0xFC */ +#define CHAR_FE '\376' /* 0xFE */ +char * +smbfs_name_alloc(const char *name, int nmlen) +{ + char *cp; + size_t alen; + +#ifdef SMBFS_NAME_DEBUG + /* + * Note: The passed length is strlen(name), + * and does NOT include the terminating nul. + * Allocated space holds: (in order) + * (int)strlen + * char 0xFC (1st marker) + * copy of string + * terminating null + * char 0xFE (2nd marker) + */ + alen = sizeof (int) + 1 + nmlen + 1 + 1; + cp = kmem_alloc(alen, KM_SLEEP); + /*LINTED*/ + *(int *)cp = nmlen; + cp += sizeof (int); + cp[0] = CHAR_FC; + cp++; + bcopy(name, cp, nmlen); + cp[nmlen] = 0; + cp[nmlen + 1] = CHAR_FE; +#else + alen = nmlen + 1; /* Passed length does NOT include the nul. */ + cp = kmem_alloc(alen, KM_SLEEP); + bcopy(name, cp, nmlen); + cp[nmlen] = 0; +#endif + return (cp); +} + +/* + * Note: Passed length does NOT include the nul, + * the same as with smbfs_name_alloc(). + */ +void +smbfs_name_free(const char *name, int nmlen) +{ + size_t alen; +#ifdef SMBFS_NAME_DEBUG + int lnmlen; + char *cp; + + /* + * See comment in smbfs_name_alloc + * about the layout of this memory. + */ + alen = sizeof (int) + 1 + nmlen + 1 + 1; + cp = (char *)name; + cp--; + if (*cp != CHAR_FC) { + debug_enter("smbfs_name_free: name[-1] != 0xFC"); + } + cp -= sizeof (int); + /*LINTED*/ + lnmlen = *(int *)cp; + if (lnmlen != nmlen) { + debug_enter("smbfs_name_free: name[-5] != nmlen"); + } + if (name[nmlen + 1] != CHAR_FE) { + debug_enter("smbfs_name_free: name[nmlen+1] != 0xFE"); + } + kmem_free(cp, alen); +#else + alen = nmlen + 1; + kmem_free((char *)name, alen); +#endif +} + +/* + * smbfs_nget() + * + * NOTES: + * + * It would be nice to be able to pass in a flag when the caller is sure + * that the node does not exist and should just be allocated. + */ +int +smbfs_nget(vnode_t *dvp, const char *name, int nmlen, + struct smbfattr *fap, vnode_t **vpp) +{ + struct smbnode *dnp = VTOSMB(dvp); + vnode_t *vp; + + *vpp = NULL; + + /* Don't expect "." or ".." here anymore. */ + if ((nmlen == 1 && name[0] == '.') || + (nmlen == 2 && name[0] == '.' && name[1] == '.')) { + DEBUG_ENTER("smbfs_nget: name is '.' or '..'"); + return (EINVAL); + } + + /* The real work is in this call... */ + vp = smbfs_make_node(dvp->v_vfsp, + dnp->n_rpath, dnp->n_rplen, + name, nmlen, fap); + + /* + * We always have a vp now, because + * smbfs_make_node / make_smbnode + * calls kmem_alloc with KM_SLEEP. + */ + ASSERT(vp); + +#ifdef NOT_YET + /* update the attr_cache info if the file is clean */ + if (fap && !(VTOSMB(vp)->n_flag & NFLUSHWIRE)) + smbfs_attr_cacheenter(vp, fap); + if (dvp && makeentry) { + /* add entry to DNLC */ + cache_enter(dvp, vp, &cn); + } +#endif /* NOT_YET */ + + /* BSD symlink hack removed (smb_symmagic) */ + +#ifdef NOT_YET + smbfs_attr_cacheenter(vp, fap); /* update the attr_cache info */ +#endif /* NOT_YET */ + + *vpp = vp; + + return (0); +} + +/* + * routines to maintain vnode attributes cache + * smbfs_attr_cacheenter: unpack np.i to vnode_vattr structure + * + * Note that some SMB servers do not exhibit POSIX behaviour + * with regard to the mtime on directories. To work around + * this, we never allow the mtime on a directory to go backwards, + * and bump it forwards elsewhere to simulate the correct + * behaviour. + */ +void +smbfs_attr_cacheenter(vnode_t *vp, struct smbfattr *fap) +{ + struct smbnode *np = VTOSMB(vp); + int vtype; + struct timespec ts; + + mutex_enter(&np->r_statelock); + + vtype = vp->v_type; + if (vtype == VREG) { + if (np->n_size != fap->fa_size) { + /* + * Had Darwin ubc_sync_range call here, + * invalidating the truncated range. + * XXX: Solaris equivalent? + */ + SMBVDEBUG("Update size?\n"); + } + np->n_size = fap->fa_size; + } else if (vtype == VDIR) { + np->n_size = 16384; /* XXX should be a better way ... */ + /* + * Don't allow mtime to go backwards. + * Yes this has its flaws. Better ideas are welcome! + */ + /*CSTYLED*/ + if (timespeccmp(&fap->fa_mtime, &np->n_mtime, <)) + fap->fa_mtime = np->n_mtime; + } else if (vtype != VLNK) + goto out; + + np->n_atime = fap->fa_atime; + np->n_ctime = fap->fa_ctime; + np->n_mtime = fap->fa_mtime; + np->n_dosattr = fap->fa_attr; + + np->n_flag &= ~NATTRCHANGED; + gethrestime(&ts); + np->n_attrage = ts.tv_sec; + +out: + mutex_exit(&np->r_statelock); +} + +int +smbfs_attr_cachelookup(vnode_t *vp, struct vattr *vap) +{ + struct smbnode *np = VTOSMB(vp); + struct smbmntinfo *smi = VTOSMI(vp); + time_t attrtimeo; + struct timespec ts, *stime; + mode_t type; + + /* + * Determine attrtimeo. It will be something between SMB_MINATTRTIMO and + * SMB_MAXATTRTIMO where recently modified files have a short timeout + * and files that haven't been modified in a long time have a long + * timeout. This is the same algorithm used by NFS. + */ + gethrestime(&ts); + stime = &np->r_mtime; + attrtimeo = (ts.tv_sec - stime->tv_sec) / 10; + if (attrtimeo < SMB_MINATTRTIMO) { + attrtimeo = SMB_MINATTRTIMO; + } else if (attrtimeo > SMB_MAXATTRTIMO) + attrtimeo = SMB_MAXATTRTIMO; + /* has too much time passed? */ + stime = (struct timespec *)&np->r_attrtime; + if ((ts.tv_sec - stime->tv_sec) > attrtimeo) + return (ENOENT); + + if (!vap) + return (0); + + switch (vp->v_type) { + case VREG: + type = S_IFREG; + break; + case VLNK: + type = S_IFLNK; + break; + case VDIR: + type = S_IFDIR; + break; + default: + SMBSDEBUG("unknown vnode_vtype %d\n", vp->v_type); + return (EINVAL); + } + + mutex_enter(&np->r_statelock); + + if (!(np->n_flag & NGOTIDS)) { + np->n_mode = type; +#ifdef APPLE + if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) { + /* XXX: Can this block? Drop r_statelock? */ + if (!smbfs_getids(np, scredp)) { + np->n_flag |= NGOTIDS; + np->n_mode |= ACCESSPERMS; /* 0777 */ + } + } +#endif /* APPLE */ + if (!(np->n_flag & NGOTIDS)) { + np->n_flag |= NGOTIDS; + np->n_uid = smi->smi_args.uid; + np->n_gid = smi->smi_args.gid; + } + } + + if (vap->va_mask & AT_TYPE) + vap->va_type = vp->v_type; + if (vap->va_mask & AT_MODE) { + np->n_mode = 0; + if (vp->v_type == VDIR) + np->n_mode |= smi->smi_args.dir_mode; + else /* symlink and regular file */ + np->n_mode |= smi->smi_args.file_mode; + vap->va_mode = np->n_mode; + } + if (vap->va_mask & AT_SIZE) + vap->va_size = np->n_size; + if (vap->va_mask & AT_NODEID) + vap->va_nodeid = np->n_ino; + if (vap->va_mask & AT_ATIME) + vap->va_atime = np->n_atime; + if (vap->va_mask & AT_CTIME) + vap->va_ctime = np->n_ctime; + if (vap->va_mask & AT_MTIME) + vap->va_mtime = np->n_mtime; + vap->va_nlink = 1; + vap->va_uid = np->n_uid; + vap->va_gid = np->n_gid; + vap->va_fsid = vp->v_vfsp->vfs_dev; + vap->va_rdev = 0; + vap->va_blksize = MAXBSIZE; + vap->va_nblocks = (fsblkcnt64_t)btod(np->n_size); + vap->va_seq = 0; + + mutex_exit(&np->r_statelock); + + return (0); +} + +/* + * Some SMB servers don't exhibit POSIX behaviour with regard to + * updating the directory mtime when the directory's contents + * change. + * + * We force the issue here by updating our cached copy of the mtime + * whenever we perform such an action ourselves, and then mark the + * cache invalid. Subsequently when the invalidated cache entry is + * updated, we disallow an update that would move the mtime backwards. + * + * This preserves correct or near-correct behaviour with a + * compliant server, and gives near-correct behaviour with + * a non-compliant server in the most common case (we are the + * only client changing the directory). + * + * There are also complications if a server's time is ahead + * of our own. We must 'touch' a directory when it is first + * created, to ensure that the timestamp starts out sane, + * however it may have a timestamp well ahead of the 'touch' + * point which will be returned and cached the first time the + * directory's attributes are fetched. Subsequently, the + * directory's mtime will not appear to us to change at all + * until our local time catches up to the server. + * + * Thus, any time a directory is 'touched', the saved timestamp + * must advance at least far enough forwards to be visible to + * the stat(2) interface. + * + * XXX note that better behaviour with non-compliant servers + * could be obtained by bumping the mtime forwards when + * an update for an invalidated entry returns a nonsensical + * mtime. + */ + +void +smbfs_attr_touchdir(struct smbnode *dnp) +{ + struct timespec ts, ta; + + mutex_enter(&dnp->r_statelock); + + /* + * XXX - not sure about this... + * Creep the saved time forwards far enough that + * layers above the kernel will notice. + */ + ta.tv_sec = 1; + ta.tv_nsec = 0; + timespecadd(&dnp->n_mtime, &ta); + /* + * If the current time is later than the updated + * saved time, apply it instead. + */ + gethrestime(&ts); + /*CSTYLED*/ + if (timespeccmp(&dnp->n_mtime, &ts, <)) + dnp->n_mtime = ts; + /* + * Invalidate the cache, so that we go to the wire + * to check that the server doesn't have a better + * timestamp next time we care. + */ + smbfs_attr_cacheremove(dnp); + mutex_exit(&dnp->r_statelock); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,301 @@ +/* + * 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: smbfs_node.h,v 1.31.52.1 2005/05/27 02:35:28 lindak Exp $ + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _FS_SMBFS_NODE_H_ +#define _FS_SMBFS_NODE_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Much code copied into here from Sun NFS. + */ + +#include <sys/avl.h> +#include <sys/list.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct rddir_cache { + lloff_t _cookie; /* cookie used to find this cache entry */ + lloff_t _ncookie; /* cookie used to find the next cache entry */ + char *entries; /* buffer containing dirent entries */ + int eof; /* EOF reached after this request */ + int entlen; /* size of dirent entries in buf */ + int buflen; /* size of the buffer used to store entries */ + int flags; /* control flags, see below */ + kcondvar_t cv; /* cv for blocking */ + int error; /* error from RPC operation */ + kmutex_t lock; + uint_t count; /* reference count */ + avl_node_t tree; /* AVL tree links */ +} rddir_cache; + +#define smbfs_cookie _cookie._p._l +#define smbfs_ncookie _ncookie._p._l +#define smbfs3_cookie _cookie._f +#define smbfs3_ncookie _ncookie._f + +#define RDDIR 0x1 /* readdir operation in progress */ +#define RDDIRWAIT 0x2 /* waiting on readdir in progress */ +#define RDDIRREQ 0x4 /* a new readdir is required */ +#define RDDIRCACHED 0x8 /* entry is in the cache */ + +#define HAVE_RDDIR_CACHE(rp) (avl_numnodes(&(rp)->r_dir) > 0) + +/* + * A homegrown reader/writer lock implementation. It addresses + * two requirements not addressed by the system primitives. They + * are that the `enter" operation is optionally interruptible and + * that that they can be re`enter'ed by writers without deadlock. + */ +typedef struct smbfs_rwlock { + int count; + int waiters; + kthread_t *owner; + kmutex_t lock; + kcondvar_t cv; +} smbfs_rwlock_t; + +/* + * The format of the hash bucket used to lookup smbnodes from a file handle. + */ +typedef struct rhashq { + struct smbnode *r_hashf; + struct smbnode *r_hashb; + krwlock_t r_lock; +} rhashq_t; + +/* + * Remote file information structure. + * + * The smbnode is the "inode" for remote files. It contains all the + * information necessary to handle remote file on the client side. + * + * Note on file sizes: we keep two file sizes in the smbnode: the size + * according to the client (r_size) and the size according to the server + * (r_attr.va_size). They can differ because we modify r_size during a + * write system call (smbfs_rdwr), before the write request goes over the + * wire (before the file is actually modified on the server). If an OTW + * request occurs before the cached data is written to the server the file + * size returned from the server (r_attr.va_size) may not match r_size. + * r_size is the one we use, in general. r_attr.va_size is only used to + * determine whether or not our cached data is valid. + * + * Each smbnode has 3 locks associated with it (not including the smbnode + * hash table and free list locks): + * + * r_rwlock: Serializes smbfs_write and smbfs_setattr requests + * and allows smbfs_read requests to proceed in parallel. + * Serializes reads/updates to directories. + * + * r_lkserlock: Serializes lock requests with map, write, and + * readahead operations. + * + * r_statelock: Protects all fields in the smbnode except for + * those listed below. This lock is intented + * to be held for relatively short periods of + * time (not accross entire putpage operations, + * for example). + * + * The following members are protected by the mutex rpfreelist_lock: + * r_freef + * r_freeb + * + * The following members are protected by the hash bucket rwlock: + * r_hashf + * r_hashb + * + * Note: r_modaddr is only accessed when the r_statelock mutex is held. + * Its value is also controlled via r_rwlock. It is assumed that + * there will be only 1 writer active at a time, so it safe to + * set r_modaddr and release r_statelock as long as the r_rwlock + * writer lock is held. + * + * 64-bit offsets: the code formerly assumed that atomic reads of + * r_size were safe and reliable; on 32-bit architectures, this is + * not true since an intervening bus cycle from another processor + * could update half of the size field. The r_statelock must now + * be held whenever any kind of access of r_size is made. + * + * Lock ordering: + * r_rwlock > r_lkserlock > r_statelock + */ +struct exportinfo; /* defined in smbfs/export.h */ +struct failinfo; /* defined in smbfs/smbfs_clnt.h */ +struct mntinfo; /* defined in smbfs/smbfs_clnt.h */ + +#ifdef _KERNEL +/* Bits for smbnode.n_flag */ +#define NFLUSHINPROG 0x00001 +#define NFLUSHWANT 0x00002 /* they should gone ... */ +#define NMODIFIED 0x00004 /* bogus, until async IO implemented */ +#define NREFPARENT 0x00010 /* node holds parent from recycling */ +#define NGOTIDS 0x00020 +#define NRDIRSERIAL 0x00080 /* serialize readdir operation */ +#define NISMAPPED 0x00800 +#define NFLUSHWIRE 0x01000 +#define NATTRCHANGED 0x02000 /* use smbfs_attr_cacheremove at close */ +#define NALLOC 0x04000 /* being created */ +#define NWALLOC 0x08000 /* awaiting creation */ + +typedef struct smbnode { + /* from Sun NFS struct rnode (XXX: cleanup needed) */ + /* the hash fields must be first to match the rhashq_t */ + /* Lock for the hash queue is: np->r_hashq->r_lock */ + struct smbnode *r_hashf; /* hash queue forward pointer */ + struct smbnode *r_hashb; /* hash queue back pointer */ + /* Lock for the free list is: smbfreelist_lock */ + struct smbnode *r_freef; /* free list forward pointer */ + struct smbnode *r_freeb; /* free list back pointer */ + rhashq_t *r_hashq; /* pointer to the hash bucket */ + vnode_t *r_vnode; /* vnode for remote file */ + smbfs_rwlock_t r_rwlock; /* serializes write/setattr requests */ + smbfs_rwlock_t r_lkserlock; /* serialize lock with other ops */ + kmutex_t r_statelock; /* protects (most of) smbnode fields */ + u_offset_t r_nextr; /* next byte read offset (read-ahead) */ + cred_t *r_cred; /* current credentials */ + len_t r_size; /* client's view of file size */ + struct vattr r_attr; /* cached vnode attributes */ + hrtime_t r_attrtime; /* time attributes become invalid */ + long r_mapcnt; /* count of mmapped pages */ + uint_t r_count; /* # of refs not reflect in v_count */ + uint_t r_awcount; /* # of outstanding async write */ + uint_t r_gcount; /* getattrs waiting to flush pages */ + ushort_t r_flags; /* flags, see below */ + short r_error; /* async write error */ + kcondvar_t r_cv; /* condvar for blocked threads */ + avl_tree_t r_dir; /* cache of readdir responses */ + rddir_cache *r_direof; /* pointer to the EOF entry */ + kthread_t *r_serial; /* id of purging thread */ + list_t r_indelmap; /* list of delmap callers */ + /* + * Members derived from Darwin struct smbnode. + * Note: n_parent node pointer removed because it + * caused unwanted "holds" on nodes in our cache. + * Now keeping just the full remote path instead, + * in server form, relative to the share root. + */ + char *n_rpath; + int n_rplen; + uint32_t n_flag; + smbmntinfo_t *n_mount; + ino64_t n_ino; + /* Lock for the next 7 is r_lkserlock */ + int n_dirrefs; + struct smbfs_fctx *n_dirseq; /* ff context */ + long n_dirofs; /* last ff offset */ + long n_direof; /* End of dir. offset. */ + int n_fidrefs; + uint16_t n_fid; /* file handle */ + uint32_t n_rights; /* granted rights */ + /* Lock for the rest is r_statelock */ + uid_t n_uid; + gid_t n_gid; + mode_t n_mode; + timestruc_t r_atime; + timestruc_t r_ctime; + timestruc_t r_mtime; + int n_dosattr; + /* + * XXX: Maybe use this instead: + * #define n_atime r_attr.va_atime + * etc. + */ +#define n_size r_size +#define n_atime r_atime +#define n_ctime r_ctime +#define n_mtime r_mtime +#define n_attrage r_attrtime +} smbnode_t; +#endif /* _KERNEL */ + +/* + * Flags + */ +#define RREADDIRPLUS 0x1 /* issue a READDIRPLUS instead of READDIR */ +#define RDIRTY 0x2 /* dirty pages from write operation */ +#define RSTALE 0x4 /* file handle is stale */ +#define RMODINPROGRESS 0x8 /* page modification happening */ +#define RTRUNCATE 0x10 /* truncating, don't commit */ +#define RHAVEVERF 0x20 /* have a write verifier to compare against */ +#define RCOMMIT 0x40 /* commit in progress */ +#define RCOMMITWAIT 0x80 /* someone is waiting to do a commit */ +#define RHASHED 0x100 /* smbnode is in hash queues */ +#define ROUTOFSPACE 0x200 /* an out of space error has happened */ +#define RDIRECTIO 0x400 /* bypass the buffer cache */ +#define RLOOKUP 0x800 /* a lookup has been performed */ +#define RWRITEATTR 0x1000 /* attributes came from WRITE */ +#define RINDNLCPURGE 0x2000 /* in the process of purging DNLC references */ +#define RDELMAPLIST 0x4000 /* delmap callers tracking for as callback */ + +/* + * Convert between vnode and smbnode + */ +#define VTOSMB(vp) ((smbnode_t *)((vp)->v_data)) +#define SMBTOV(np) ((np)->r_vnode) + +/* Attribute cache timeouts in seconds */ +#define SMB_MINATTRTIMO 2 +#define SMB_MAXATTRTIMO 30 + +/* + * Function definitions. + */ +struct smb_cred; +int smbfs_nget(vnode_t *dvp, const char *name, int nmlen, + struct smbfattr *fap, vnode_t **vpp); +void smbfs_attr_cacheenter(vnode_t *vp, struct smbfattr *fap); +int smbfs_attr_cachelookup(vnode_t *vp, struct vattr *va); +void smbfs_attr_touchdir(struct smbnode *dnp); +char *smbfs_name_alloc(const char *name, int nmlen); +void smbfs_name_free(const char *name, int nmlen); +uint32_t smbfs_hash(const char *name, int nmlen); +uint32_t smbfs_hash3(uint32_t ival, const char *name, int nmlen); +uint32_t smbfs_getino(struct smbnode *dnp, const char *name, int nmlen); +int smb_check_table(struct vfs *vfsp, smbnode_t *srp); + +#define smbfs_attr_cacheremove(np) (np)->n_attrage = 0 + +#ifdef __cplusplus +} +#endif + +#endif /* _FS_SMBFS_NODE_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_rwlock.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,252 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * A homegrown reader/writer lock implementation. It addresses + * two requirements not addressed by the system primitives. They + * are that the `enter" operation is optionally interruptible and + * that that they can be re`enter'ed by writers without deadlock. + * + * All of this was borrowed from NFS. + * See: uts/common/fs/nfs/nfs_subr.c + * + * XXX: Could we make this serve our needs instead? + * See: uts/common/os/rwstlock.c + * (and then use it for NFS too) + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/time.h> +#include <sys/vnode.h> + +#include <smbfs/smbfs.h> +#include <smbfs/smbfs_node.h> +#include <smbfs/smbfs_subr.h> + + +/* + * Only can return non-zero if intr != 0. + */ +int +smbfs_rw_enter_sig(smbfs_rwlock_t *l, krw_t rw, int intr) +{ + + mutex_enter(&l->lock); + + /* + * If this is a nested enter, then allow it. There + * must be as many exits as enters through. + */ + if (l->owner == curthread) { + /* lock is held for writing by current thread */ + ASSERT(rw == RW_READER || rw == RW_WRITER); + l->count--; + } else if (rw == RW_READER) { + /* + * While there is a writer active or writers waiting, + * then wait for them to finish up and move on. Then, + * increment the count to indicate that a reader is + * active. + */ + while (l->count < 0 || l->waiters > 0) { + if (intr) { + klwp_t *lwp = ttolwp(curthread); + + if (lwp != NULL) + lwp->lwp_nostop++; + if (!cv_wait_sig(&l->cv, &l->lock)) { + if (lwp != NULL) + lwp->lwp_nostop--; + mutex_exit(&l->lock); + return (EINTR); + } + if (lwp != NULL) + lwp->lwp_nostop--; + } else + cv_wait(&l->cv, &l->lock); + } + ASSERT(l->count < INT_MAX); +#ifdef SMBDEBUG + if ((l->count % 10000) == 9999) + cmn_err(CE_WARN, "smbfs_rw_enter_sig: count %d on" + "rwlock @ %p\n", l->count, (void *)&l); +#endif + l->count++; + } else { + ASSERT(rw == RW_WRITER); + /* + * While there are readers active or a writer + * active, then wait for all of the readers + * to finish or for the writer to finish. + * Then, set the owner field to curthread and + * decrement count to indicate that a writer + * is active. + */ + while (l->count > 0 || l->owner != NULL) { + l->waiters++; + if (intr) { + klwp_t *lwp = ttolwp(curthread); + + if (lwp != NULL) + lwp->lwp_nostop++; + if (!cv_wait_sig(&l->cv, &l->lock)) { + if (lwp != NULL) + lwp->lwp_nostop--; + l->waiters--; + cv_broadcast(&l->cv); + mutex_exit(&l->lock); + return (EINTR); + } + if (lwp != NULL) + lwp->lwp_nostop--; + } else + cv_wait(&l->cv, &l->lock); + l->waiters--; + } + l->owner = curthread; + l->count--; + } + + mutex_exit(&l->lock); + + return (0); +} + +/* + * If the lock is available, obtain it and return non-zero. If there is + * already a conflicting lock, return 0 immediately. + */ + +int +smbfs_rw_tryenter(smbfs_rwlock_t *l, krw_t rw) +{ + mutex_enter(&l->lock); + + /* + * If this is a nested enter, then allow it. There + * must be as many exits as enters through. + */ + if (l->owner == curthread) { + /* lock is held for writing by current thread */ + ASSERT(rw == RW_READER || rw == RW_WRITER); + l->count--; + } else if (rw == RW_READER) { + /* + * If there is a writer active or writers waiting, deny the + * lock. Otherwise, bump the count of readers. + */ + if (l->count < 0 || l->waiters > 0) { + mutex_exit(&l->lock); + return (0); + } + l->count++; + } else { + ASSERT(rw == RW_WRITER); + /* + * If there are readers active or a writer active, deny the + * lock. Otherwise, set the owner field to curthread and + * decrement count to indicate that a writer is active. + */ + if (l->count > 0 || l->owner != NULL) { + mutex_exit(&l->lock); + return (0); + } + l->owner = curthread; + l->count--; + } + + mutex_exit(&l->lock); + + return (1); +} + +void +smbfs_rw_exit(smbfs_rwlock_t *l) +{ + + mutex_enter(&l->lock); + /* + * If this is releasing a writer lock, then increment count to + * indicate that there is one less writer active. If this was + * the last of possibly nested writer locks, then clear the owner + * field as well to indicate that there is no writer active + * and wakeup any possible waiting writers or readers. + * + * If releasing a reader lock, then just decrement count to + * indicate that there is one less reader active. If this was + * the last active reader and there are writer(s) waiting, + * then wake up the first. + */ + if (l->owner != NULL) { + ASSERT(l->owner == curthread); + l->count++; + if (l->count == 0) { + l->owner = NULL; + cv_broadcast(&l->cv); + } + } else { + ASSERT(l->count > 0); + l->count--; + if (l->count == 0 && l->waiters > 0) + cv_broadcast(&l->cv); + } + mutex_exit(&l->lock); +} + +int +smbfs_rw_lock_held(smbfs_rwlock_t *l, krw_t rw) +{ + + if (rw == RW_READER) + return (l->count > 0); + ASSERT(rw == RW_WRITER); + return (l->count < 0); +} + +/* ARGSUSED */ +void +smbfs_rw_init(smbfs_rwlock_t *l, char *name, krw_type_t type, void *arg) +{ + + l->count = 0; + l->waiters = 0; + l->owner = NULL; + mutex_init(&l->lock, NULL, MUTEX_DEFAULT, NULL); + cv_init(&l->cv, NULL, CV_DEFAULT, NULL); +} + +void +smbfs_rw_destroy(smbfs_rwlock_t *l) +{ + + mutex_destroy(&l->lock); + cv_destroy(&l->cv); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,3147 @@ +/* + * 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: smbfs_smb.c,v 1.73.38.1 2005/05/27 02:35:28 lindak Exp $ + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/time.h> +#include <sys/vnode.h> +#include <sys/cmn_err.h> + +#ifdef APPLE +#include <sys/smb_apple.h> +#include <sys/utfconv.h> +#else +#include <netsmb/smb_osdep.h> +#endif + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> +#include <netsmb/smb_rq.h> + +#include <smbfs/smbfs.h> +#include <smbfs/smbfs_node.h> +#include <smbfs/smbfs_subr.h> + +/* + * Local functions. + * Not static, to aid debugging. + */ + +int smbfs_smb_qfileinfo(struct smbnode *np, struct smbfattr *fap, + struct smb_cred *scrp, short infolevel); +int smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap, + struct smb_cred *scrp, short infolevel); +int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen, + struct smbfattr *fap, struct smb_cred *scrp); + +int smbfs_smb_statfsLM1(struct smb_share *ssp, + statvfs64_t *sbp, struct smb_cred *scrp); +int smbfs_smb_statfsLM2(struct smb_share *ssp, + statvfs64_t *sbp, struct smb_cred *scrp); + +int smbfs_smb_setftime1(struct smbnode *np, uint16_t fid, + struct timespec *mtime, struct timespec *atime, + struct smb_cred *scrp); +int smbfs_smb_setfattrNT(struct smbnode *np, uint16_t fid, + uint32_t attr, struct timespec *mtime, struct timespec *atime, + struct smb_cred *scrp); + +int smbfs_smb_setpattr1(struct smbnode *np, + const char *name, int len, uint32_t attr, + struct timespec *mtime, struct smb_cred *scrp); +int smbfs_smb_setpattr2(struct smbnode *np, uint32_t attr, + struct timespec *mtime, struct timespec *atime, + struct smb_cred *scrp); +int smbfs_smb_setpattrNT(struct smbnode *np, uint32_t attr, + struct timespec *mtime, struct timespec *atime, + struct smb_cred *scrp); + + +/* + * Todo: locking over-the-wire + */ +#ifdef APPLE + +static int +smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid, + offset_t start, uint64_t len, int largelock, + struct smb_cred *scrp, uint32_t timeout) +{ + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_rq rq, *rqp = &rq; + struct mbchain *mbp; + uint8_t ltype = 0; + int error; + + /* Shared lock for n_fid use below. */ + ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); + + if (op == SMB_LOCK_SHARED) + ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; + if (largelock) + ltype |= SMB_LOCKING_ANDX_LARGE_FILES; + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_uint8(mbp, 0xff); /* secondary command */ + mb_put_uint8(mbp, 0); /* MBZ */ + mb_put_uint16le(mbp, 0); + mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); + mb_put_uint8(mbp, ltype); /* locktype */ + mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ + mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */ + mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0); + mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint16le(mbp, pid); + if (!largelock) { + mb_put_uint32le(mbp, start); + mb_put_uint32le(mbp, len); + } else { + mb_put_uint16le(mbp, 0); /* pad */ + mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */ + mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */ + mb_put_uint32le(mbp, len >> 32); /* LengthHigh */ + mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */ + } + smb_rq_bend(rqp); + /* + * Don't want to risk missing a successful + * unlock send or lock response, or we could + * lose track of an outstanding lock. + */ + if (op == SMB_LOCK_RELEASE) + rqp->sr_flags |= SMBR_NOINTR_SEND; + else + rqp->sr_flags |= SMBR_NOINTR_RECV; + + error = smb_rq_simple(rqp); + smb_rq_done(rqp); + return (error); +} + +int +smbfs_smb_lock(struct smbnode *np, int op, caddr_t id, + offset_t start, uint64_t len, int largelock, + struct smb_cred *scrp, uint32_t timeout) +{ + struct smb_share *ssp = np->n_mount->smi_share; + + if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0) + /* + * TODO: use LOCK_BYTE_RANGE here. + */ + return (EINVAL); + else + return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len, + largelock, scrp, timeout)); +} + +#endif /* APPLE */ + +/* + * Helper for smbfs_getattr + * Something like nfs_getattr_otw + */ +int +smbfs_smb_getfattr( + struct smbnode *np, + struct smbfattr *fap, + struct smb_cred *scrp) +{ + int error; + + /* + * This lock is really only necessary for qfileinfo, + * but hopefully we use that most of the time. + * Lock may be writer (via open) or reader. + */ + ASSERT(np->r_lkserlock.count != 0); + + if (np->n_fidrefs) + error = smbfs_smb_qfileinfo(np, fap, scrp, 0); + else + error = smbfs_smb_qpathinfo(np, fap, scrp, 0); + + if (error == EINVAL) { + /* fallback */ + error = smbfs_smb_query_info(np, NULL, 0, fap, scrp); + } + +#if 0 /* Moved this part to caller. */ + if (!error && fap->fa_mtime.tv_sec == 0) + smbfs_attr_touchdir(dnp); +#endif + + return (error); +} + + +/* + * Nearly identical to smbfs_smb_qfileinfo (below). + * Please keep them in sync. + */ +int +smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap, + struct smb_cred *scrp, short infolevel) +{ + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + struct smb_t2rq *t2p; + int error, svtz, timesok = 1; + struct mbchain *mbp; + struct mdchain *mdp; + uint16_t date, time, wattr; + uint64_t llongint, lsize; + uint32_t size, dattr; + +top: + error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION, + scrp, &t2p); + if (error) + return (error); + mbp = &t2p->t2_tparam; + mb_init(mbp); + if (!infolevel) { + if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) + infolevel = SMB_QFILEINFO_STANDARD; + else + infolevel = SMB_QFILEINFO_ALL_INFO; + } + mb_put_uint16le(mbp, infolevel); + mb_put_uint32le(mbp, 0); + /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */ + error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\'); + if (error) { + smb_t2_done(t2p); + return (error); + } + t2p->t2_maxpcount = 2; + t2p->t2_maxdcount = vcp->vc_txmax; + error = smb_t2_request(t2p); + if (error) { + smb_t2_done(t2p); + /* Invalid info level? Try fallback. */ + if (error == EINVAL && + infolevel == SMB_QFILEINFO_ALL_INFO) { + infolevel = SMB_QFILEINFO_STANDARD; + goto top; + } + return (error); + } + mdp = &t2p->t2_rdata; + svtz = vcp->vc_sopt.sv_tz; + switch (infolevel) { + case SMB_QFILEINFO_STANDARD: + timesok = 0; + md_get_uint16le(mdp, NULL); + md_get_uint16le(mdp, NULL); /* creation time */ + md_get_uint16le(mdp, &date); + md_get_uint16le(mdp, &time); /* access time */ + if (date || time) { + timesok++; + smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime); + } + md_get_uint16le(mdp, &date); + md_get_uint16le(mdp, &time); /* modify time */ + if (date || time) { + timesok++; + smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime); + } + md_get_uint32le(mdp, &size); + fap->fa_size = size; + md_get_uint32(mdp, NULL); /* allocation size */ + md_get_uint16le(mdp, &wattr); + fap->fa_attr = wattr; + break; + case SMB_QFILEINFO_ALL_INFO: + timesok = 0; + /* creation time (discard) */ + md_get_uint64(mdp, NULL); + /* last access time */ + md_get_uint64le(mdp, &llongint); + if (llongint) { + timesok++; + smb_time_NT2local(llongint, svtz, &fap->fa_atime); + } + /* last write time */ + md_get_uint64le(mdp, &llongint); + if (llongint) { + timesok++; + smb_time_NT2local(llongint, svtz, &fap->fa_mtime); + } + /* last change time */ + md_get_uint64le(mdp, &llongint); + if (llongint) { + timesok++; + smb_time_NT2local(llongint, svtz, &fap->fa_ctime); + } + /* attributes */ + md_get_uint32le(mdp, &dattr); + fap->fa_attr = dattr; + /* + * 4-Byte alignment - discard + * Specs doesn't talk about this. + */ + md_get_uint32le(mdp, NULL); + /* allocation size (discard) */ + md_get_uint64le(mdp, NULL); + /* File size */ + md_get_uint64le(mdp, &lsize); + fap->fa_size = lsize; + break; + default: + SMBVDEBUG("unexpected info level %d\n", infolevel); + error = EINVAL; + } + smb_t2_done(t2p); + /* + * if all times are zero (observed with FAT on NT4SP6) + * then fall back to older info level + */ + if (!timesok) { + if (infolevel == SMB_QFILEINFO_ALL_INFO) { + infolevel = SMB_QFILEINFO_STANDARD; + goto top; + } + error = EINVAL; + } + return (error); +} + +/* + * Nearly identical to smbfs_smb_qpathinfo (above). + * Please keep them in sync. + */ +int +smbfs_smb_qfileinfo(struct smbnode *np, struct smbfattr *fap, + struct smb_cred *scrp, short infolevel) +{ + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + struct smb_t2rq *t2p; + int error, svtz, timesok = 1; + struct mbchain *mbp; + struct mdchain *mdp; + uint16_t date, time, wattr; + uint64_t llongint, lsize; + uint32_t size, dattr; + + /* + * Shared lock for n_fid use below. + * See smbfs_smb_getfattr() + */ + ASSERT(np->r_lkserlock.count != 0); + + if (np->n_fid == SMB_FID_UNUSED) + return (EBADF); + +top: + error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FILE_INFORMATION, + scrp, &t2p); + if (error) + return (error); + mbp = &t2p->t2_tparam; + mb_init(mbp); + if (!infolevel) { + if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) + infolevel = SMB_QFILEINFO_STANDARD; + else + infolevel = SMB_QFILEINFO_ALL_INFO; + } + mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); + mb_put_uint16le(mbp, infolevel); + t2p->t2_maxpcount = 2; + t2p->t2_maxdcount = vcp->vc_txmax; + error = smb_t2_request(t2p); + if (error) { + smb_t2_done(t2p); + /* Invalid info level? Try fallback. */ + if (error == EINVAL && + infolevel == SMB_QFILEINFO_ALL_INFO) { + infolevel = SMB_QFILEINFO_STANDARD; + goto top; + } + return (error); + } + mdp = &t2p->t2_rdata; + svtz = vcp->vc_sopt.sv_tz; + switch (infolevel) { + case SMB_QFILEINFO_STANDARD: + timesok = 0; + md_get_uint16le(mdp, NULL); + md_get_uint16le(mdp, NULL); /* creation time */ + md_get_uint16le(mdp, &date); + md_get_uint16le(mdp, &time); /* access time */ + if (date || time) { + timesok++; + smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime); + } + md_get_uint16le(mdp, &date); + md_get_uint16le(mdp, &time); /* modify time */ + if (date || time) { + timesok++; + smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime); + } + md_get_uint32le(mdp, &size); + fap->fa_size = size; + md_get_uint32(mdp, NULL); /* allocation size */ + md_get_uint16le(mdp, &wattr); + fap->fa_attr = wattr; + break; + case SMB_QFILEINFO_ALL_INFO: + timesok = 0; + /* creation time (discard) */ + md_get_uint64(mdp, NULL); + /* last access time */ + md_get_uint64le(mdp, &llongint); + if (llongint) { + timesok++; + smb_time_NT2local(llongint, svtz, &fap->fa_atime); + } + /* last write time */ + md_get_uint64le(mdp, &llongint); + if (llongint) { + timesok++; + smb_time_NT2local(llongint, svtz, &fap->fa_mtime); + } + /* last change time */ + md_get_uint64le(mdp, &llongint); + if (llongint) { + timesok++; + smb_time_NT2local(llongint, svtz, &fap->fa_ctime); + } + /* attributes */ + md_get_uint32le(mdp, &dattr); + fap->fa_attr = dattr; + /* + * 4-Byte alignment - discard + * Specs doesn't talk about this. + */ + md_get_uint32le(mdp, NULL); + /* allocation size (discard) */ + md_get_uint64le(mdp, NULL); + /* File size */ + md_get_uint64le(mdp, &lsize); + fap->fa_size = lsize; + break; + default: + SMBVDEBUG("unexpected info level %d\n", infolevel); + error = EINVAL; + } + smb_t2_done(t2p); + /* + * if all times are zero (observed with FAT on NT4SP6) + * then fall back to older info level + */ + if (!timesok) { + if (infolevel == SMB_QFILEINFO_ALL_INFO) { + infolevel = SMB_QFILEINFO_STANDARD; + goto top; + } + error = EINVAL; + } + return (error); +} + +/* + * Support functions for _qstreaminfo + * Todo: show NT file streams as + * Solaris named attributes. + */ +#ifdef APPLE + +static char * +sfm2xattr(char *sfm) +{ + if (!strncasecmp(sfm, SFM_RESOURCEFORK_NAME, + sizeof (SFM_RESOURCEFORK_NAME))) + return (XATTR_RESOURCEFORK_NAME); + if (!strncasecmp(sfm, SFM_FINDERINFO_NAME, + sizeof (SFM_FINDERINFO_NAME))) + return (XATTR_FINDERINFO_NAME); + return (NULL); +} + +static int +smbfs_smb_undollardata(struct smbnode *np, struct smbfs_fctx *ctx) +{ + char *cp; + int len = strlen(SMB_DATASTREAM); + + if (!ctx->f_name) /* sanity check */ + goto bad; + if (ctx->f_nmlen < len + 1) /* "::$DATA" at a minimum */ + goto bad; + if (*ctx->f_name != ':') /* leading colon - "always" */ + goto bad; + cp = &ctx->f_name[ctx->f_nmlen - len]; /* point to 2nd colon */ + if (bcmp(cp, SMB_DATASTREAM, len)) + goto bad; + if (ctx->f_nmlen == len + 1) /* merely the data fork? */ + return (0); /* skip it */ + /* + * XXX here we should be calling KPI to validate the stream name + */ + if (ctx->f_nmlen >= 18 && + !(bcmp(ctx->f_name, ":com.apple.system.", 18) == 0)) + return (0); /* skip protected system attrs */ + if (ctx->f_nmlen - len > XATTR_MAXNAMELEN + 1) + goto bad; /* mustnt return more than 128 bytes */ + /* + * Un-count a colon and the $DATA, then the + * 2nd colon is replaced by a terminating null. + */ + ctx->f_nmlen -= len; + *cp = '\0'; + return (1); +bad: + SMBSDEBUG("file \"%.*s\" has bad stream \"%.*s\"\n", + np->n_nmlen, np->n_name, ctx->f_nmlen, ctx->f_name); + return (0); /* skip it */ +} + +PRIVSYM int +smbfs_smb_qstreaminfo(struct smbnode *np, struct smb_cred *scrp, + uio_t uio, size_t *sizep) +{ + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + struct smb_t2rq *t2p; + int error; + struct mbchain *mbp; + struct mdchain *mdp; + uint32_t next, nlen, used; + struct smbfs_fctx ctx; + + *sizep = 0; + ctx.f_ssp = ssp; + ctx.f_name = NULL; + + error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION, + scrp, &t2p); + if (error) + return (error); + mbp = &t2p->t2_tparam; + mb_init(mbp); + /* + * SMB_QFILEINFO_STREAM_INFORMATION is an option to consider + * here. Samba declined to support the older info level with + * a comment claiming doing so caused a BSOD. + */ + mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO); + mb_put_uint32le(mbp, 0); + /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */ + error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\'); + if (error) + goto out; + t2p->t2_maxpcount = 2; + t2p->t2_maxdcount = vcp->vc_txmax; + error = smb_t2_request(t2p); + if (error) { + if (smb_t2_err(t2p) == NT_STATUS_INVALID_PARAMETER) + error = ENOTSUP; + goto out; + } + mdp = &t2p->t2_rdata; + /* + * On a directory Windows is likely to return a zero data count. + * Check for that now to avoid EBADRPC from md_get_uint32le + */ + if (mdp->md_cur == NULL) + goto out; + do { + if ((error = md_get_uint32le(mdp, &next))) + goto out; + if ((error = md_get_uint32le(mdp, &nlen))) /* name length */ + goto out; + if ((error = md_get_uint64le(mdp, NULL))) /* stream size */ + goto out; + if ((error = md_get_uint64le(mdp, NULL))) /* allocated size */ + goto out; + /* + * Sanity check to limit DoS or buffer overrun attempts. + * The arbitrary 16384 is sufficient for all legit packets. + */ + if (nlen > 16384) { + SMBVDEBUG("huge name length in packet!\n"); + error = EBADRPC; + goto out; + } + ctx.f_name = kmem_zalloc(nlen, KM_SLEEP); + ctx.f_namesz = nlen; + if ((error = md_get_mem(mdp, ctx.f_name, nlen, MB_MSYSTEM))) + goto out; + /* + * skip pad bytes and/or tail of overlong name + */ + used = 4 + 4 + 8 + 8 + nlen; + if (next && next > used) { + if (next - used > 16384) { + SMBVDEBUG("huge offset in packet!\n"); + error = EBADRPC; + goto out; + } + md_get_mem(mdp, NULL, next - used, MB_MSYSTEM); + } + /* ignore a trailing null, not that we expect them */ + if (SMB_UNICODE_STRINGS(vcp)) { + if (nlen > 1 && !ctx.f_name[nlen - 1] && + !ctx.f_name[nlen - 2]) + nlen -= 2; + } else { + if (nlen && !ctx.f_name[nlen - 1]) + nlen -= 1; + } + ctx.f_nmlen = nlen; + smbfs_fname_tolocal(&ctx); /* converts from UCS2LE */ + /* + * We should now have a name in the form + * : <foo> :$DATA + * Where <foo> is UTF-8 w/o null termination + * If it isn't in that form we want to LOG it and skip it. + * Note we want to skip w/o logging the "data fork" entry, + * which is simply ::$DATA + * Otherwise we want to uiomove out <foo> with a null added. + */ + if (smbfs_smb_undollardata(np, &ctx)) { + char *s; + + /* the "+ 1" skips over the leading colon */ + s = sfm2xattr(ctx.f_name + 1); +#ifndef DUAL_EAS /* XXX */ + /* + * In Tiger Carbon still accesses dot-underscore files directly, so... + * For Tiger we preserve the SFM/Thursby AFP_* stream names rather + * than mapping them to com.apple.*. This means our copy engines + * will preserve SFM/Thursby resource-fork and finder-info. + */ + s = NULL; +#endif + if (s) + ctx.f_nmlen = strlen(s) + 1; + else + s = ctx.f_name + 1; + if (uio) + uiomove(s, ctx.f_nmlen, uio); + else + *sizep += ctx.f_nmlen; + } + kmem_free(ctx.f_name, ctx.f_namesz); + ctx.f_name = NULL; + } while (next && !error); +out: + if (ctx.f_name) + kmem_free(ctx.f_name, ctx.f_namesz); + smb_t2_done(t2p); + return (error); +} + +#endif /* APPLE */ + +int +smbfs_smb_qfsattr(struct smb_share *ssp, uint32_t *attrp, + struct smb_cred *scrp) +{ + struct smb_t2rq *t2p; + struct mbchain *mbp; + struct mdchain *mdp; + uint32_t nlen; + int error; + char *fs_name; /* will malloc whatever the size is */ + struct smbfs_fctx ctx; + + error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, + scrp, &t2p); + if (error) + return (error); + mbp = &t2p->t2_tparam; + mb_init(mbp); + mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO); + t2p->t2_maxpcount = 4; + t2p->t2_maxdcount = 4 * 3 + 512; + error = smb_t2_request(t2p); + if (error) { + smb_t2_done(t2p); + return (error); + } + mdp = &t2p->t2_rdata; + md_get_uint32le(mdp, attrp); + md_get_uint32le(mdp, &ssp->ss_maxfilenamelen); + md_get_uint32le(mdp, &nlen); /* fs name length */ + if (ssp->ss_fsname == NULL && nlen) { + ctx.f_ssp = ssp; + ctx.f_name = kmem_alloc(nlen, KM_SLEEP); + ctx.f_namesz = nlen; + md_get_mem(mdp, ctx.f_name, nlen, MB_MSYSTEM); + ctx.f_nmlen = nlen; + smbfs_fname_tolocal(&ctx); + fs_name = kmem_alloc(ctx.f_nmlen+1, KM_SLEEP); + bcopy(ctx.f_name, fs_name, ctx.f_nmlen); + fs_name[ctx.f_nmlen] = '\0'; + ssp->ss_fsname = fs_name; + kmem_free(ctx.f_name, ctx.f_namesz); + /* + * If fs_name isn't NTFS they probably require resume keys. + * This is another example of the client trying to fix a server + * bug. This code uses the logic created by PR-3983209. See + * long block comment in smbfs_smb_findnextLM2. + */ + if (strcmp(fs_name, "NTFS")) { + SMB_SS_LOCK(ssp); + ssp->ss_flags |= SMBS_RESUMEKEYS; + SMB_SS_UNLOCK(ssp); + } + SMBVDEBUG("(fyi) share '%s', attr 0x%x, maxfilename %d\n", + ssp->ss_fsname, *attrp, ssp->ss_maxfilenamelen); + } + smb_t2_done(t2p); + return (0); +} + +int +smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp, + struct smb_cred *scp) +{ + int error; + + if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0) + error = smbfs_smb_statfsLM2(ssp, sbp, scp); + else + error = smbfs_smb_statfsLM1(ssp, sbp, scp); + + return (error); +} + +int +smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp, + struct smb_cred *scrp) +{ + struct smb_t2rq *t2p; + struct mbchain *mbp; + struct mdchain *mdp; + uint16_t bsize; + uint32_t units, bpu, funits; + uint64_t s, t, f; + int error; + + error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, + scrp, &t2p); + if (error) + return (error); + mbp = &t2p->t2_tparam; + mb_init(mbp); + mb_put_uint16le(mbp, SMB_QFS_ALLOCATION); + t2p->t2_maxpcount = 4; + t2p->t2_maxdcount = 4 * 4 + 2; + error = smb_t2_request(t2p); + if (error) { + smb_t2_done(t2p); + return (error); + } + mdp = &t2p->t2_rdata; + md_get_uint32(mdp, NULL); /* fs id */ + md_get_uint32le(mdp, &bpu); + md_get_uint32le(mdp, &units); + md_get_uint32le(mdp, &funits); + md_get_uint16le(mdp, &bsize); + s = bsize; + s *= bpu; + t = units; + f = funits; + /* + * Don't allow over-large blocksizes as they determine + * Finder List-view size granularities. On the other + * hand, we mustn't let the block count overflow the + * 31 bits available. + */ + while (s > 16 * 1024) { + if (t > LONG_MAX) + break; + s /= 2; + t *= 2; + f *= 2; + } + while (t > LONG_MAX) { + t /= 2; + f /= 2; + s *= 2; + } + sbp->f_bsize = (ulong_t)s; /* file system block size */ + sbp->f_blocks = t; /* total data blocks in file system */ + sbp->f_bfree = f; /* free blocks in fs */ + sbp->f_bavail = f; /* free blocks avail to non-superuser */ + sbp->f_files = (-1); /* total file nodes in file system */ + sbp->f_ffree = (-1); /* free file nodes in fs */ + smb_t2_done(t2p); + return (0); +} + +int +smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp, + struct smb_cred *scrp) +{ + struct smb_rq rq, *rqp = &rq; + struct mdchain *mdp; + uint16_t units, bpu, bsize, funits; + uint64_t s, t, f; + int error; + + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, + scrp); + if (error) + return (error); + smb_rq_wstart(rqp); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + if (error) { + smb_rq_done(rqp); + return (error); + } + smb_rq_getreply(rqp, &mdp); + md_get_uint16le(mdp, &units); + md_get_uint16le(mdp, &bpu); + md_get_uint16le(mdp, &bsize); + md_get_uint16le(mdp, &funits); + s = bsize; + s *= bpu; + t = units; + f = funits; + /* + * Don't allow over-large blocksizes as they determine + * Finder List-view size granularities. On the other + * hand, we mustn't let the block count overflow the + * 31 bits available. + */ + while (s > 16 * 1024) { + if (t > LONG_MAX) + break; + s /= 2; + t *= 2; + f *= 2; + } + while (t > LONG_MAX) { + t /= 2; + f /= 2; + s *= 2; + } + sbp->f_bsize = (ulong_t)s; /* file system block size */ + sbp->f_blocks = t; /* total data blocks in file system */ + sbp->f_bfree = f; /* free blocks in fs */ + sbp->f_bavail = f; /* free blocks avail to non-superuser */ + sbp->f_files = (-1); /* total file nodes in file system */ + sbp->f_ffree = (-1); /* free file nodes in fs */ + smb_rq_done(rqp); + return (0); +} + +int +smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize, + struct smb_cred *scrp) +{ + struct smb_t2rq *t2p; + struct smb_vc *vcp = SSTOVC(ssp); + struct mbchain *mbp; + int error; + + error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, + scrp, &t2p); + if (error) + return (error); + mbp = &t2p->t2_tparam; + mb_init(mbp); + mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); + if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) + mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION); + else + mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO); + mb_put_uint32le(mbp, 0); /* XXX should be 16 not 32(?) */ + mbp = &t2p->t2_tdata; + mb_init(mbp); + mb_put_uint64le(mbp, newsize); + mb_put_uint32le(mbp, 0); /* padding */ + mb_put_uint16le(mbp, 0); + t2p->t2_maxpcount = 2; + t2p->t2_maxdcount = 0; + error = smb_t2_request(t2p); + smb_t2_done(t2p); + return (error); +} + +/*ARGSUSED*/ +int +smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp, + const char *tname, int tnmlen, struct smb_cred *scrp, int overwrite) +{ + struct smb_t2rq *t2p; + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + struct mbchain *mbp; + int32_t *ucslenp; + int error, cerror; + uint16_t fid = 0; + + /* Shared lock for n_fid use below. */ + ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); + + if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)) + return (ENOTSUP); + error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, + scrp, &t2p); + if (error) + return (error); + if (tdnp) { + error = smbfs_smb_tmpopen(tdnp, SA_RIGHT_FILE_READ_DATA, scrp, + &fid); + if (error) + goto exit; + } + mbp = &t2p->t2_tparam; + mb_init(mbp); + mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); + mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION); + mb_put_uint16le(mbp, 0); /* reserved, nowadays */ + mbp = &t2p->t2_tdata; + mb_init(mbp); + mb_put_uint32le(mbp, overwrite); + mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); /* base for tname */ + mb_put_uint16le(mbp, 0); /* part of a 32bit fid? */ + ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t)); + mbp->mb_count = 0; + error = smb_put_dstring(mbp, vcp, tname, SMB_CS_NONE); + if (error) + goto exit; + mbp->mb_count--; /* don't count the null */ + *ucslenp = htolel(mbp->mb_count); + t2p->t2_maxpcount = 2; + t2p->t2_maxdcount = 0; + error = smb_t2_request(t2p); +exit: + if (fid) { + cerror = smbfs_smb_tmpclose(tdnp, fid, scrp); + if (cerror) + SMBERROR("error %d closing fid %d\n", cerror, fid); + } + smb_t2_done(t2p); + return (error); +} + +int +smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp) +{ + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_rq rq, *rqp = &rq; + struct mbchain *mbp; + int error; + + /* Shared lock for n_fid use below. */ + ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); + + if (!(np->n_flag & NFLUSHWIRE)) + return (0); + if (np->r_count == 0) + return (0); /* not open */ + if (np->r_vnode->v_type != VREG) + return (0); /* not a file */ + + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + smb_rq_done(rqp); + if (!error) { + mutex_enter(&np->r_statelock); + np->n_flag &= ~NFLUSHWIRE; + mutex_exit(&np->r_statelock); + } + return (error); +} + +int +smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize, + struct smb_cred *scrp) +{ + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_rq rq, *rqp = &rq; + struct mbchain *mbp; + int error; + + /* + * This call knows about 64-bit offsets. + */ + error = smbfs_smb_seteof(ssp, fid, newsize, scrp); + if (!error) { + mutex_enter(&np->r_statelock); + np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); + mutex_exit(&np->r_statelock); + return (0); + } + + /* + * If we have SMB_CAP_LARGE_FILES, the above + * should have worked. XXX: Don't fallback? + * XXX: Or fallback on specific errors? + */ + if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) { + SMBVDEBUG("Have CAP_LARGE but _seteof error=%d\n", error); + } + + /* + * OK, so fallback to SMB_COM_WRITE, but note: + * it only supports 32-bit file offsets. + */ + if (newsize > UINT32_MAX) + return (EFBIG); + + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); + mb_put_uint16le(mbp, 0); + mb_put_uint32le(mbp, newsize); + mb_put_uint16le(mbp, 0); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint8(mbp, SMB_DT_DATA); + mb_put_uint16le(mbp, 0); + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + smb_rq_done(rqp); + mutex_enter(&np->r_statelock); + np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); + mutex_exit(&np->r_statelock); + return (error); +} + +int +smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen, + struct smbfattr *fap, struct smb_cred *scrp) +{ + struct smb_rq rq, *rqp = &rq; + struct smb_share *ssp = np->n_mount->smi_share; + struct mbchain *mbp; + struct mdchain *mdp; + uint8_t wc; + int error; + uint16_t wattr; + uint32_t longint; + + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint8(mbp, SMB_DT_ASCII); + do { + error = smbfs_fullpath(mbp, SSTOVC(ssp), np, + name, &nmlen, '\\'); + if (error) + break; + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + if (error) + break; + smb_rq_getreply(rqp, &mdp); + if (md_get_uint8(mdp, &wc) != 0 || wc != 10) { + error = EBADRPC; + break; + } + md_get_uint16le(mdp, &wattr); + fap->fa_attr = wattr; + /* + * Be careful using the time returned here, as + * with FAT on NT4SP6, at least, the time returned is low + * 32 bits of 100s of nanoseconds (since 1601) so it rolls + * over about every seven minutes! + */ + md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */ + if (longint) /* avoid bogus zero returns */ + smb_time_server2local(longint, + SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime); + md_get_uint32le(mdp, &longint); + fap->fa_size = longint; + /*LINTED*/ + } while (0); + smb_rq_done(rqp); + return (error); +} + +int +smbfs_smb_setpattr(struct smbnode *np, uint32_t attr, + struct timespec *mtime, struct timespec *atime, + struct smb_cred *scrp) +{ + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + int error; + + /* + * This is the logic that was in smbfs_vnops.c + */ + if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) && + (vcp->vc_flags & SMBV_NT4) == 0) { + /* + * NT4 doesn't understand "NT" style SMBs; + * for NT4 we use the old SET_PATH_INFO + * XXX Actually, I think the issue is that + * NT requires an open handle for this. + */ + error = smbfs_smb_setpattrNT(np, + attr, mtime, atime, scrp); + if (error != EBADRPC) + return (error); + + /* NT4 response, remember */ + SMB_VC_LOCK(vcp); + vcp->vc_flags |= SMBV_NT4; + SMB_VC_UNLOCK(vcp); + } + + if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { + error = smbfs_smb_setpattr2(np, + attr, mtime, atime, scrp); + } else { + error = smbfs_smb_setpattr1(np, NULL, 0, + attr, mtime, scrp); + } + + return (error); +} + +/* + * Set DOS file attributes. mtime should be NULL for dialects above lm10 + */ +int +smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len, + uint32_t attr, struct timespec *mtime, + struct smb_cred *scrp) +{ + struct smb_rq rq, *rqp = &rq; + struct smb_share *ssp = np->n_mount->smi_share; + struct mbchain *mbp; + long time; + int error, svtz; + + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp); + if (error) + return (error); + svtz = SSTOVC(ssp)->vc_sopt.sv_tz; + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_uint16le(mbp, (uint16_t)attr); + if (mtime) { + smb_time_local2server(mtime, svtz, &time); + } else + time = 0; + mb_put_uint32le(mbp, time); /* mtime */ + mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint8(mbp, SMB_DT_ASCII); + do { + error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &len, '\\'); + if (error) + break; + mb_put_uint8(mbp, SMB_DT_ASCII); + if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) { + mb_put_padbyte(mbp); + mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */ + } + mb_put_uint8(mbp, 0); + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + if (error) + break; + /*LINTED*/ + } while (0); + smb_rq_done(rqp); + return (error); +} + +int +smbfs_smb_hideit(struct smbnode *np, const char *name, int len, + struct smb_cred *scrp) +{ + struct smbfattr fa; + int error; + uint32_t attr; + + error = smbfs_smb_query_info(np, name, len, &fa, scrp); + attr = fa.fa_attr; + if (!error && !(attr & SMB_FA_HIDDEN)) { + attr |= SMB_FA_HIDDEN; + error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp); + } + return (error); +} + + +int +smbfs_smb_unhideit(struct smbnode *np, const char *name, int len, + struct smb_cred *scrp) +{ + struct smbfattr fa; + uint32_t attr; + int error; + + error = smbfs_smb_query_info(np, name, len, &fa, scrp); + attr = fa.fa_attr; + if (!error && (attr & SMB_FA_HIDDEN)) { + attr &= ~SMB_FA_HIDDEN; + error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp); + } + return (error); +} + +/* + * Note, win95 doesn't support this call. + */ +int +smbfs_smb_setpattr2(struct smbnode *np, uint32_t attr, + struct timespec *mtime, struct timespec *atime, + struct smb_cred *scrp) +{ + struct smb_t2rq *t2p; + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + struct mbchain *mbp; + uint16_t date, time; + int error, tzoff; + + error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, + scrp, &t2p); + if (error) + return (error); + mbp = &t2p->t2_tparam; + mb_init(mbp); + mb_put_uint16le(mbp, SMB_SFILEINFO_STANDARD); + mb_put_uint32le(mbp, 0); /* MBZ */ + /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ + error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\'); + if (error) { + smb_t2_done(t2p); + return (error); + } + tzoff = vcp->vc_sopt.sv_tz; + mbp = &t2p->t2_tdata; + mb_init(mbp); + mb_put_uint32le(mbp, 0); /* creation time */ + if (atime) + smb_time_unix2dos(atime, tzoff, &date, &time, NULL); + else + time = date = 0; + mb_put_uint16le(mbp, date); + mb_put_uint16le(mbp, time); + if (mtime) + smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); + else + time = date = 0; + mb_put_uint16le(mbp, date); + mb_put_uint16le(mbp, time); + mb_put_uint32le(mbp, 0); /* file size */ + mb_put_uint32le(mbp, 0); /* allocation unit size */ + mb_put_uint16le(mbp, attr); /* DOS attr */ + mb_put_uint32le(mbp, 0); /* EA size */ + t2p->t2_maxpcount = 5 * 2; + t2p->t2_maxdcount = vcp->vc_txmax; + error = smb_t2_request(t2p); + smb_t2_done(t2p); + return (error); +} + +/* + * *BASIC_INFO works with Samba, but Win2K servers say it is an + * invalid information level on a SET_PATH_INFO. Note Win2K does + * support *BASIC_INFO on a SET_FILE_INFO, and they support the + * equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure. + */ +int +smbfs_smb_setpattrNT(struct smbnode *np, uint32_t attr, + struct timespec *mtime, struct timespec *atime, + struct smb_cred *scrp) +{ + struct smb_t2rq *t2p; + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + struct mbchain *mbp; + uint64_t tm; + int error, tzoff; + /* 64 bit value for Jan 1 1980 */ + PRIVSYM uint64_t DIFF1980TO1601 = 11960035200ULL*10000000ULL; + + error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, + scrp, &t2p); + if (error) + return (error); + mbp = &t2p->t2_tparam; + mb_init(mbp); + if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) + mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION); + else + mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFO); + mb_put_uint32le(mbp, 0); /* MBZ */ + /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ + error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\'); + if (error) { + smb_t2_done(t2p); + return (error); + } + tzoff = vcp->vc_sopt.sv_tz; + + /* do we know it won't support dates < 1980? */ + if (!(ssp->ss_flags & SMBS_1980)) { + mbp = &t2p->t2_tdata; + mb_init(mbp); + mb_put_uint64le(mbp, 0); /* creation time */ + if (atime) { + smb_time_local2NT(atime, tzoff, &tm); + } else + tm = 0; + mb_put_uint64le(mbp, tm); /* access time */ + if (mtime) { + smb_time_local2NT(mtime, tzoff, &tm); + } else + tm = 0; + mb_put_uint64le(mbp, tm); /* last write time */ + mb_put_uint64le(mbp, tm); /* change time */ + mb_put_uint32le(mbp, attr); /* attr */ + mb_put_uint32le(mbp, 0); /* undocumented padding */ + t2p->t2_maxpcount = 24; + t2p->t2_maxdcount = 56; + error = smb_t2_request(t2p); + } + /* + * "invalid argument" error probably means it's a + * FAT drive that doesn't accept dates earlier + * than 1980, so adjust dates and retry. If the + * 1980 flag is on we fell thru the if {} above + */ + if ((ssp->ss_flags & SMBS_1980) || (error == EINVAL)) { + mbp = &t2p->t2_tdata; + mb_init(mbp); + mb_put_uint64le(mbp, 0); /* creation time */ + if (atime) { + smb_time_local2NT(atime, tzoff, &tm); + if (tm < DIFF1980TO1601) + tm = DIFF1980TO1601; + } else + tm = 0; + mb_put_uint64le(mbp, tm); /* access time */ + if (mtime) { + smb_time_local2NT(mtime, tzoff, &tm); + if (tm < DIFF1980TO1601) + tm = DIFF1980TO1601; + } else + tm = 0; + mb_put_uint64le(mbp, tm); /* last write time */ + mb_put_uint64le(mbp, tm); /* change time */ + mb_put_uint32le(mbp, attr); /* attr */ + mb_put_uint32le(mbp, 0); /* undocumented padding */ + t2p->t2_maxpcount = 24; + t2p->t2_maxdcount = 56; + error = smb_t2_request(t2p); + + /* if this worked set flag to do the right thing next time */ + if (!(error)) { + SMB_SS_LOCK(ssp); + ssp->ss_flags |= SMBS_1980; + SMB_SS_UNLOCK(ssp); + } + } + smb_t2_done(t2p); + return (error); +} + +int +smbfs_smb_setfattr(struct smbnode *np, uint16_t fid, + uint32_t attr, struct timespec *mtime, + struct timespec *atime, struct smb_cred *scrp) +{ + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + int error; + + /* + * This is the logic that was in smbfs_vnops.c + * Might not be quite right for older dialects. + * (XXX: What about the DOS attributes?) + */ + if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) + error = smbfs_smb_setfattrNT(np, fid, + np->n_dosattr, mtime, atime, scrp); + else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) + error = smbfs_smb_setftime1(np, fid, + mtime, atime, scrp); + else + error = smbfs_smb_setpattr1(np, NULL, 0, + attr, mtime, scrp); + + return (error); +} + +/* + * Set file atime and mtime. Isn't supported by core dialect. + */ +int +smbfs_smb_setftime1( + struct smbnode *np, + uint16_t fid, + struct timespec *mtime, + struct timespec *atime, + struct smb_cred *scrp) +{ + struct smb_rq rq, *rqp = &rq; + struct smb_share *ssp = np->n_mount->smi_share; + struct mbchain *mbp; + uint16_t date, time; + int error, tzoff; + + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp); + if (error) + return (error); + tzoff = SSTOVC(ssp)->vc_sopt.sv_tz; + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); + mb_put_uint32le(mbp, 0); /* creation time */ + + if (atime) + smb_time_unix2dos(atime, tzoff, &date, &time, NULL); + else + time = date = 0; + mb_put_uint16le(mbp, date); + mb_put_uint16le(mbp, time); + if (mtime) + smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); + else + time = date = 0; + mb_put_uint16le(mbp, date); + mb_put_uint16le(mbp, time); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + SMBVDEBUG("%d\n", error); + smb_rq_done(rqp); + return (error); +} + +/* + * Set DOS file attributes. + * Looks like this call can be used only if CAP_NT_SMBS bit is on. + */ +int +smbfs_smb_setfattrNT(struct smbnode *np, uint16_t fid, + uint32_t attr, struct timespec *mtime, + struct timespec *atime, struct smb_cred *scrp) +{ + struct smb_t2rq *t2p; + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + struct mbchain *mbp; + uint64_t tm; + int error, svtz; + + error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, + scrp, &t2p); + if (error) + return (error); + svtz = SSTOVC(ssp)->vc_sopt.sv_tz; + mbp = &t2p->t2_tparam; + mb_init(mbp); + mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); + if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) + mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION); + else + mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFO); + mb_put_uint32le(mbp, 0); /* XXX should be 16 not 32(?) */ + mbp = &t2p->t2_tdata; + mb_init(mbp); + mb_put_uint64le(mbp, 0); /* creation time */ + if (atime) { + smb_time_local2NT(atime, svtz, &tm); + } else + tm = 0; + mb_put_uint64le(mbp, tm); /* access time */ + if (mtime) { + smb_time_local2NT(mtime, svtz, &tm); + } else + tm = 0; + mb_put_uint64le(mbp, tm); /* last write time */ + mb_put_uint64le(mbp, tm); /* change time */ + mb_put_uint32le(mbp, attr); + mb_put_uint32le(mbp, 0); /* padding */ + t2p->t2_maxpcount = 2; + t2p->t2_maxdcount = 0; + error = smb_t2_request(t2p); + smb_t2_done(t2p); + return (error); +} + +/* + * Modern create/open of file or directory. + * + * If disp is ..._DISP_OPEN, or ...DISP_OPEN_IF, or... + * then this is an open attempt, and: + * If xattr then name is the stream to be opened at np, + * Else np should be opened. + * ...we won't touch *fidp, + * ...we will set or clear *attrcacheupdated. + * Else this is a creation attempt, and: + * If xattr then name is the stream to create at np, + * Else name is the thing to create under directory np. + * ...we will return *fidp, + * ...we won't touch *attrcacheupdated. + * + * Note, We use: disp = ...OPEN_IF, ...OVERWRITE_IF, etc. + * now too, which may or may not create a new object. + */ +int +smbfs_smb_ntcreatex(struct smbnode *np, uint32_t rights, + struct smb_cred *scrp, enum vtype vt, + int *attrcacheupdated, uint16_t *fidp, + const char *name, int nmlen, uint32_t disp, int xattr, + len_t *sizep, uint32_t *rightsp) +{ + struct smb_rq rq, *rqp = &rq; + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + struct mbchain *mbp; + struct mdchain *mdp; + struct smbfattr fap; + uint8_t wc; + uint32_t longint, createact, createopt, efa; + uint64_t llongint; + int error; + uint16_t fid, *namelenp; + + /* + * Set the File attributes and Create options. + * WinXP uses EFA_NORMAL in all of these cases. + */ + createopt = (vt == VDIR) ? + NTCREATEX_OPTIONS_DIRECTORY : + NTCREATEX_OPTIONS_NON_DIRECTORY_FILE; + efa = SMB_EFA_NORMAL; + if (disp != NTCREATEX_DISP_OPEN && !xattr) { + if (name && *name == '.') + efa = SMB_EFA_HIDDEN; + } + + gethrestime(&fap.fa_reqtime); + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_uint8(mbp, 0xff); /* secondary command */ + mb_put_uint8(mbp, 0); /* MBZ */ + mb_put_uint16le(mbp, 0); /* offset to next command (none) */ + mb_put_uint8(mbp, 0); /* MBZ */ + namelenp = (uint16_t *)mb_reserve(mbp, sizeof (uint16_t)); + /* + * XP to a W2K Server does not use NTCREATEX_FLAGS_OPEN_DIRECTORY + * for creating nor for opening a directory. Samba ignores the bit. + */ +#if 0 /* causes sharing violation when making dir on W2K! */ + mb_put_uint32le(mbp, vt == VDIR ? NTCREATEX_FLAGS_OPEN_DIRECTORY : 0); +#else + mb_put_uint32le(mbp, 0); /* NTCREATEX_FLAGS_* */ +#endif + mb_put_uint32le(mbp, 0); /* FID - basis for path if not root */ + mb_put_uint32le(mbp, rights); + mb_put_uint64le(mbp, 0); /* "initial allocation size" */ + mb_put_uint32le(mbp, efa); + mb_put_uint32le(mbp, NTCREATEX_SHARE_ACCESS_ALL); + mb_put_uint32le(mbp, disp); + mb_put_uint32le(mbp, createopt); + mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */ + mb_put_uint8(mbp, 0); /* security flags (?) */ + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + do { + if (name == NULL) + nmlen = 0; + error = smbfs_fullpath(mbp, vcp, np, name, &nmlen, + xattr ? ':' : '\\'); + if (error) + break; + *namelenp = htoles(nmlen); /* includes null */ + smb_rq_bend(rqp); + /* + * Don't want to risk missing a successful + * open response, or we could "leak" FIDs. + */ + rqp->sr_flags |= SMBR_NOINTR_RECV; + error = smb_rq_simple_timed(rqp, smb_timo_open); + if (error) + break; + smb_rq_getreply(rqp, &mdp); + /* + * spec says 26 for word count, but 34 words are defined + * and observed from win2000 + */ + if (md_get_uint8(mdp, &wc) != 0 || + (wc != 26 && wc != 34 && wc != 42)) { + error = EBADRPC; + break; + } + md_get_uint8(mdp, NULL); /* secondary cmd */ + md_get_uint8(mdp, NULL); /* mbz */ + md_get_uint16le(mdp, NULL); /* andxoffset */ + md_get_uint8(mdp, NULL); /* oplock lvl granted */ + md_get_uint16(mdp, &fid); /* yes, leaving it LE */ + md_get_uint32le(mdp, &createact); /* create_action */ + md_get_uint64le(mdp, &llongint); /* creation time */ + md_get_uint64le(mdp, &llongint); /* access time */ + if (llongint) /* avoid bogus 0 time (on FAT roots) */ + smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz, + &fap.fa_atime); + md_get_uint64le(mdp, &llongint); /* write time */ + if (llongint) /* avoid bogus 0 time (on FAT roots) */ + smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz, + &fap.fa_mtime); + md_get_uint64le(mdp, &llongint); /* change time */ + if (llongint) /* avoid bogus 0 time (on FAT roots) */ + smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz, + &fap.fa_ctime); + md_get_uint32le(mdp, &longint); /* attributes */ + fap.fa_attr = longint; + md_get_uint64le(mdp, NULL); /* allocation size */ + md_get_uint64le(mdp, &llongint); /* EOF */ + fap.fa_size = llongint; + if (sizep) + *sizep = fap.fa_size; + md_get_uint16le(mdp, NULL); /* file type */ + md_get_uint16le(mdp, NULL); /* device state */ + md_get_uint8(mdp, NULL); /* directory (boolean) */ + /*LINTED*/ + } while (0); + smb_rq_done(rqp); + if (error) + return (error); + if (fidp) + *fidp = fid; + if (rightsp) + *rightsp = rights; + /* + * Is it possible that we have cached attributes? + * Assume "not cached" if we created the object. + */ + if (createact == NTCREATEX_ACTION_CREATED || xattr) + goto uncached; + if (attrcacheupdated) + *attrcacheupdated = 0; + /* + * Update the cached attributes if they are still valid + * in the cache and if nothing has changed. + */ + if (np->r_vnode == NULL) + goto uncached; + if (smbfs_attr_cachelookup(np->r_vnode, NULL) != 0) + goto uncached; /* the cached attributes are not valid */ + if (fap.fa_size != np->n_size) + goto uncached; /* the size is different */ + if (fap.fa_attr != np->n_dosattr) + goto uncached; /* the attrs are different */ + /* + * fap.fa_mtime is in two second increments while np->n_mtime + * may be in one second increments, so comparing the times is + * somewhat sloppy. + * + * XXX: true fap.fa_mtime resolution must depend upon server's + * local filesystem and is thus indeterminate... XXX ...TBD how that + * affects this code... note wire resolution here is 100ns versus + * 1sec down in smbfs_smb_oldopen(SMB_COM_OPEN) + */ + if (fap.fa_mtime.tv_sec != np->n_mtime.tv_sec && + fap.fa_mtime.tv_sec != np->n_mtime.tv_sec - 1 && + fap.fa_mtime.tv_sec != np->n_mtime.tv_sec + 1) + goto uncached; /* the mod time is different */ + + fap.fa_mtime.tv_sec = np->n_mtime.tv_sec; /* keep higher res time */ + smbfs_attr_cacheenter(np->r_vnode, &fap); + if (attrcacheupdated) + *attrcacheupdated = 1; +uncached: + return (0); +} + +static uint32_t +smb_mode2rights(int mode) +{ + mode = mode & SMB_AM_OPENMODE; + + switch (mode) { + case SMB_AM_OPENREAD: + return (GENERIC_RIGHT_READ_ACCESS); + case SMB_AM_OPENWRITE: + return (GENERIC_RIGHT_WRITE_ACCESS); + case SMB_AM_OPENRW: + return (GENERIC_RIGHT_ALL_ACCESS); + case SMB_AM_OPENEXEC: + return (GENERIC_RIGHT_EXECUTE_ACCESS); + } + return (0); +} + +static int +smb_rights2mode(uint32_t rights) +{ + int accmode = SMB_AM_OPENEXEC; /* our fallback */ + + if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD | + SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES | + SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS | + STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS | + GENERIC_RIGHT_ALL_ACCESS | GENERIC_RIGHT_WRITE_ACCESS)) + accmode = SMB_AM_OPENWRITE; + if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES | + SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS | + GENERIC_RIGHT_ALL_ACCESS | GENERIC_RIGHT_READ_ACCESS)) + accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD + : SMB_AM_OPENRW; + return (accmode); +} + +static int +smbfs_smb_oldopen(struct smbnode *np, int accmode, struct smb_cred *scrp, + int *attrcacheupdated, uint16_t *fidp, const char *name, + int nmlen, int xattr, len_t *sizep, uint32_t *rightsp) +{ + struct smb_rq rq, *rqp = &rq; + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + struct mbchain *mbp; + struct mdchain *mdp; + struct smbfattr fap; + uint8_t wc; + uint16_t fid, wattr, grantedmode; + uint32_t longint; + int error; + + /* + * Use DENYNONE to give unixy semantics of permitting + * everything not forbidden by permissions. Ie denial + * is up to server with clients/openers needing to use + * advisory locks for further control. + */ + accmode |= SMB_SM_DENYNONE; + + gethrestime(&fap.fa_reqtime); + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_uint16le(mbp, accmode); + mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY | + SMB_FA_DIR); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint8(mbp, SMB_DT_ASCII); + do { + error = smbfs_fullpath(mbp, vcp, np, name, &nmlen, + xattr ? ':' : '\\'); + if (error) + break; + smb_rq_bend(rqp); + /* + * Don't want to risk missing a successful + * open response, or we could "leak" FIDs. + */ + rqp->sr_flags |= SMBR_NOINTR_RECV; + error = smb_rq_simple_timed(rqp, smb_timo_open); + if (error) + break; + smb_rq_getreply(rqp, &mdp); + /* + * 8/2002 a DAVE server returned wc of 15 so we ignore that. + * (the actual packet length and data was correct) + */ + if (md_get_uint8(mdp, &wc) != 0 || (wc != 7 && wc != 15)) { + error = EBADRPC; + break; + } + md_get_uint16(mdp, &fid); /* yes, we leave it LE */ + md_get_uint16le(mdp, &wattr); + fap.fa_attr = wattr; + /* + * Be careful using the time returned here, as + * with FAT on NT4SP6, at least, the time returned is low + * 32 bits of 100s of nanoseconds (since 1601) so it rolls + * over about every seven minutes! + */ + md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */ + if (longint) /* avoid bogus zero returns */ + smb_time_server2local(longint, vcp->vc_sopt.sv_tz, + &fap.fa_mtime); + md_get_uint32le(mdp, &longint); + fap.fa_size = longint; + if (sizep) + *sizep = fap.fa_size; + md_get_uint16le(mdp, &grantedmode); + /*LINTED*/ + } while (0); + smb_rq_done(rqp); + if (error) + return (error); + if (fidp) + *fidp = fid; + if (xattr) + goto uncached; + if (rightsp) + *rightsp = smb_mode2rights(grantedmode); + if (attrcacheupdated) + *attrcacheupdated = 0; + /* + * Update the cached attributes if they are still valid + * in the cache and if nothing has changed. + * Note that this won't ever update if the file size is + * greater than the 32-bits returned by SMB_COM_OPEN. + * For 64-bit file sizes, SMB_COM_NT_CREATE_ANDX must + * be used instead of SMB_COM_OPEN. + */ + if (np->r_vnode == NULL) + goto uncached; + if (smbfs_attr_cachelookup(np->r_vnode, NULL) != 0) + goto uncached; /* the cached attributes are not valid */ + if (fap.fa_size != np->n_size) + goto uncached; /* the size is different */ + if (fap.fa_attr != np->n_dosattr) + goto uncached; /* the attrs are different */ + /* + * fap.fa_mtime is in two second increments while np->n_mtime + * may be in one second increments, so comparing the times is + * somewhat sloppy. + */ + if (fap.fa_mtime.tv_sec != np->n_mtime.tv_sec && + fap.fa_mtime.tv_sec != np->n_mtime.tv_sec - 1 && + fap.fa_mtime.tv_sec != np->n_mtime.tv_sec + 1) + goto uncached; /* the mod time is different */ + + fap.fa_mtime.tv_sec = np->n_mtime.tv_sec; /* keep higher res time */ + smbfs_attr_cacheenter(np->r_vnode, &fap); + if (attrcacheupdated) + *attrcacheupdated = 1; +uncached: + return (0); +} + +int +smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, + uint16_t *fidp) +{ + struct smb_vc *vcp = SSTOVC(np->n_mount->smi_share); + enum vtype vt = VREG; + int error; + + /* Shared lock for n_fid use below. */ + ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); + + mutex_enter(&np->r_statelock); + if (np->n_fidrefs && (rights & np->n_rights) == rights) { + np->n_fidrefs++; + *fidp = np->n_fid; + mutex_exit(&np->r_statelock); + return (0); + } + mutex_exit(&np->r_statelock); + + if (!(vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) { + int mode = smb_rights2mode(rights); + error = smbfs_smb_oldopen(np, mode, scrp, + NULL, fidp, NULL, 0, 0, NULL, NULL); + } else { + if (SMBTOV(np)) + vt = SMBTOV(np)->v_type; + error = smbfs_smb_ntcreatex(np, rights, scrp, vt, + NULL, fidp, NULL, 0, NTCREATEX_DISP_OPEN, 0, + NULL, NULL); + } + + if (*fidp == np->n_fid) { + /* + * Oh no, the server gave us the same FID again? + * This will cause us to close np->n_fid early! + */ + SMBVDEBUG("duplicate fid: 0x%x\n", *fidp); + } + + return (error); +} + +int +smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp) +{ + struct smb_share *ssp = np->n_mount->smi_share; + int error = 0; + uint16_t oldfid = SMB_FID_UNUSED; + + /* Shared lock for n_fid use below. */ + ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); + + mutex_enter(&np->r_statelock); + if (fid == np->n_fid) { + ASSERT(np->n_fidrefs > 0); + if (--np->n_fidrefs == 0) { + /* + * Don't expect to find the last reference + * here in tmpclose. Hard to deal with as + * we don't have r_lkserlock exclusive. + * Will close oldfid below. + */ + oldfid = np->n_fid; + np->n_fid = SMB_FID_UNUSED; + } + } else { + /* Will close the passed fid. */ + oldfid = fid; + } + mutex_exit(&np->r_statelock); + + if (oldfid != SMB_FID_UNUSED) + error = smbfs_smb_close(ssp, oldfid, NULL, scrp); + + return (error); +} + +int +smbfs_smb_open(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, + int *attrcacheupdated, uint16_t *fidp, const char *name, + int nmlen, int xattr, len_t *sizep, uint32_t *rightsp) +{ + int error; + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + enum vtype vt = VREG; + + if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { + if (SMBTOV(np)) + vt = SMBTOV(np)->v_type; + error = smbfs_smb_ntcreatex(np, rights, scrp, vt, + attrcacheupdated, fidp, name, nmlen, + NTCREATEX_DISP_OPEN, xattr, sizep, rightsp); + } else { + error = smbfs_smb_oldopen(np, smb_rights2mode(rights), scrp, + attrcacheupdated, fidp, name, nmlen, xattr, sizep, rightsp); + } +#if 0 /* let caller do this */ + if (!error && !name) + np->n_fidrefs++; +#endif + return (error); +} + +int +smbfs_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime, + struct smb_cred *scrp) +{ + struct smb_rq rq, *rqp = &rq; + struct mbchain *mbp; + long time; + int error; + + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scrp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM); + if (mtime) { + smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time); + } else + time = 0; + mb_put_uint32le(mbp, time); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + smb_rq_bend(rqp); + + /* + * We don't really care about the result here, but we + * do need to make sure we send this out, or we could + * "leak" open file handles on interrupt or timeout. + * The NOINTR_SEND flag makes this request immune to + * interrupt or timeout until the send is done. + */ + rqp->sr_flags |= SMBR_NOINTR_SEND; + error = smb_rq_simple(rqp); + smb_rq_done(rqp); + /* + * ENOTCONN isn't interesting - if the connection is closed, + * so are all our FIDs - and EIO is also not interesting, + * as it means a forced unmount was done. (was ENXIO) + * Also ETIME, which means we sent the request but gave up + * waiting before the response came back. + * + * Don't clog up the system log with warnings about these + * uninteresting failures on closes. + */ + switch (error) { + case ENOTCONN: + case ENXIO: + case EIO: + case ETIME: + error = 0; + } + return (error); +} + +static int +smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen, + struct smb_cred *scrp, uint16_t *fidp, int xattr) +{ + struct smb_rq rq, *rqp = &rq; + struct smb_share *ssp = dnp->n_mount->smi_share; + struct mbchain *mbp; + struct mdchain *mdp; + struct timespec ctime; + uint8_t wc; + long tm; + int error; + uint16_t attr = SMB_FA_ARCHIVE; + + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + if (name && *name == '.') + attr |= SMB_FA_HIDDEN; + mb_put_uint16le(mbp, attr); /* attributes */ + gethrestime(&ctime); + smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); + mb_put_uint32le(mbp, tm); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint8(mbp, SMB_DT_ASCII); + error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &nmlen, + xattr ? ':' : '\\'); + if (!error) { + smb_rq_bend(rqp); + /* + * Don't want to risk missing a successful + * open response, or we could "leak" FIDs. + */ + rqp->sr_flags |= SMBR_NOINTR_RECV; + error = smb_rq_simple_timed(rqp, smb_timo_open); + if (!error) { + smb_rq_getreply(rqp, &mdp); + md_get_uint8(mdp, &wc); + if (wc == 1) + md_get_uint16(mdp, fidp); + else + error = EBADRPC; + } + } + smb_rq_done(rqp); + return (error); +} + +int +smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, + struct smb_cred *scrp, uint16_t *fidp, uint32_t disp, int xattr) +{ + struct smb_vc *vcp = SSTOVC(dnp->n_mount->smi_share); + + /* + * At present the only access we might need is to WRITE data, + * and that only if we are creating a "symlink". When/if the + * access needed gets more complex it should made a parameter + * and be set upstream. + */ + if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { + return (smbfs_smb_ntcreatex(dnp, SA_RIGHT_FILE_WRITE_DATA, + scrp, VREG, NULL, fidp, name, nmlen, disp, xattr, + NULL, NULL)); + } else + return (smbfs_smb_oldcreate(dnp, name, nmlen, scrp, fidp, + xattr)); +} + +int +smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name, + int nmlen, int xattr) +{ + struct smb_rq rq, *rqp = &rq; + struct smb_share *ssp = np->n_mount->smi_share; + struct mbchain *mbp; + int error; + + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint8(mbp, SMB_DT_ASCII); + error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &nmlen, + xattr ? ':' : '\\'); + if (!error) { + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + } + smb_rq_done(rqp); + return (error); +} + +int +smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, + const char *tname, int tnmlen, struct smb_cred *scrp) +{ + struct smb_rq rq, *rqp = &rq; + struct smb_share *ssp = src->n_mount->smi_share; + struct mbchain *mbp; + int error; + uint16_t fa; + + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + /* freebsd bug: Let directories be renamed - Win98 requires DIR bit */ + fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0; + fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN; + mb_put_uint16le(mbp, fa); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint8(mbp, SMB_DT_ASCII); + do { + error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, '\\'); + if (error) + break; + mb_put_uint8(mbp, SMB_DT_ASCII); + error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen, + '\\'); + if (error) + break; + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + /*LINTED*/ + } while (0); + smb_rq_done(rqp); + return (error); +} + +int +smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, + const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp) +{ + struct smb_rq rq, *rqp = &rq; + struct smb_share *ssp = src->n_mount->smi_share; + struct mbchain *mbp; + int error; + + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_uint16le(mbp, SMB_TID_UNKNOWN); + mb_put_uint16le(mbp, 0x20); /* delete target file */ + mb_put_uint16le(mbp, flags); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint8(mbp, SMB_DT_ASCII); + do { + error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, '\\'); + if (error) + break; + mb_put_uint8(mbp, SMB_DT_ASCII); + error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen, + '\\'); + if (error) + break; + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + /*LINTED*/ + } while (0); + smb_rq_done(rqp); + return (error); +} + +static int +smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len, + struct smb_cred *scrp) +{ + struct smb_rq rq, *rqp = &rq; + struct smb_share *ssp = dnp->n_mount->smi_share; + struct mbchain *mbp; + int error; + + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint8(mbp, SMB_DT_ASCII); + error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &len, '\\'); + if (!error) { + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + } + smb_rq_done(rqp); + return (error); +} + +int +smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len, + struct smb_cred *scrp) +{ + struct smb_share *ssp = dnp->n_mount->smi_share; + uint16_t fid; + int error; + + /* + * We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but + * just to be asking for something. The rights==0 case could + * easily be broken on some old or unusual servers. + */ + if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { + error = smbfs_smb_ntcreatex(dnp, SA_RIGHT_FILE_READ_DATA, + scrp, VDIR, NULL, &fid, name, len, + NTCREATEX_DISP_CREATE, 0, NULL, NULL); + if (error) + return (error); + error = smbfs_smb_close(ssp, fid, NULL, scrp); + if (error) + SMBERROR("error %d closing fid %d\n", error, fid); + return (0); + } else + return (smbfs_smb_oldmkdir(dnp, name, len, scrp)); +} + +int +smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp) +{ + struct smb_rq rq, *rqp = &rq; + struct smb_share *ssp = np->n_mount->smi_share; + struct mbchain *mbp; + int error; + + error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint8(mbp, SMB_DT_ASCII); + error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, NULL, '\\'); + if (!error) { + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + } + smb_rq_done(rqp); + return (error); +} + +static int +smbfs_smb_search(struct smbfs_fctx *ctx) +{ + struct smb_vc *vcp = SSTOVC(ctx->f_ssp); + struct smb_rq *rqp; + struct mbchain *mbp; + struct mdchain *mdp; + uint8_t wc, bt; + uint16_t ec, dlen, bc; + int len, maxent, error, iseof = 0; + + maxent = min(ctx->f_left, + (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN); + if (ctx->f_rq) { + smb_rq_done(ctx->f_rq); + ctx->f_rq = NULL; + } + error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, + ctx->f_scred, &rqp); + if (error) + return (error); + ctx->f_rq = rqp; + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_uint16le(mbp, maxent); /* max entries to return */ + mb_put_uint16le(mbp, ctx->f_attrmask); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ + if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { + len = ctx->f_wclen; + error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, + &len, '\\'); + if (error) + return (error); + mb_put_uint8(mbp, SMB_DT_VARIABLE); + mb_put_uint16le(mbp, 0); /* context length */ + ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; + } else { + if (SMB_UNICODE_STRINGS(vcp)) { + mb_put_padbyte(mbp); + mb_put_uint8(mbp, 0); + } + mb_put_uint8(mbp, 0); + mb_put_uint8(mbp, SMB_DT_VARIABLE); + mb_put_uint16le(mbp, SMB_SKEYLEN); + mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); + } + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) { + error = 0; + iseof = 1; + ctx->f_flags |= SMBFS_RDD_EOF; + } else if (error) + return (error); + smb_rq_getreply(rqp, &mdp); + md_get_uint8(mdp, &wc); + if (wc != 1) + return (iseof ? ENOENT : EBADRPC); + md_get_uint16le(mdp, &ec); + if (ec == 0) + return (ENOENT); + ctx->f_ecnt = ec; + md_get_uint16le(mdp, &bc); + if (bc < 3) + return (EBADRPC); + bc -= 3; + md_get_uint8(mdp, &bt); + if (bt != SMB_DT_VARIABLE) + return (EBADRPC); + md_get_uint16le(mdp, &dlen); + if (dlen != bc || dlen % SMB_DENTRYLEN != 0) + return (EBADRPC); + return (0); +} + + +/*ARGSUSED*/ +static int +smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp, + const char *wildcard, int wclen, uint16_t attr, struct smb_cred *scrp) +{ + /* #pragma unused(dnp, scrp) */ + ctx->f_attrmask = attr; + if (wildcard) { + if (wclen == 1 && wildcard[0] == '*') { + ctx->f_wildcard = "*.*"; + ctx->f_wclen = 3; + } else { + ctx->f_wildcard = wildcard; + ctx->f_wclen = wclen; + } + } else { + ctx->f_wildcard = NULL; + ctx->f_wclen = 0; + } + ctx->f_name = (char *)ctx->f_fname; + ctx->f_namesz = 0; + return (0); +} + +static int +smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit) +{ + struct mdchain *mdp; + struct smb_rq *rqp; + char *cp; + uint8_t battr; + uint16_t date, time; + uint32_t size; + int error; + struct timespec ts; + + if (ctx->f_ecnt == 0) { + if (ctx->f_flags & SMBFS_RDD_EOF) + return (ENOENT); + ctx->f_left = ctx->f_limit = limit; + gethrestime(&ts); + error = smbfs_smb_search(ctx); + if (error) + return (error); + ctx->f_attr.fa_reqtime = ts; + } + rqp = ctx->f_rq; + smb_rq_getreply(rqp, &mdp); + md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); + md_get_uint8(mdp, &battr); + md_get_uint16le(mdp, &time); + md_get_uint16le(mdp, &date); + md_get_uint32le(mdp, &size); + cp = ctx->f_name; + md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM); + cp[sizeof (ctx->f_fname) - 1] = 0; + cp += strlen(cp) - 1; + while (*cp == ' ' && cp >= ctx->f_name) + *cp-- = 0; + ctx->f_attr.fa_attr = battr; + smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz, + &ctx->f_attr.fa_mtime); + ctx->f_attr.fa_size = size; + ctx->f_nmlen = strlen(ctx->f_name); + ctx->f_ecnt--; + ctx->f_left--; + return (0); +} + +static int +smbfs_smb_findcloseLM1(struct smbfs_fctx *ctx) +{ + if (ctx->f_rq) + smb_rq_done(ctx->f_rq); + return (0); +} + +/* + * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect + */ +static int +smbfs_smb_trans2find2(struct smbfs_fctx *ctx) +{ + struct smb_t2rq *t2p; + struct smb_vc *vcp = SSTOVC(ctx->f_ssp); + struct mbchain *mbp; + struct mdchain *mdp; + uint16_t tw, flags; + int len, error; + + if (ctx->f_t2) { + smb_t2_done(ctx->f_t2); + ctx->f_t2 = NULL; + } + ctx->f_flags &= ~SMBFS_RDD_GOTRNAME; + flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS; + if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { + flags |= FIND2_CLOSE_AFTER_REQUEST; + ctx->f_flags |= SMBFS_RDD_NOCLOSE; + } + if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { + error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2, + ctx->f_scred, &t2p); + if (error) + return (error); + ctx->f_t2 = t2p; + mbp = &t2p->t2_tparam; + mb_init(mbp); + mb_put_uint16le(mbp, ctx->f_attrmask); + mb_put_uint16le(mbp, ctx->f_limit); + mb_put_uint16le(mbp, flags); + mb_put_uint16le(mbp, ctx->f_infolevel); + mb_put_uint32le(mbp, 0); + /* mb_put_uint8(mbp, SMB_DT_ASCII); specs? hah! */ + len = ctx->f_wclen; + error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, + &len, '\\'); + if (error) + return (error); + } else { + error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2, + ctx->f_scred, &t2p); + if (error) + return (error); + ctx->f_t2 = t2p; + mbp = &t2p->t2_tparam; + mb_init(mbp); + mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); + mb_put_uint16le(mbp, ctx->f_limit); + mb_put_uint16le(mbp, ctx->f_infolevel); + if (ctx->f_ssp->ss_flags & SMBS_RESUMEKEYS) { + mb_put_uint32le(mbp, ctx->f_rkey); + } else + mb_put_uint32le(mbp, 0); + mb_put_uint16le(mbp, flags); + if (ctx->f_rname) { + /* resume file name */ + mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen, + MB_MSYSTEM); + } + /* Add trailing null - 1 byte if ASCII, 2 if Unicode */ + if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) + mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */ + mb_put_uint8(mbp, 0); +#if 0 + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 200 * 1000 * 1000; /* 200ms */ + if (vcp->vc_flags & SMBC_WIN95) { + /* + * some implementations suggests to sleep here + * for 200ms, due to the bug in the Win95. + * I've didn't notice any problem, but put code + * for it. + */ + msleep(&flags, 0, PVFS, "fix95", &ts); + } +#endif + } + t2p->t2_maxpcount = 5 * 2; + t2p->t2_maxdcount = vcp->vc_txmax; + error = smb_t2_request(t2p); + if (error) + return (error); + mdp = &t2p->t2_rparam; + if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { + if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0) + return (error); + ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; + } + if ((error = md_get_uint16le(mdp, &tw)) != 0) + return (error); + ctx->f_ecnt = tw; /* search count - # entries returned */ + if ((error = md_get_uint16le(mdp, &tw)) != 0) + return (error); + /* + * tw now is the "end of search" flag. against an XP server tw + * comes back zero when the prior find_next returned exactly + * the number of entries requested. in which case we'd try again + * but the search has in fact been closed so an EBADF results. our + * circumvention is to check here for a zero search count. + */ + if (tw || ctx->f_ecnt == 0) + ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; + if ((error = md_get_uint16le(mdp, &tw)) != 0) + return (error); + if ((error = md_get_uint16le(mdp, &tw)) != 0) + return (error); + if (ctx->f_ecnt == 0) + return (ENOENT); + ctx->f_rnameofs = tw; + mdp = &t2p->t2_rdata; + if (mdp->md_top == NULL) { + SMBVDEBUG("ecnt = %d, but data is NULL\n", ctx->f_ecnt); + return (ENOENT); + } +#ifdef APPLE + if (mdp->md_top->m_len == 0) { + printf("bug: ecnt = %d, but m_len = 0 and m_next = %p " + "(please report)\n", ctx->f_ecnt, mbp->mb_top->m_next); + return (ENOENT); + } +#endif + ctx->f_eofs = 0; + return (0); +} + +static int +smbfs_smb_findclose2(struct smbfs_fctx *ctx) +{ + struct smb_rq rq, *rqp = &rq; + struct mbchain *mbp; + int error; + + error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, + ctx->f_scred); + if (error) + return (error); + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + smb_rq_bend(rqp); + /* Ditto comments at _smb_close */ + rqp->sr_flags |= SMBR_NOINTR_SEND; + error = smb_rq_simple(rqp); + smb_rq_done(rqp); + return (error); +} + +/*ARGSUSED*/ +static int +smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, + const char *wildcard, int wclen, uint16_t attr, struct smb_cred *scrp) +{ + ctx->f_namesz = SMB_MAXFNAMELEN; + if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) + ctx->f_namesz *= 2; + ctx->f_name = kmem_zalloc(ctx->f_namesz, KM_SLEEP); + ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) + < SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD : + SMB_FIND_BOTH_DIRECTORY_INFO; + ctx->f_attrmask = attr; + ctx->f_wildcard = wildcard; + ctx->f_wclen = wclen; + return (0); +} + +static int +smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit) +{ + struct mdchain *mdp; + struct smb_t2rq *t2p; + char *cp; + uint8_t tb; + uint16_t date, time, wattr; + uint32_t size, next, dattr, resumekey = 0; + uint64_t llongint; + int error, svtz, cnt, fxsz, nmlen, recsz, otw; + struct timespec ts; + +again: + otw = 0; /* nothing sent Over The Wire (yet) */ + if (ctx->f_ecnt == 0) { + if (ctx->f_flags & SMBFS_RDD_EOF) + return (ENOENT); + ctx->f_left = ctx->f_limit = limit; + gethrestime(&ts); + error = smbfs_smb_trans2find2(ctx); + if (error) + return (error); + ctx->f_attr.fa_reqtime = ts; + ctx->f_otws++; + otw = 1; + } + t2p = ctx->f_t2; + mdp = &t2p->t2_rdata; + svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz; + switch (ctx->f_infolevel) { + case SMB_FIND_STANDARD: + next = 0; + fxsz = 0; + md_get_uint16le(mdp, &date); + md_get_uint16le(mdp, &time); /* creation time */ + md_get_uint16le(mdp, &date); + md_get_uint16le(mdp, &time); /* access time */ + smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime); + md_get_uint16le(mdp, &date); + md_get_uint16le(mdp, &time); /* modify time */ + smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime); + md_get_uint32le(mdp, &size); + ctx->f_attr.fa_size = size; + md_get_uint32(mdp, NULL); /* allocation size */ + md_get_uint16le(mdp, &wattr); + ctx->f_attr.fa_attr = wattr; + md_get_uint8(mdp, &tb); + size = nmlen = tb; + fxsz = 23; + recsz = next = 24 + nmlen; /* docs misses zero byte @end */ + break; + case SMB_FIND_DIRECTORY_INFO: + case SMB_FIND_BOTH_DIRECTORY_INFO: + md_get_uint32le(mdp, &next); + md_get_uint32le(mdp, &resumekey); /* file index (resume key) */ + md_get_uint64(mdp, NULL); /* creation time */ + md_get_uint64le(mdp, &llongint); + smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_atime); + md_get_uint64le(mdp, &llongint); + smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_mtime); + md_get_uint64le(mdp, &llongint); + smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_ctime); + md_get_uint64le(mdp, &llongint); /* file size */ + ctx->f_attr.fa_size = llongint; + md_get_uint64(mdp, NULL); /* real size (should use) */ + /* freebsd bug: fa_attr endian bug */ + md_get_uint32le(mdp, &dattr); /* extended file attributes */ + ctx->f_attr.fa_attr = dattr; + md_get_uint32le(mdp, &size); /* name len */ + fxsz = 64; /* size ofinfo up to filename */ + if (ctx->f_infolevel == SMB_FIND_BOTH_DIRECTORY_INFO) { + /* + * Skip EaSize(4 bytes), a byte of ShortNameLength, + * a reserved byte, and ShortName(8.3 means 24 bytes, + * as Leach defined it to always be Unicode) + */ + md_get_mem(mdp, NULL, 30, MB_MSYSTEM); + fxsz += 30; + } + recsz = next ? next : fxsz + size; + break; + default: + SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel); + return (EINVAL); + } + if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) + nmlen = min(size, SMB_MAXFNAMELEN * 2); + else + nmlen = min(size, SMB_MAXFNAMELEN); + if (ctx->f_name) + kmem_free(ctx->f_name, ctx->f_namesz); + cp = ctx->f_name = kmem_alloc(nmlen, KM_SLEEP); + ctx->f_namesz = nmlen; + error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM); + if (error) + return (error); + if (next) { + cnt = next - nmlen - fxsz; + if (cnt > 0) + md_get_mem(mdp, NULL, cnt, MB_MSYSTEM); + else if (cnt < 0) { + SMBVDEBUG("out of sync\n"); + return (EBADRPC); + } + } + /* Don't count any trailing null in the name. */ + if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { + if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0) + nmlen -= 2; + } else { + if (nmlen && cp[nmlen - 1] == 0) + nmlen--; + } + if (nmlen == 0) + return (EBADRPC); + + /* + * Ref radar 3983209. On a find-next we expect a server will + * 1) if the continue bit is set, use the server's idea of current loc, + * 2) else if the resume key is non-zero, use that location, + * 3) else if the resume name is set, use that location, + * 4) else use the server's idea of current location. + * + * Current NetApps don't do that. If we send no continue bit, a zero + * resume key, and a resume name, the NetApp ignores the resume name + * and acts on the (zero) resume key, sending back the start of the + * directory again. Panther doesn't expose the netapp bug; Panther used + * the continue bit, but that was changed for 2866172. Win2000 as a + * client also relies upon the resume name, but they request a very + * large number of files, so the bug would be seen only with very + * large directories. + * + * Our fix is to notice if the second OTW op (the first find-next) + * returns, in the first filename, the same filename we got back + * at the start of the first OTW (the find-first). In that case + * we've detected the server bug and set SMBS_RESUMEKEYS, causing us + * to send non-zero resume keys henceforth. + * + * Caveat: if there's a netapp so old it doesn't negotiate NTLM 0.12 + * then we get no resume keys so f_rkey stays zero and this "fix" + * changes nothing. + * + * Note due to a similar problem (4051871) we also set SMBS_RESUMEKEYS + * for FAT volumes, at mount time. + */ + if (otw && !(ctx->f_ssp->ss_flags & SMBS_RESUMEKEYS)) { + if (ctx->f_otws == 1) { + ctx->f_firstnmlen = nmlen; + ctx->f_firstnm = kmem_alloc(nmlen, KM_SLEEP); + bcopy(ctx->f_name, ctx->f_firstnm, nmlen); + } else if (ctx->f_otws == 2 && nmlen == ctx->f_firstnmlen && + !(bcmp(ctx->f_name, ctx->f_firstnm, nmlen) == 0)) { + struct smb_share *ssp = ctx->f_ssp; + SMBERROR( + "server resume_name bug seen; using resume keys\n"); + SMB_SS_LOCK(ssp); + ssp->ss_flags |= SMBS_RESUMEKEYS; + SMB_SS_UNLOCK(ssp); + ctx->f_ecnt = 0; + goto again; /* must redo last otw op! */ + } + } + ctx->f_rkey = resumekey; + + next = ctx->f_eofs + recsz; + if (ctx->f_rnameofs && + (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 && + (ctx->f_rnameofs >= ctx->f_eofs && + ctx->f_rnameofs < (int)next)) { + /* + * Server needs a resume filename. + */ + if (ctx->f_rnamelen != nmlen) { + if (ctx->f_rname) + kmem_free(ctx->f_rname, ctx->f_rnamelen); + ctx->f_rname = kmem_alloc(nmlen, KM_SLEEP); + ctx->f_rnamelen = nmlen; + } + bcopy(ctx->f_name, ctx->f_rname, nmlen); + ctx->f_flags |= SMBFS_RDD_GOTRNAME; + } + ctx->f_nmlen = nmlen; + ctx->f_eofs = next; + ctx->f_ecnt--; + ctx->f_left--; + return (0); +} + +static int +smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx) +{ + if (ctx->f_name) + kmem_free(ctx->f_name, ctx->f_namesz); + if (ctx->f_t2) + smb_t2_done(ctx->f_t2); + if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0) + smbfs_smb_findclose2(ctx); + return (0); +} + +int +smbfs_smb_findopen(struct smbnode *dnp, const char *wildcard, int wclen, + int attr, struct smb_cred *scrp, + struct smbfs_fctx **ctxpp) +{ + struct smbfs_fctx *ctx; + int error; + + ctx = kmem_alloc(sizeof (*ctx), KM_SLEEP); + if (ctx == NULL) + return (ENOMEM); + bzero(ctx, sizeof (*ctx)); + if (dnp->n_mount->smi_share) { + ctx->f_ssp = dnp->n_mount->smi_share; + } + ctx->f_dnp = dnp; + ctx->f_flags = SMBFS_RDD_FINDFIRST; + ctx->f_scred = scrp; + if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 || + (dnp->n_mount->smi_args.flags & SMBFS_MOUNT_NO_LONG)) { + ctx->f_flags |= SMBFS_RDD_USESEARCH; + error = smbfs_smb_findopenLM1(ctx, dnp, wildcard, wclen, + attr, scrp); + } else + error = smbfs_smb_findopenLM2(ctx, dnp, wildcard, wclen, + attr, scrp); + if (error) + smbfs_smb_findclose(ctx, scrp); + else + *ctxpp = ctx; + return (error); +} + +int +smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp) +{ + int error; + + /* + * Note: "limit" (maxcount) needs to fit in a short! + * + * smb_lookup always uses 1, which is OK (no wildcards). + * Otherwise, this is smbfs_readdir, and we want to force + * limit to be in the range 3 to 1000. The low limit (3) + * is so we can always give the caller one "real" entry + * (something other than "." or "..") The high limit is + * just tuning. WinNT used 512, Win2k 1366. We use 1000. + * + * XXX: Move the [skip . ..] gunk to our caller (readdir). + */ + if ((ctx->f_flags & SMBFS_RDD_FINDSINGLE) == 0) { + if (limit < 3) + limit = 3; + if (limit > 1000) + limit = 1000; + } + + ctx->f_scred = scrp; + for (;;) { + if (ctx->f_flags & SMBFS_RDD_USESEARCH) { + error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit); + } else + error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit); + if (error) + return (error); + if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { + /*LINTED*/ + uint16_t *up = (uint16_t *)ctx->f_name; + + /* Do comparisons on UCS-2LE characters */ + if ((ctx->f_nmlen == 2 && up[0] == htoles('.')) || + (ctx->f_nmlen == 4 && up[0] == htoles('.') && + up[1] == htoles('.'))) + continue; + } else { + if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') || + (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && + ctx->f_name[1] == '.')) + continue; + } + break; + } + smbfs_fname_tolocal(ctx); + ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, + ctx->f_nmlen); + return (0); +} + + +int +smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp) +{ + ctx->f_scred = scrp; + if (ctx->f_flags & SMBFS_RDD_USESEARCH) { + smbfs_smb_findcloseLM1(ctx); + } else + smbfs_smb_findcloseLM2(ctx); + if (ctx->f_rname) + kmem_free(ctx->f_rname, ctx->f_rnamelen); + if (ctx->f_firstnm) + kmem_free(ctx->f_firstnm, ctx->f_firstnmlen); + kmem_free(ctx, sizeof (*ctx)); + return (0); +} + + +int +smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp, + struct smbfattr *fap, struct smb_cred *scrp) +{ + struct smbfs_fctx *ctx; + int error, intr; + const char *name = (namep ? *namep : NULL); + int nmlen = (nmlenp ? *nmlenp : 0); + + /* This is no longer called with a null dnp */ + ASSERT(dnp); + + /* + * Should not get here with "" anymore. + */ + if (!name || !nmlen) { + DEBUG_ENTER("smbfs_smb_lookup: name is NULL"); + return (EINVAL); + } + + /* + * Should not get here with "." or ".." anymore. + */ + if ((nmlen == 1 && name[0] == '.') || + (nmlen == 2 && name[0] == '.' && name[1] == '.')) { + DEBUG_ENTER("smbfs_smb_lookup: name is '.' or '..'"); + return (EINVAL); + } + + /* + * Shared lock for n_fid use (smb_flush). + */ + intr = dnp->n_mount->smi_flags & SMI_INT; + if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr)) + return (EINTR); + + bzero(fap, sizeof (*fap)); + + /* + * This hides a server bug observable in Win98: + * size changes may not show until a CLOSE or a FLUSH op + * XXX: Make this conditional on !NTSMBs + */ + error = smbfs_smb_flush(dnp, scrp); + if (error) + goto out; + error = smbfs_smb_findopen(dnp, name, nmlen, + SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx); + if (error) + goto out; + ctx->f_flags |= SMBFS_RDD_FINDSINGLE; + error = smbfs_smb_findnext(ctx, 1, scrp); + if (error == 0) { + *fap = ctx->f_attr; + if (name == NULL) + fap->fa_ino = dnp->n_ino; + if (namep) + *namep = (const char *)smbfs_name_alloc( + ctx->f_name, ctx->f_nmlen); + if (nmlenp) + *nmlenp = ctx->f_nmlen; + } + smbfs_smb_findclose(ctx, scrp); + +out: + smbfs_rw_exit(&dnp->r_lkserlock); + return (error); +} + +/* + * Support functions for get/set security + */ +#ifdef APPLE + +int +smbfs_smb_getsec_int(struct smb_share *ssp, uint16_t fid, + struct smb_cred *scrp, uint32_t selector, + struct ntsecdesc **res, int *reslen) +{ + struct smb_ntrq *ntp; + struct mbchain *mbp; + struct mdchain *mdp; + int error, len; + + error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC, + scrp, &ntp); + if (error) + return (error); + mbp = &ntp->nt_tparam; + mb_init(mbp); + mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); + mb_put_uint16le(mbp, 0); /* reserved */ + mb_put_uint32le(mbp, selector); + ntp->nt_maxpcount = 4; + ntp->nt_maxdcount = *reslen; + error = smb_nt_request(ntp); + if (error && !(ntp->nt_flags & SMBT2_MOREDATA)) + goto done; + *res = NULL; + /* + * if there's more data than we said we could receive, here + * is where we pick up the length of it + */ + mdp = &ntp->nt_rparam; + md_get_uint32le(mdp, reslen); + + mdp = &ntp->nt_rdata; + if (mdp->md_top) { /* XXX md_cur safer than md_top */ + len = m_fixhdr(mdp->md_top); + /* + * The following "if (len < *reslen)" handles a Windows bug + * observed when the underlying filesystem is FAT32. In that + * case a 32 byte security descriptor comes back (S-1-1-0, ie + * "Everyone") but the Parameter Block claims 44 is the length + * of the security descriptor. (The Data Block length + * claimed is 32. This server bug was reported against NT + * first and I've personally observed it with W2K. + */ + if (len < *reslen) + *reslen = len; + if (len == *reslen) { + MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK); + md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM); + } else if (len > *reslen) + SMBVDEBUG("len %d *reslen %d fid 0x%x\n", len, *reslen, + letohs(fid)); + } else + SMBVDEBUG("null md_top? fid 0x%x\n", letohs(fid)); +done: + smb_nt_done(ntp); + return (error); +} + +int +smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp, + uint32_t selector, struct ntsecdesc **res) +{ + int error, olen, seclen; + + olen = seclen = 500; /* "overlarge" values => server errors */ + error = smbfs_smb_getsec_int(ssp, fid, scrp, selector, res, &seclen); + if (error && seclen > olen) + error = smbfs_smb_getsec_int(ssp, fid, scrp, selector, res, + &seclen); + return (error); +} + +int +smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp, + uint32_t selector, uint16_t flags, struct ntsid *owner, + struct ntsid *group, struct ntacl *sacl, struct ntacl *dacl) +{ + struct smb_ntrq *ntp; + struct mbchain *mbp; + int error, off; + struct ntsecdesc ntsd; + + error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC, + scrp, &ntp); + if (error) + return (error); + mbp = &ntp->nt_tparam; + mb_init(mbp); + mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); + mb_put_uint16le(mbp, 0); /* reserved */ + mb_put_uint32le(mbp, selector); + mbp = &ntp->nt_tdata; + mb_init(mbp); + bzero(&ntsd, sizeof (ntsd)); + wset_sdrevision(&ntsd); + /* + * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN) + * We set here only those bits we can be sure must be set. The rest + * are up to the caller. In particular, the caller may intentionally + * set an acl PRESENT bit while giving us a null pointer for the + * acl - that sets a null acl, giving access to everyone. Note also + * that the AUTO_INHERITED bits should probably always be set unless + * the server is NT. + */ + flags |= SD_SELF_RELATIVE; + off = sizeof (ntsd); + if (owner) { + wset_sdowneroff(&ntsd, off); + off += sidlen(owner); + } + if (group) { + wset_sdgroupoff(&ntsd, off); + off += sidlen(group); + } + if (sacl) { + flags |= SD_SACL_PRESENT; + wset_sdsacloff(&ntsd, off); + off += acllen(sacl); + } + if (dacl) { + flags |= SD_DACL_PRESENT; + wset_sddacloff(&ntsd, off); + } + wset_sdflags(&ntsd, flags); + mb_put_mem(mbp, (caddr_t)&ntsd, sizeof (ntsd), MB_MSYSTEM); + if (owner) + mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM); + if (group) + mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM); + if (sacl) + mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM); + if (dacl) + mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM); + ntp->nt_maxpcount = 0; + ntp->nt_maxdcount = 0; + error = smb_nt_request(ntp); + smb_nt_done(ntp); + return (error); +} + +#endif /* APPLE */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,368 @@ +/* + * 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: smbfs_subr.c,v 1.18 2005/02/02 00:22:23 lindak Exp $ + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/time.h> +#include <sys/vnode.h> +#include <sys/sunddi.h> + +#ifdef APPLE +#include <sys/smb_apple.h> +#include <sys/utfconv.h> +#include <sys/smb_iconv.h> +#else /* APPLE */ +#include <netsmb/smb_osdep.h> +#endif /* APPLE */ + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> +#include <netsmb/smb_rq.h> + +#include <smbfs/smbfs.h> +#include <smbfs/smbfs_node.h> +#include <smbfs/smbfs_subr.h> + +#ifdef APPLE +MALLOC_DEFINE(M_SMBFSDATA, "SMBFS data", "SMBFS private data"); +#endif /* APPLE */ + +/* + * Time & date conversion routines taken from msdosfs. Although leap + * year calculation is bogus, it's sufficient before 2100 :) + */ +/* + * This is the format of the contents of the deTime field in the direntry + * structure. + * We don't use bitfields because we don't know how compilers for + * arbitrary machines will lay them out. + */ +#define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */ +#define DT_2SECONDS_SHIFT 0 +#define DT_MINUTES_MASK 0x7E0 /* minutes */ +#define DT_MINUTES_SHIFT 5 +#define DT_HOURS_MASK 0xF800 /* hours */ +#define DT_HOURS_SHIFT 11 + +/* + * This is the format of the contents of the deDate field in the direntry + * structure. + */ +#define DD_DAY_MASK 0x1F /* day of month */ +#define DD_DAY_SHIFT 0 +#define DD_MONTH_MASK 0x1E0 /* month */ +#define DD_MONTH_SHIFT 5 +#define DD_YEAR_MASK 0xFE00 /* year - 1980 */ +#define DD_YEAR_SHIFT 9 +/* + * Total number of days that have passed for each month in a regular year. + */ +static ushort_t regyear[] = { + 31, 59, 90, 120, 151, 181, + 212, 243, 273, 304, 334, 365 +}; + +/* + * Total number of days that have passed for each month in a leap year. + */ +static ushort_t leapyear[] = { + 31, 60, 91, 121, 152, 182, + 213, 244, 274, 305, 335, 366 +}; + +/* + * Variables used to remember parts of the last time conversion. Maybe we + * can avoid a full conversion. + */ +static ulong_t lasttime; +static ulong_t lastday; +static ushort_t lastddate; +static ushort_t lastdtime; + +#ifdef APPLE +PRIVSYM int wall_cmos_clock = 0; /* XXX */ +PRIVSYM int adjkerntz = 0; /* XXX */ +#endif /* APPLE */ + +void +smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp, + u_int16_t *dtp, u_int8_t *dhp) +{ + long t; + ulong_t days, year, month, inc; + ushort_t *months; + + /* + * If the time from the last conversion is the same as now, then + * skip the computations and use the saved result. + */ + smb_time_local2server(tsp, tzoff, &t); + t &= ~1; + if (lasttime != t) { + lasttime = t; + if (t < 0) { + /* + * This is before 1970, so it's before 1980, + * and can't be represented as a DOS time. + * Just represent it as the DOS epoch. + */ + lastdtime = 0; + lastddate = (1 << DD_DAY_SHIFT) + + (1 << DD_MONTH_SHIFT) + + ((1980 - 1980) << DD_YEAR_SHIFT); + } else { + lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT) + + (((t / 60) % 60) << DT_MINUTES_SHIFT) + + (((t / 3600) % 24) << DT_HOURS_SHIFT); + + /* + * If the number of days since 1970 is the same as + * the last time we did the computation then skip + * all this leap year and month stuff. + */ + days = t / (24 * 60 * 60); + if (days != lastday) { + lastday = days; + for (year = 1970; ; year++) { + /* + * XXX - works in 2000, but won't + * work in 2100. + */ + inc = year & 0x03 ? 365 : 366; + if (days < inc) + break; + days -= inc; + } + /* + * XXX - works in 2000, but won't work in 2100. + */ + months = year & 0x03 ? regyear : leapyear; + for (month = 0; days >= months[month]; month++) + ; + if (month > 0) + days -= months[month - 1]; + lastddate = ((days + 1) << DD_DAY_SHIFT) + + ((month + 1) << DD_MONTH_SHIFT); + /* + * Remember DOS's idea of time is relative + * to 1980, but UN*X's is relative to 1970. + * If somehow we get a time before 1980 then + * don't give totally crazy results. + */ + if (year > 1980) + lastddate += (year - 1980) << + DD_YEAR_SHIFT; + } + } + } + if (dtp) + *dtp = lastdtime; + if (dhp) + *dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000; + + *ddp = lastddate; +} + +/* + * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that + * interval there were 8 regular years and 2 leap years. + */ +#define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60)) + +static ushort_t lastdosdate; +static ulong_t lastseconds; + +void +smb_dos2unixtime(uint_t dd, uint_t dt, uint_t dh, int tzoff, + struct timespec *tsp) +{ + ulong_t seconds; + ulong_t month; + ulong_t year; + ulong_t days; + ushort_t *months; + + if (dd == 0) { + tsp->tv_sec = 0; + tsp->tv_nsec = 0; + return; + } + seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1) + + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60 + + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600 + + dh / 100; + /* + * If the year, month, and day from the last conversion are the + * same then use the saved value. + */ + if (lastdosdate != dd) { + lastdosdate = (ushort_t)dd; + days = 0; + year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT; + days = year * 365; + days += year / 4 + 1; /* add in leap days */ + /* + * XXX - works in 2000, but won't work in 2100. + */ + if ((year & 0x03) == 0) + days--; /* if year is a leap year */ + months = year & 0x03 ? regyear : leapyear; + month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT; + if (month < 1 || month > 12) { + month = 1; + } + if (month > 1) + days += months[month - 2]; + days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1; + lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980; + } + smb_time_server2local(seconds + lastseconds, tzoff, tsp); + tsp->tv_nsec = (dh % 100) * 10000000; +} + +/* + * In the Darwin code, this function used to compute the full path + * by following the chain of n_parent pointers back to the root. + * In the Solaris port we found the n_parent pointers inconvenient + * because they hold parent nodes busy. We now keep the full path + * in every node, so this function need only marshall the directory + * path, and (if provided) the separator and last component name. + * + * Note that this logic must match that in smbfs_getino + */ +int +smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp, + const char *name, int *lenp, u_int8_t sep) +{ + int caseopt = SMB_CS_NONE; + int error, len = 0; + int unicode = (SMB_UNICODE_STRINGS(vcp)) ? 1 : 0; + + if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0) + caseopt |= SMB_CS_UPPER; + + if (lenp) { + len = *lenp; + *lenp = 0; + } + if (unicode) { + error = mb_put_padbyte(mbp); + if (error) + return (error); + } + error = smb_put_dmem(mbp, vcp, + dnp->n_rpath, dnp->n_rplen, + caseopt, lenp); + if (name) { + /* If not at root, put separator */ + if (dnp->n_rplen > 1) { + if (unicode) + error = mb_put_uint16le(mbp, sep); + else + error = mb_put_uint8(mbp, sep); + if (!error && lenp) + *lenp += (unicode + 1); + if (error) + return (error); + } + /* Put the name */ + error = smb_put_dmem(mbp, vcp, + name, len, caseopt, lenp); + if (error) + return (error); + } + /* Put NULL termination. */ + if (unicode) + error = mb_put_uint16le(mbp, 0); + else + error = mb_put_uint8(mbp, 0); + if (!error && lenp) + *lenp += (unicode + 1); + + return (error); +} + +void +smbfs_fname_tolocal(struct smbfs_fctx *ctx) +{ + int length; + struct smb_vc *vcp = SSTOVC(ctx->f_ssp); + uchar_t *dst; + const ushort_t *src; + size_t inlen, outlen; + int flags = 0; + + if (ctx->f_nmlen == 0) + return; + + /* XXX: This is temporary, right? Need iconv... */ + if (!SMB_UNICODE_STRINGS(vcp)) + return; + + /* + * In Unix, the UTF-8 name can be larger and + * in-place conversions are not supported. + * Note: 3,9 are the maximum UTF-8 expansion + * factors when converting strings from UTF-16 + * XXX: This was removed. REVISIT + */ + if (SMB_UNICODE_STRINGS(vcp)) + length = ctx->f_nmlen * 9; /* why 9 */ + else + length = ctx->f_nmlen * 3; /* why 3 */ + length = min(length, SMB_MAXFNAMELEN); + + dst = kmem_zalloc(length, KM_SLEEP); + outlen = length; + /*LINTED*/ + src = (const ushort_t *)ctx->f_name; + inlen = ctx->f_nmlen / 2; /* need number of UCS-2 characters */ + flags |= UCONV_IN_LITTLE_ENDIAN; + + if (uconv_u16tou8(src, &inlen, dst, &outlen, flags) == 0) { + kmem_free(ctx->f_name, ctx->f_namesz); + ctx->f_name = (char *)dst; + ctx->f_namesz = length; + ctx->f_nmlen = (int)outlen; + } else + kmem_free(dst, length); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,260 @@ +/* + * 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: smbfs_subr.h,v 1.25 2005/03/17 01:23:40 lindak Exp $ + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _FS_SMBFS_SMBFS_SUBR_H_ +#define _FS_SMBFS_SMBFS_SUBR_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* This defines terms used in the error messages */ +#include <sys/cmn_err.h> + +#if defined(DEBUG) || defined(lint) +#define SMB_VNODE_DEBUG 1 +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + +/* + * Let's use C99 standard variadic macros! + * Also the C99 __func__ (function name) feature. + */ +#define SMBFSERR(...) \ + smb_errmsg(CE_NOTE, __func__, __VA_ARGS__) +#define SMBVDEBUG(...) \ + smb_errmsg(CE_CONT, __func__, __VA_ARGS__) + +/* + * Possible lock commands + */ +#define SMB_LOCK_EXCL 0 +#define SMB_LOCK_SHARED 1 +#define SMB_LOCK_RELEASE 2 + +struct mbchain; +struct smb_cred; +struct smb_vc; +struct statvfs; +struct timespec; + + +/* + * Context to perform findfirst/findnext/findclose operations + */ +#define SMBFS_RDD_FINDFIRST 0x01 +#define SMBFS_RDD_EOF 0x02 +#define SMBFS_RDD_FINDSINGLE 0x04 +#define SMBFS_RDD_USESEARCH 0x08 +#define SMBFS_RDD_NOCLOSE 0x10 +#define SMBFS_RDD_GOTRNAME 0x1000 + +/* + * Search context supplied by server + */ +#define SMB_SKEYLEN 21 /* search context */ +#define SMB_DENTRYLEN (SMB_SKEYLEN + 22) /* entire entry */ + +struct smbfs_fctx { + /* + * Setable values + */ + int f_flags; /* SMBFS_RDD_ */ + /* + * Return values + */ + struct smbfattr f_attr; /* current attributes */ + char *f_name; /* current file name */ + int f_nmlen; /* name len */ + int f_namesz; /* memory allocated */ + /* + * Internal variables + */ + uint16_t f_limit; /* maximum number of entries */ + uint16_t f_attrmask; /* SMB_FA_ */ + int f_wclen; + const char *f_wildcard; + struct smbnode *f_dnp; + struct smb_cred *f_scred; + struct smb_share *f_ssp; + union { + struct smb_rq *uf_rq; + struct smb_t2rq *uf_t2; + } f_urq; + int f_left; /* entries left */ + int f_ecnt; /* entries left in current response */ + int f_eofs; /* entry offset in data block */ + uchar_t f_skey[SMB_SKEYLEN]; /* server side search context */ + uchar_t f_fname[8 + 1 + 3 + 1]; /* for 8.3 filenames */ + uint16_t f_Sid; /* Search handle (like a FID) */ + uint16_t f_infolevel; + int f_rnamelen; + char *f_rname; /* resume name */ + int f_rnameofs; + int f_otws; /* # over-the-wire ops so far */ + char *f_firstnm; /* first filename we got back */ + int f_firstnmlen; + int f_rkey; /* resume key */ +}; +typedef struct smbfs_fctx smbfs_fctx_t; + +#define f_rq f_urq.uf_rq +#define f_t2 f_urq.uf_t2 + + +/* + * smb level + */ +int smbfs_smb_lock(struct smbnode *np, int op, caddr_t id, + offset_t start, uint64_t len, int largelock, + struct smb_cred *scrp, uint32_t timeout); +int smbfs_smb_qfsattr(struct smb_share *ssp, uint32_t *attrp, + struct smb_cred *scrp); +int smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp, + struct smb_cred *scrp); +int smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize, + struct smb_cred *scrp); + +int smbfs_smb_getfattr(struct smbnode *np, struct smbfattr *fap, + struct smb_cred *scrp); + +int smbfs_smb_setfattr(struct smbnode *np, uint16_t fid, + uint32_t attr, struct timespec *mtime, struct timespec *atime, + struct smb_cred *scrp); + +int smbfs_smb_setpattr(struct smbnode *np, + uint32_t attr, struct timespec *mtime, struct timespec *atime, + struct smb_cred *scrp); + +int smbfs_smb_open(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, + int *attrcacheupdated, uint16_t *fidp, const char *name, int nmlen, + int xattr, len_t *sizep, uint32_t *rightsp); +int smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, + struct smb_cred *scrp, uint16_t *fidp); +int smbfs_smb_close(struct smb_share *ssp, uint16_t fid, + struct timespec *mtime, struct smb_cred *scrp); +int smbfs_smb_tmpclose(struct smbnode *ssp, uint16_t fid, + struct smb_cred *scrp); +int smbfs_smb_create(struct smbnode *dnp, const char *name, int len, + struct smb_cred *scrp, uint16_t *fidp, uint32_t disp, int xattr); +int smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, + const char *name, int len, int xattr); +int smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, + const char *tname, int tnmlen, struct smb_cred *scrp); +int smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp, + const char *tname, int tnmlen, struct smb_cred *scrp, int overwrite); +int smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, + const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp); +int smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len, + struct smb_cred *scrp); +int smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp); +int smbfs_smb_findopen(struct smbnode *dnp, const char *wildcard, int wclen, + int attr, struct smb_cred *scrp, struct smbfs_fctx **ctxpp); +int smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, + struct smb_cred *scrp); +int smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp); +int smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, + struct smbnode *dnp, const char *name, int *nmlenp, uint8_t sep); +int smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp, + struct smbfattr *fap, struct smb_cred *scrp); +int smbfs_smb_hideit(struct smbnode *np, const char *name, int len, + struct smb_cred *scrp); +int smbfs_smb_unhideit(struct smbnode *np, const char *name, int len, + struct smb_cred *scrp); +int smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp); +int smbfs_0extend(vnode_t *vp, uint16_t fid, len_t from, len_t to, + struct smb_cred *scredp, int timo); + +#ifdef NOT_YET +int smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, + struct smb_cred *scrp, uint32_t selector, struct ntsecdesc **res); +int smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, + struct smb_cred *scrp, uint32_t selector, uint16_t flags, + struct ntsid *owner, struct ntsid *group, struct ntacl *sacl, + struct ntacl *dacl); +int smbfs_smb_qstreaminfo(struct smbnode *np, struct smb_cred *scrp, + uio_t uio, size_t *sizep); +#endif /* NOT_YET */ + +void smbfs_fname_tolocal(struct smbfs_fctx *ctx); + +void smb_time_local2server(struct timespec *tsp, int tzoff, long *seconds); +void smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp); +void smb_time_NT2local(uint64_t nsec, int tzoff, struct timespec *tsp); +void smb_time_local2NT(struct timespec *tsp, int tzoff, uint64_t *nsec); +void smb_time_unix2dos(struct timespec *tsp, int tzoff, uint16_t *ddp, + uint16_t *dtp, uint8_t *dhp); +void smb_dos2unixtime(uint_t dd, uint_t dt, uint_t dh, int tzoff, + struct timespec *tsp); + +/* Stuff borrowed from NFS (and then hacked) */ +vnode_t *smbfs_make_node(vfs_t *vfsp, + const char *dir, int dirlen, + const char *name, int nmlen, + struct smbfattr *fap); +void smb_addfree(smbnode_t *sp); +void smb_addhash(smbnode_t *sp); +void smb_rmhash(smbnode_t *); + +int smbfs_subrinit(void); +void smbfs_subrfini(void); +int smbfs_clntinit(void); +void smbfs_clntfini(void); +void smbfs_zonelist_add(smbmntinfo_t *smi); +void smbfs_zonelist_remove(smbmntinfo_t *smi); +void smbfs_destroy_table(struct vfs *vfsp); +int smbfs_readvnode(vnode_t *, uio_t *, cred_t *, struct vattr *); +int smbfs_writevnode(vnode_t *vp, uio_t *uiop, cred_t *cr, + int ioflag, int timo); +int smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr); + +/* For Solaris, interruptible rwlock */ +int smbfs_rw_enter_sig(smbfs_rwlock_t *l, krw_t rw, int intr); +int smbfs_rw_tryenter(smbfs_rwlock_t *l, krw_t rw); +void smbfs_rw_exit(smbfs_rwlock_t *l); +int smbfs_rw_lock_held(smbfs_rwlock_t *l, krw_t rw); +void smbfs_rw_init(smbfs_rwlock_t *l, char *name, krw_type_t type, void *arg); +void smbfs_rw_destroy(smbfs_rwlock_t *l); + +#endif /* !_FS_SMBFS_SMBFS_SUBR_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,1001 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Node hash implementation borrowed from NFS. + * See: uts/common/fs/nfs/nfs_subr.c + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/time.h> +#include <sys/vnode.h> +#include <sys/bitmap.h> +#include <sys/dnlc.h> +#include <sys/kmem.h> +#include <sys/sunddi.h> + +#ifdef APPLE +#include <sys/smb_apple.h> +#include <sys/utfconv.h> +#include <sys/smb_iconv.h> +#else +#include <netsmb/smb_osdep.h> +#endif + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> +#include <netsmb/smb_rq.h> + +#include <smbfs/smbfs.h> +#include <smbfs/smbfs_node.h> +#include <smbfs/smbfs_subr.h> + +/* + * The hash queues for the access to active and cached smbnodes + * are organized as doubly linked lists. A reader/writer lock + * for each hash bucket is used to control access and to synchronize + * lookups, additions, and deletions from the hash queue. + * + * The smbnode freelist is organized as a doubly linked list with + * a head pointer. Additions and deletions are synchronized via + * a single mutex. + * + * In order to add an smbnode to the free list, it must be hashed into + * a hash queue and the exclusive lock to the hash queue be held. + * If an smbnode is not hashed into a hash queue, then it is destroyed + * because it represents no valuable information that can be reused + * about the file. The exclusive lock to the hash queue must be + * held in order to prevent a lookup in the hash queue from finding + * the smbnode and using it and assuming that the smbnode is not on the + * freelist. The lookup in the hash queue will have the hash queue + * locked, either exclusive or shared. + * + * The vnode reference count for each smbnode is not allowed to drop + * below 1. This prevents external entities, such as the VM + * subsystem, from acquiring references to vnodes already on the + * freelist and then trying to place them back on the freelist + * when their reference is released. This means that the when an + * smbnode is looked up in the hash queues, then either the smbnode + * is removed from the freelist and that reference is tranfered to + * the new reference or the vnode reference count must be incremented + * accordingly. The mutex for the freelist must be held in order to + * accurately test to see if the smbnode is on the freelist or not. + * The hash queue lock might be held shared and it is possible that + * two different threads may race to remove the smbnode from the + * freelist. This race can be resolved by holding the mutex for the + * freelist. Please note that the mutex for the freelist does not + * need to held if the smbnode is not on the freelist. It can not be + * placed on the freelist due to the requirement that the thread + * putting the smbnode on the freelist must hold the exclusive lock + * to the hash queue and the thread doing the lookup in the hash + * queue is holding either a shared or exclusive lock to the hash + * queue. + * + * The lock ordering is: + * + * hash bucket lock -> vnode lock + * hash bucket lock -> freelist lock + */ +static rhashq_t *smbtable; + +static kmutex_t smbfreelist_lock; +static smbnode_t *smbfreelist = NULL; +static ulong_t smbnodenew = 0; +long nsmbnode = 0; + +static int smbtablesize; +static int smbtablemask; +static int smbhashlen = 4; + +static struct kmem_cache *smbnode_cache; + +/* + * Mutex to protect the following variables: + * smbfs_major + * smbfs_minor + */ +kmutex_t smbfs_minor_lock; +int smbfs_major; +int smbfs_minor; + +/* + * Local functions. + * Not static, to aid debugging. + */ +void smb_rmfree(smbnode_t *); +void smbinactive(smbnode_t *); +void smb_rmhash_locked(smbnode_t *); +void smb_destroy_node(smbnode_t *); +void smbfs_kmem_reclaim(void *cdrarg); + +smbnode_t *smbhashfind(struct vfs *, const char *, int, rhashq_t *); +static vnode_t *make_smbnode(vfs_t *, char *, int, rhashq_t *, int *); + + +/* + * Free the resources associated with an smbnode. + * Note: This is different from smbfs_inactive + * + * NFS: nfs_subr.c:rinactive + */ +void +smbinactive(smbnode_t *np) +{ + + if (np->n_rpath) { + kmem_free(np->n_rpath, np->n_rplen + 1); + np->n_rpath = NULL; + } +} + +/* + * Return a vnode for the given CIFS directory and filename. + * If no smbnode exists for this fhandle, create one and put it + * into the hash queues. If the smbnode for this fhandle + * already exists, return it. + * + * Note: make_smbnode() may upgrade the hash bucket lock to exclusive. + * + * NFS: nfs_subr.c:makenfsnode + */ +vnode_t * +smbfs_make_node( + vfs_t *vfsp, + const char *dir, + int dirlen, + const char *name, + int nmlen, + struct smbfattr *fap) +{ + char *rpath; + int rplen, idx; + uint32_t hash; + rhashq_t *rhtp; + smbnode_t *np; + vnode_t *vp; +#ifdef NOT_YET + vattr_t va; +#endif + int newnode; + + /* + * Build the full path name in allocated memory + * so we have it for lookup, etc. + * + * ToDo: Would prefer to allocate a remote path + * only when we will create a new node. + */ + rplen = dirlen; + if (name) { + /* If not at root, we'll add a slash. */ + if (dirlen > 1) + rplen++; + rplen += nmlen; + } + rpath = kmem_alloc(rplen + 1, KM_SLEEP); + + bcopy(dir, rpath, dirlen); + if (name) { + if (dirlen > 1) + rpath[dirlen++] = '\\'; + bcopy(name, &rpath[dirlen], nmlen); + } + rpath[rplen] = 0; + + hash = smbfs_hash(rpath, rplen); + idx = hash & smbtablemask; + rhtp = &smbtable[idx]; + rw_enter(&rhtp->r_lock, RW_READER); + + vp = make_smbnode(vfsp, rpath, rplen, rhtp, &newnode); + np = VTOSMB(vp); + np->n_ino = hash; /* Equivalent to: smbfs_getino() */ + + /* + * Note: make_smbnode keeps a reference to rpath in + * new nodes it creates, so only free when we found + * an existing node. + */ + if (!newnode) { + kmem_free(rpath, rplen + 1); + rpath = NULL; + } + + if (fap == NULL) { +#ifdef NOT_YET + if (newnode) { + PURGE_ATTRCACHE(vp); + } +#endif + rw_exit(&rhtp->r_lock); + return (vp); + } + + /* Have SMB attributes. */ + vp->v_type = (fap->fa_attr & SMB_FA_DIR) ? VDIR : VREG; + /* XXX: np->n_ino = fap->fa_ino; see above */ + np->r_size = fap->fa_size; + /* XXX: np->r_attr = *fap here instead? */ + np->r_atime = fap->fa_atime; + np->r_ctime = fap->fa_mtime; + np->r_mtime = fap->fa_ctime; + +#ifdef NOT_YET + if (!newnode) { + rw_exit(&rhtp->r_lock); + (void) nfs_cache_fattr(vp, attr, &va, t, cr); + } else { + if (attr->na_type < NFNON || attr->na_type > NFSOC) + vp->v_type = VBAD; + else + vp->v_type = n2v_type(attr); + vp->v_rdev = makedevice(attr->rdev.specdata1, + attr->rdev.specdata2); + nfs_attrcache(vp, attr, t); + rw_exit(&rhtp->r_lock); + } +#else + rw_exit(&rhtp->r_lock); +#endif + + return (vp); +} + +/* + * NFS: nfs_subr.c:rtablehash + * We use smbfs_hash(). + */ + +/* + * Find or create an smbnode. + * NFS: nfs_subr.c:make_rnode + */ +static vnode_t * +make_smbnode( + vfs_t *vfsp, + char *rpath, + int rplen, + rhashq_t *rhtp, + int *newnode) +{ + smbnode_t *np; + smbnode_t *tnp; + vnode_t *vp; + smbmntinfo_t *mi; + + ASSERT(RW_READ_HELD(&rhtp->r_lock)); + + mi = VFTOSMI(vfsp); + +start: + np = smbhashfind(vfsp, rpath, rplen, rhtp); + if (np != NULL) { + vp = SMBTOV(np); + *newnode = 0; + return (vp); + } + + /* Note: will retake this lock below. */ + rw_exit(&rhtp->r_lock); + + /* + * see if we can find something on the freelist + */ + mutex_enter(&smbfreelist_lock); + if (smbfreelist != NULL && smbnodenew >= nsmbnode) { + np = smbfreelist; + smb_rmfree(np); + mutex_exit(&smbfreelist_lock); + + vp = SMBTOV(np); + + if (np->r_flags & RHASHED) { + rw_enter(&np->r_hashq->r_lock, RW_WRITER); + mutex_enter(&vp->v_lock); + if (vp->v_count > 1) { + vp->v_count--; + mutex_exit(&vp->v_lock); + rw_exit(&np->r_hashq->r_lock); + rw_enter(&rhtp->r_lock, RW_READER); + goto start; + } + mutex_exit(&vp->v_lock); + smb_rmhash_locked(np); + rw_exit(&np->r_hashq->r_lock); + } + + smbinactive(np); + + mutex_enter(&vp->v_lock); + if (vp->v_count > 1) { + vp->v_count--; + mutex_exit(&vp->v_lock); + rw_enter(&rhtp->r_lock, RW_READER); + goto start; + } + mutex_exit(&vp->v_lock); + vn_invalid(vp); + /* + * destroy old locks before bzero'ing and + * recreating the locks below. + */ + smbfs_rw_destroy(&np->r_rwlock); + smbfs_rw_destroy(&np->r_lkserlock); + mutex_destroy(&np->r_statelock); + cv_destroy(&np->r_cv); + /* + * Make sure that if smbnode is recycled then + * VFS count is decremented properly before + * reuse. + */ + VFS_RELE(vp->v_vfsp); + vn_reinit(vp); + } else { + /* + * allocate and initialize a new smbnode + */ + vnode_t *new_vp; + + mutex_exit(&smbfreelist_lock); + + np = kmem_cache_alloc(smbnode_cache, KM_SLEEP); + new_vp = vn_alloc(KM_SLEEP); + + atomic_add_long((ulong_t *)&smbnodenew, 1); + vp = new_vp; + } + + /* Initialize smbnode_t */ + bzero(np, sizeof (*np)); + + smbfs_rw_init(&np->r_rwlock, NULL, RW_DEFAULT, NULL); + smbfs_rw_init(&np->r_lkserlock, NULL, RW_DEFAULT, NULL); + mutex_init(&np->r_statelock, NULL, MUTEX_DEFAULT, NULL); + cv_init(&np->r_cv, NULL, CV_DEFAULT, NULL); + /* cv_init(&np->r_commit.c_cv, NULL, CV_DEFAULT, NULL); */ + + np->r_vnode = vp; + np->n_mount = mi; + np->r_hashq = rhtp; + np->n_direof = -1; + np->n_fid = SMB_FID_UNUSED; + np->n_uid = UID_NOBODY; + np->n_gid = GID_NOBODY; + /* XXX: make attributes stale? */ + +#if 0 /* XXX dircache */ + /* + * We don't know if it's a directory yet. + * Let the caller do this? XXX + */ + avl_create(&np->r_dir, compar, sizeof (rddir_cache), + offsetof(rddir_cache, tree)); +#endif + + /* Now fill in the vnode. */ + vn_setops(vp, smbfs_vnodeops); + vp->v_data = (caddr_t)np; + VFS_HOLD(vfsp); + vp->v_vfsp = vfsp; + vp->v_type = VNON; + + /* + * There is a race condition if someone else + * alloc's the smbnode while no locks are held, so we + * check again and recover if found. + */ + rw_enter(&rhtp->r_lock, RW_WRITER); + tnp = smbhashfind(vfsp, rpath, rplen, rhtp); + if (tnp != NULL) { + vp = SMBTOV(tnp); + *newnode = 0; + rw_exit(&rhtp->r_lock); + /* The node we were building goes on the free list. */ + smb_addfree(np); + rw_enter(&rhtp->r_lock, RW_READER); + return (vp); + } + + /* + * Hash search identifies nodes by the full pathname, + * so store that before linking in the hash list. + * Note: caller allocates the rpath, and knows + * about this reference when *newnode is set. + */ + np->n_rpath = rpath; + np->n_rplen = rplen; + + smb_addhash(np); + *newnode = 1; + return (vp); +} + +/* + * smb_addfree + * Put a smbnode on the free list. + * + * Normally called by smbfs_inactive, but also + * called in here during cleanup operations. + * + * Smbnodes which were allocated above and beyond the normal limit + * are immediately freed. + * + * NFS: nfs_subr.c:rp_addfree + */ +void +smb_addfree(smbnode_t *np) +{ + vnode_t *vp; + struct vfs *vfsp; + + vp = SMBTOV(np); + ASSERT(vp->v_count >= 1); + ASSERT(np->r_freef == NULL && np->r_freeb == NULL); + + /* + * If we have too many smbnodes allocated and there are no + * references to this smbnode, or if the smbnode is no longer + * accessible by it does not reside in the hash queues, + * or if an i/o error occurred while writing to the file, + * then just free it instead of putting it on the smbnode + * freelist. + */ + vfsp = vp->v_vfsp; + if (((smbnodenew > nsmbnode || !(np->r_flags & RHASHED) || + np->r_error || (vfsp->vfs_flag & VFS_UNMOUNTED)) && + np->r_count == 0)) { + if (np->r_flags & RHASHED) { + rw_enter(&np->r_hashq->r_lock, RW_WRITER); + mutex_enter(&vp->v_lock); + if (vp->v_count > 1) { + vp->v_count--; + mutex_exit(&vp->v_lock); + rw_exit(&np->r_hashq->r_lock); + return; + /* + * Will get another call later, + * via smbfs_inactive. + */ + } + mutex_exit(&vp->v_lock); + smb_rmhash_locked(np); + rw_exit(&np->r_hashq->r_lock); + } + + smbinactive(np); + + /* + * Recheck the vnode reference count. We need to + * make sure that another reference has not been + * acquired while we were not holding v_lock. The + * smbnode is not in the smbnode hash queues, so the + * only way for a reference to have been acquired + * is for a VOP_PUTPAGE because the smbnode was marked + * with RDIRTY or for a modified page. This + * reference may have been acquired before our call + * to smbinactive. The i/o may have been completed, + * thus allowing smbinactive to complete, but the + * reference to the vnode may not have been released + * yet. In any case, the smbnode can not be destroyed + * until the other references to this vnode have been + * released. The other references will take care of + * either destroying the smbnode or placing it on the + * smbnode freelist. If there are no other references, + * then the smbnode may be safely destroyed. + */ + mutex_enter(&vp->v_lock); + if (vp->v_count > 1) { + vp->v_count--; + mutex_exit(&vp->v_lock); + return; + } + mutex_exit(&vp->v_lock); + + smb_destroy_node(np); + return; + } + /* + * Lock the hash queue and then recheck the reference count + * to ensure that no other threads have acquired a reference + * to indicate that the smbnode should not be placed on the + * freelist. If another reference has been acquired, then + * just release this one and let the other thread complete + * the processing of adding this smbnode to the freelist. + */ + rw_enter(&np->r_hashq->r_lock, RW_WRITER); + + mutex_enter(&vp->v_lock); + if (vp->v_count > 1) { + vp->v_count--; + mutex_exit(&vp->v_lock); + rw_exit(&np->r_hashq->r_lock); + return; + } + mutex_exit(&vp->v_lock); + + /* + * If there is no cached data or metadata for this file, then + * put the smbnode on the front of the freelist so that it will + * be reused before other smbnodes which may have cached data or + * metadata associated with them. + */ + mutex_enter(&smbfreelist_lock); + if (smbfreelist == NULL) { + np->r_freef = np; + np->r_freeb = np; + smbfreelist = np; + } else { + np->r_freef = smbfreelist; + np->r_freeb = smbfreelist->r_freeb; + smbfreelist->r_freeb->r_freef = np; + smbfreelist->r_freeb = np; + } + mutex_exit(&smbfreelist_lock); + + rw_exit(&np->r_hashq->r_lock); +} + +/* + * Remove an smbnode from the free list. + * + * The caller must be holding smbfreelist_lock and the smbnode + * must be on the freelist. + * + * NFS: nfs_subr.c:rp_rmfree + */ +void +smb_rmfree(smbnode_t *np) +{ + + ASSERT(MUTEX_HELD(&smbfreelist_lock)); + ASSERT(np->r_freef != NULL && np->r_freeb != NULL); + + if (np == smbfreelist) { + smbfreelist = np->r_freef; + if (np == smbfreelist) + smbfreelist = NULL; + } + + np->r_freeb->r_freef = np->r_freef; + np->r_freef->r_freeb = np->r_freeb; + + np->r_freef = np->r_freeb = NULL; +} + +/* + * Put a smbnode in the hash table. + * + * The caller must be holding the exclusive hash queue lock. + * + * NFS: nfs_subr.c:rp_addhash + */ +void +smb_addhash(smbnode_t *np) +{ + + ASSERT(RW_WRITE_HELD(&np->r_hashq->r_lock)); + ASSERT(!(np->r_flags & RHASHED)); + + np->r_hashf = np->r_hashq->r_hashf; + np->r_hashq->r_hashf = np; + np->r_hashb = (smbnode_t *)np->r_hashq; + np->r_hashf->r_hashb = np; + + mutex_enter(&np->r_statelock); + np->r_flags |= RHASHED; + mutex_exit(&np->r_statelock); +} + +/* + * Remove a smbnode from the hash table. + * + * The caller must be holding the hash queue lock. + * + * NFS: nfs_subr.c:rp_rmhash_locked + */ +void +smb_rmhash_locked(smbnode_t *np) +{ + + ASSERT(RW_WRITE_HELD(&np->r_hashq->r_lock)); + ASSERT(np->r_flags & RHASHED); + + np->r_hashb->r_hashf = np->r_hashf; + np->r_hashf->r_hashb = np->r_hashb; + + mutex_enter(&np->r_statelock); + np->r_flags &= ~RHASHED; + mutex_exit(&np->r_statelock); +} + +/* + * Remove a smbnode from the hash table. + * + * The caller must not be holding the hash queue lock. + */ +void +smb_rmhash(smbnode_t *np) +{ + + rw_enter(&np->r_hashq->r_lock, RW_WRITER); + smb_rmhash_locked(np); + rw_exit(&np->r_hashq->r_lock); +} + +/* + * Lookup a smbnode by fhandle. + * + * The caller must be holding the hash queue lock, either shared or exclusive. + * XXX: make static? + * + * NFS: nfs_subr.c:rfind + */ +smbnode_t * +smbhashfind( + struct vfs *vfsp, + const char *rpath, + int rplen, + rhashq_t *rhtp) +{ + smbnode_t *np; + vnode_t *vp; + + ASSERT(RW_LOCK_HELD(&rhtp->r_lock)); + + for (np = rhtp->r_hashf; np != (smbnode_t *)rhtp; np = np->r_hashf) { + vp = SMBTOV(np); + if (vp->v_vfsp == vfsp && + np->n_rplen == rplen && + bcmp(np->n_rpath, rpath, rplen) == 0) { + /* + * remove smbnode from free list, if necessary. + */ + if (np->r_freef != NULL) { + mutex_enter(&smbfreelist_lock); + /* + * If the smbnode is on the freelist, + * then remove it and use that reference + * as the new reference. Otherwise, + * need to increment the reference count. + */ + if (np->r_freef != NULL) { + smb_rmfree(np); + mutex_exit(&smbfreelist_lock); + } else { + mutex_exit(&smbfreelist_lock); + VN_HOLD(vp); + } + } else + VN_HOLD(vp); + return (np); + } + } + return (NULL); +} + +#ifdef SMB_VNODE_DEBUG +int smb_check_table_debug = 1; +#else /* SMB_VNODE_DEBUG */ +int smb_check_table_debug = 0; +#endif /* SMB_VNODE_DEBUG */ + + +/* + * Return 1 if there is a active vnode belonging to this vfs in the + * smbtable cache. + * + * Several of these checks are done without holding the usual + * locks. This is safe because destroy_smbtable(), smb_addfree(), + * etc. will redo the necessary checks before actually destroying + * any smbnodes. + * + * NFS: nfs_subr.c:check_rtable + * + * Debugging changes here relative to NFS. + * Relatively harmless, so left 'em in. + */ +int +smb_check_table(struct vfs *vfsp, smbnode_t *rtnp) +{ + smbnode_t *np; + vnode_t *vp; + int index; + int busycnt = 0; + + for (index = 0; index < smbtablesize; index++) { + rw_enter(&smbtable[index].r_lock, RW_READER); + for (np = smbtable[index].r_hashf; + np != (smbnode_t *)(&smbtable[index]); + np = np->r_hashf) { + if (np == rtnp) + continue; /* skip the root */ + vp = SMBTOV(np); + if (vp->v_vfsp != vfsp) + continue; /* skip other mount */ + + /* Now the 'busy' checks: */ + /* Not on the free list? */ + if (np->r_freef == NULL) { + SMBVDEBUG("!r_freef: node=0x%p, v_path=%s\n", + (void *)np, vp->v_path); + busycnt++; + } + + /* Has dirty pages? */ + if (vn_has_cached_data(vp) && + (np->r_flags & RDIRTY)) { + SMBVDEBUG("is dirty: node=0x%p, v_path=%s\n", + (void *)np, vp->v_path); + busycnt++; + } + + /* Other refs? (not reflected in v_count) */ + if (np->r_count > 0) { + SMBVDEBUG("+r_count: node=0x%p, v_path=%s\n", + (void *)np, vp->v_path); + busycnt++; + } + + if (busycnt && !smb_check_table_debug) + break; + + } + rw_exit(&smbtable[index].r_lock); + } + return (busycnt); +} + +/* + * Destroy inactive vnodes from the hash queues which belong to this + * vfs. It is essential that we destroy all inactive vnodes during a + * forced unmount as well as during a normal unmount. + * + * NFS: nfs_subr.c:destroy_rtable + */ +void +smbfs_destroy_table(struct vfs *vfsp) +{ + int index; + smbnode_t *np; + smbnode_t *rlist; + smbnode_t *r_hashf; + vnode_t *vp; + + rlist = NULL; + + for (index = 0; index < smbtablesize; index++) { + rw_enter(&smbtable[index].r_lock, RW_WRITER); + for (np = smbtable[index].r_hashf; + np != (smbnode_t *)(&smbtable[index]); + np = r_hashf) { + /* save the hash pointer before destroying */ + r_hashf = np->r_hashf; + vp = SMBTOV(np); + if (vp->v_vfsp == vfsp) { + mutex_enter(&smbfreelist_lock); + if (np->r_freef != NULL) { + smb_rmfree(np); + mutex_exit(&smbfreelist_lock); + smb_rmhash_locked(np); + np->r_hashf = rlist; + rlist = np; + } else + mutex_exit(&smbfreelist_lock); + } + } + rw_exit(&smbtable[index].r_lock); + } + + for (np = rlist; np != NULL; np = rlist) { + rlist = np->r_hashf; + /* + * This call to smb_addfree will end up destroying the + * smbnode, but in a safe way with the appropriate set + * of checks done. + */ + smb_addfree(np); + } + +} + +/* + * This routine destroys all the resources associated with the smbnode + * and then the smbnode itself. + * + * NFS: nfs_subr.c:destroy_rnode + */ +void +smb_destroy_node(smbnode_t *np) +{ + vnode_t *vp; + vfs_t *vfsp; + + vp = SMBTOV(np); + vfsp = vp->v_vfsp; + + ASSERT(vp->v_count == 1); + ASSERT(np->r_count == 0); + ASSERT(np->r_mapcnt == 0); + ASSERT(!(np->r_flags & RHASHED)); + ASSERT(np->r_freef == NULL && np->r_freeb == NULL); + atomic_add_long((ulong_t *)&smbnodenew, -1); + vn_invalid(vp); + vn_free(vp); + kmem_cache_free(smbnode_cache, np); + VFS_RELE(vfsp); +} + +/* rflush? */ +/* access cache */ +/* client handles */ + +/* + * initialize resources that are used by smbfs_subr.c + * this is called from the _init() routine (by the way of smbfs_clntinit()) + * + * allocate and initialze smbfs hash table + * NFS: nfs_subr.c:nfs_subrinit + */ +int +smbfs_subrinit(void) +{ + int i; + ulong_t nsmbnode_max; + + /* + * Allocate and initialize the smbnode hash queues + */ + if (nsmbnode <= 0) + nsmbnode = ncsize; /* dnlc.h */ + nsmbnode_max = (ulong_t)((kmem_maxavail() >> 2) / + sizeof (struct smbnode)); + if (nsmbnode > nsmbnode_max || (nsmbnode == 0 && ncsize == 0)) { + zcmn_err(GLOBAL_ZONEID, CE_NOTE, + "setting nsmbnode to max value of %ld", nsmbnode_max); + nsmbnode = nsmbnode_max; + } + + smbtablesize = 1 << highbit(nsmbnode / smbhashlen); + smbtablemask = smbtablesize - 1; + smbtable = kmem_alloc(smbtablesize * sizeof (*smbtable), KM_SLEEP); + for (i = 0; i < smbtablesize; i++) { + smbtable[i].r_hashf = (smbnode_t *)(&smbtable[i]); + smbtable[i].r_hashb = (smbnode_t *)(&smbtable[i]); + rw_init(&smbtable[i].r_lock, NULL, RW_DEFAULT, NULL); + } + smbnode_cache = kmem_cache_create("smbnode_cache", sizeof (smbnode_t), + 0, NULL, NULL, smbfs_kmem_reclaim, NULL, NULL, 0); + + /* + * Initialize the various mutexes and reader/writer locks + */ + mutex_init(&smbfreelist_lock, NULL, MUTEX_DEFAULT, NULL); + mutex_init(&smbfs_minor_lock, NULL, MUTEX_DEFAULT, NULL); + + /* + * Assign unique major number for all smbfs mounts + */ + if ((smbfs_major = getudev()) == -1) { + zcmn_err(GLOBAL_ZONEID, CE_WARN, + "smbfs: init: can't get unique device number"); + smbfs_major = 0; + } + smbfs_minor = 0; + + return (0); +} + +/* + * free smbfs hash table, etc. + * NFS: nfs_subr.c:nfs_subrfini + */ +void +smbfs_subrfini(void) +{ + int i; + + /* + * Deallocate the smbnode hash queues + */ + kmem_cache_destroy(smbnode_cache); + + for (i = 0; i < smbtablesize; i++) + rw_destroy(&smbtable[i].r_lock); + kmem_free(smbtable, smbtablesize * sizeof (*smbtable)); + + /* + * Destroy the various mutexes and reader/writer locks + */ + mutex_destroy(&smbfreelist_lock); + mutex_destroy(&smbfs_minor_lock); +} + +/* rddir_cache ? */ + +/* + * Support functions for smbfs_kmem_reclaim + */ + +static int +smbfs_node_reclaim(void) +{ + int freed; + smbnode_t *np; + vnode_t *vp; + + freed = 0; + mutex_enter(&smbfreelist_lock); + while ((np = smbfreelist) != NULL) { + smb_rmfree(np); + mutex_exit(&smbfreelist_lock); + if (np->r_flags & RHASHED) { + vp = SMBTOV(np); + rw_enter(&np->r_hashq->r_lock, RW_WRITER); + mutex_enter(&vp->v_lock); + if (vp->v_count > 1) { + vp->v_count--; + mutex_exit(&vp->v_lock); + rw_exit(&np->r_hashq->r_lock); + mutex_enter(&smbfreelist_lock); + continue; + } + mutex_exit(&vp->v_lock); + smb_rmhash_locked(np); + rw_exit(&np->r_hashq->r_lock); + } + /* + * This call to smb_addfree will end up destroying the + * smbnode, but in a safe way with the appropriate set + * of checks done. + */ + smb_addfree(np); + mutex_enter(&smbfreelist_lock); + } + mutex_exit(&smbfreelist_lock); + return (freed); +} + +/* + * Called by kmem_cache_alloc ask us if we could + * "Please give back some memory!" + * + * Todo: dump nodes from the free list? + */ +/*ARGSUSED*/ +void +smbfs_kmem_reclaim(void *cdrarg) +{ + (void) smbfs_node_reclaim(); +} + +/* nfs failover stuff */ +/* nfs_rw_xxx - see smbfs_rwlock.c */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,915 @@ +/* + * 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: smbfs_vfsops.c,v 1.73.64.1 2005/05/27 02:35:28 lindak Exp $ + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/systm.h> +#include <sys/cred.h> +#include <sys/vfs.h> +#include <sys/vnode.h> +#include <fs/fs_subr.h> +#include <sys/sysmacros.h> +#include <sys/kmem.h> +#include <sys/mkdev.h> +#include <sys/mount.h> +#include <sys/statvfs.h> +#include <sys/errno.h> +#include <sys/debug.h> +#include <sys/cmn_err.h> +#include <sys/modctl.h> +#include <sys/policy.h> +#include <sys/atomic.h> +#include <sys/zone.h> +#include <sys/vfs_opreg.h> +#include <sys/mntent.h> +#include <sys/priv.h> +#include <sys/tsol/label.h> +#include <sys/tsol/tndb.h> +#include <inet/ip.h> + +#include <netsmb/smb_osdep.h> +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> +#include <netsmb/smb_dev.h> + +#include <smbfs/smbfs.h> +#include <smbfs/smbfs_node.h> +#include <smbfs/smbfs_subr.h> + +/* + * Local functions definitions. + */ +int smbfsinit(int fstyp, char *name); +void smbfsfini(); +static int smbfs_mount_label_policy(vfs_t *, void *, int, cred_t *); + +static vfsdef_t vfw = { + VFSDEF_VERSION, + "smbfs", /* type name string */ + smbfsinit, /* init routine */ + VSW_NOTZONESAFE, /* flags */ + NULL /* mount options table prototype */ +}; + +static struct modlfs modlfs = { + &mod_fsops, + "SMBFS filesystem v" SMBFS_VER_STR, + &vfw +}; + +static struct modlinkage modlinkage = { + MODREV_1, (void *)&modlfs, NULL +}; + +/* + * Mutex to protect the following variables: + * smbfs_major + * smbfs_minor + */ +extern kmutex_t smbfs_minor_lock; +extern int smbfs_major; +extern int smbfs_minor; + +/* + * Prevent unloads while we have mounts + */ +uint32_t smbfs_mountcount; + +/* + * smbfs vfs operations. + */ +static int smbfs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *); +static int smbfs_unmount(vfs_t *, int, cred_t *); +static int smbfs_root(vfs_t *, vnode_t **); +static int smbfs_statvfs(vfs_t *, statvfs64_t *); +static int smbfs_sync(vfs_t *, short, cred_t *); +static void smbfs_freevfs(vfs_t *); + +/* + * Module loading + */ + +/* + * This routine is invoked automatically when the kernel module + * containing this routine is loaded. This allows module specific + * initialization to be done when the module is loaded. + */ +int +_init(void) +{ + int status; + + /* + * Check compiled-in version of "nsmb" + * that we're linked with. (paranoid) + */ + if (nsmb_version != NSMB_VERSION) { + cmn_err(CE_WARN, "_init: nsmb version mismatch"); + return (ENOTTY); + } + + smbfs_mountcount = 0; + + if ((status = smbfs_clntinit()) != 0) { + cmn_err(CE_WARN, "_init: smbfs_clntinit failed"); + return (status); + } + + status = mod_install((struct modlinkage *)&modlinkage); + return (status); +} + +/* + * Free kernel module resources that were allocated in _init + * and remove the linkage information into the kernel + */ +int +_fini(void) +{ + int error; + + /* + * If a forcedly unmounted instance is still hanging around, + * we cannot allow the module to be unloaded because that would + * cause panics once the VFS framework decides it's time to call + * into VFS_FREEVFS(). + */ + if (smbfs_mountcount) + return (EBUSY); + + error = mod_remove(&modlinkage); + if (error) + return (error); + + /* + * Free the allocated smbnodes, etc. + */ + smbfs_clntfini(); + + /* + * Free the ops vectors + */ + smbfsfini(); + return (0); +} + +/* + * Return information about the module + */ +int +_info(struct modinfo *modinfop) +{ + return (mod_info((struct modlinkage *)&modlinkage, modinfop)); +} + +/* + * Initialize the vfs structure + */ + +int smbfsfstyp; +vfsops_t *smbfs_vfsops = NULL; + +static const fs_operation_def_t smbfs_vfsops_template[] = { + { VFSNAME_MOUNT, { .vfs_mount = smbfs_mount } }, + { VFSNAME_UNMOUNT, { .vfs_unmount = smbfs_unmount } }, + { VFSNAME_ROOT, { .vfs_root = smbfs_root } }, + { VFSNAME_STATVFS, { .vfs_statvfs = smbfs_statvfs } }, + { VFSNAME_SYNC, { .vfs_sync = smbfs_sync } }, + { VFSNAME_VGET, { .error = fs_nosys } }, + { VFSNAME_MOUNTROOT, { .error = fs_nosys } }, + { VFSNAME_FREEVFS, { .vfs_freevfs = smbfs_freevfs } }, + { NULL, NULL } +}; + +int +smbfsinit(int fstyp, char *name) +{ + int error; + + error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops); + if (error != 0) { + zcmn_err(GLOBAL_ZONEID, CE_WARN, + "smbfsinit: bad vfs ops template"); + return (error); + } + + error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops); + if (error != 0) { + (void) vfs_freevfsops_by_type(fstyp); + zcmn_err(GLOBAL_ZONEID, CE_WARN, + "smbfsinit: bad vnode ops template"); + return (error); + } + + smbfsfstyp = fstyp; + + return (0); +} + +void +smbfsfini() +{ + if (smbfs_vfsops) { + (void) vfs_freevfsops_by_type(smbfsfstyp); + smbfs_vfsops = NULL; + } + if (smbfs_vnodeops) { + vn_freevnodeops(smbfs_vnodeops); + smbfs_vnodeops = NULL; + } +} + +void +smbfs_free_smi(smbmntinfo_t *smi) +{ + if (smi) { + smbfs_zonelist_remove(smi); + kmem_free(smi, sizeof (smbmntinfo_t)); + } +} + +/* + * smbfs mount vfsop + * Set up mount info record and attach it to vfs struct. + */ +static int +smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) +{ + char *data = uap->dataptr; + int error; + vnode_t *rtvp = NULL; /* root of this fs */ + smbmntinfo_t *smi = NULL; + dev_t smbfs_dev; + int version; + int devfd; + zone_t *zone = curproc->p_zone; + zone_t *mntzone = NULL; + smb_share_t *ssp = NULL; + smb_cred_t scred; + + STRUCT_DECL(smbfs_args, args); /* smbfs mount arguments */ + + if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) + return (error); + + if (mvp->v_type != VDIR) + return (ENOTDIR); + + /* + * get arguments + * + * uap->datalen might be different from sizeof (args) + * in a compatible situation. + */ + STRUCT_INIT(args, get_udatamodel()); + bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)); + if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen, + SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)))) + return (EFAULT); + + /* + * Check mount program version + */ + version = STRUCT_FGET(args, version); + if (version != SMBFS_VERSION) { + cmn_err(CE_WARN, "mount version mismatch:" + " kernel=%d, mount=%d\n", + SMBFS_VERSION, version); + return (EINVAL); + } + + if (uap->flags & MS_REMOUNT) { + cmn_err(CE_WARN, "MS_REMOUNT not implemented"); + return (ENOTSUP); + } + + /* + * Check for busy + */ + mutex_enter(&mvp->v_lock); + if (!(uap->flags & MS_OVERLAY) && + (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { + mutex_exit(&mvp->v_lock); + return (EBUSY); + } + mutex_exit(&mvp->v_lock); + + /* + * Get the "share" from the netsmb driver (ssp). + * It is returned with a "ref" (hold) for us. + * Release this hold: at errout below, or in + * smbfs_freevfs(). + */ + devfd = STRUCT_FGET(args, devfd); + error = smb_dev2share(devfd, &ssp); + if (error) { + cmn_err(CE_WARN, "invalid device handle %d (%d)\n", + devfd, error); + return (error); + } + + /* + * We don't have data structures to support multiple mounts of + * the same share object by the same owner, so don't allow it. + */ + if (ssp->ss_mount != NULL) { + smb_share_rele(ssp); + return (EBUSY); + } + + smb_credinit(&scred, curproc, cr); + + /* + * Use "goto errout" from here on. + * See: ssp, smi, rtvp, mntzone + */ + + /* + * Determine the zone we're being mounted into. + */ + zone_hold(mntzone = zone); /* start with this assumption */ + if (getzoneid() == GLOBAL_ZONEID) { + zone_rele(mntzone); + mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); + ASSERT(mntzone != NULL); + if (mntzone != zone) { + error = EBUSY; + goto errout; + } + } + + /* + * Stop the mount from going any further if the zone is going away. + */ + if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) { + error = EBUSY; + goto errout; + } + + /* + * On a Trusted Extensions client, we may have to force read-only + * for read-down mounts. + */ + if (is_system_labeled()) { + void *addr; + int ipvers = 0; + struct smb_vc *vcp; + + vcp = SSTOVC(ssp); + addr = smb_vc_getipaddr(vcp, &ipvers); + error = smbfs_mount_label_policy(vfsp, addr, ipvers, cr); + + if (error > 0) + goto errout; + + if (error == -1) { + /* change mount to read-only to prevent write-down */ + vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); + } + } + + /* + * Get root vnode. + */ +proceed: + + /* + * Create a mount record and link it to the vfs struct. + * Compare with NFS: nfsrootvp() + */ + smi = kmem_zalloc(sizeof (smbmntinfo_t), KM_SLEEP); + + smi->smi_share = ssp; + ssp->ss_mount = smi; + smi->smi_zone = mntzone; + + /* + * XXX If not root, get uid/gid from the covered vnode. + */ + smi->smi_args.dir_mode = STRUCT_FGET(args, dir_mode); + smi->smi_args.file_mode = STRUCT_FGET(args, file_mode); + smi->smi_args.uid = STRUCT_FGET(args, uid); + smi->smi_args.gid = STRUCT_FGET(args, gid); + + error = smbfs_smb_qfsattr(ssp, &smi->smi_fsattr, &scred); + if (error) { + SMBVDEBUG("smbfs_smb_qfsattr error %d\n", error); + } + +#ifdef NOT_YET + /* Once acls are implemented, remove the ifdefs */ + else if (smbfs_aclsflunksniff(smi, &scred)) { + mutex_enter(&smi->smi_lock); + smi->smi_fsattr &= ~FILE_PERSISTENT_ACLS; + mutex_exit(&smi->smi_lock); + } +#endif /* NOT_YET */ + + /* + * Assign a unique device id to the mount + */ + mutex_enter(&smbfs_minor_lock); + do { + smbfs_minor = (smbfs_minor + 1) & MAXMIN32; + smbfs_dev = makedevice(smbfs_major, smbfs_minor); + } while (vfs_devismounted(smbfs_dev)); + mutex_exit(&smbfs_minor_lock); + + vfsp->vfs_dev = smbfs_dev; + vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfsfstyp); + vfsp->vfs_data = (caddr_t)smi; + vfsp->vfs_fstype = smbfsfstyp; + vfsp->vfs_bsize = MAXBSIZE; + vfsp->vfs_bcount = 0; + + smi->smi_flags = SMI_INT | SMI_LLOCK; + smi->smi_vfsp = vfsp; + smbfs_zonelist_add(smi); + + /* + * Create the root vnode, which we need in unmount + * for the call to smb_check_table(), etc. + */ + rtvp = smbfs_make_node(vfsp, "\\", 1, NULL, 0, NULL); + if (!rtvp) { + cmn_err(CE_WARN, "smbfs_mount: make_node failed\n"); + return (ENOENT); + } + rtvp->v_type = VDIR; + rtvp->v_flag |= VROOT; + + /* + * Could get attributes here, but that can wait + * until someone does a getattr call. + * + * NFS does other stuff here too: + * async worker threads + * init kstats + * + * End of code from NFS nfsrootvp() + */ + + smb_credrele(&scred); + + smi->smi_root = VTOSMB(rtvp); + + atomic_inc_32(&smbfs_mountcount); + + return (0); + +errout: + + ASSERT(rtvp == NULL); + + vfsp->vfs_data = NULL; + if (smi) + smbfs_free_smi(smi); + + if (mntzone != NULL) + zone_rele(mntzone); + + if (ssp) + smb_share_rele(ssp); + + smb_credrele(&scred); + + /* args, if we allocated */ + + return (error); +} + +/* + * vfs operations + */ +static int +smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr) +{ + smbmntinfo_t *smi; + smbnode_t *rtnp; + + smi = VFTOSMI(vfsp); + + if (secpolicy_fs_unmount(cr, vfsp) != 0) + return (EPERM); + + if ((flag & MS_FORCE) == 0) { +#ifdef APPLE + smbfs_rflush(vfsp, cr); +#endif + + /* + * If there are any active vnodes on this file system, + * (other than the root vnode) then the file system is + * busy and can't be umounted. + */ + if (smb_check_table(vfsp, smi->smi_root)) + return (EBUSY); + + /* + * We normally hold a ref to the root vnode, so + * check for references beyond the one we expect: + * smbmntinfo_t -> smi_root + * Note that NFS does not hold the root vnode. + */ + if (smi->smi_root && + smi->smi_root->r_vnode->v_count > 1) + return (EBUSY); + } + + /* + * common code for both forced and non-forced + * + * Setting VFS_UNMOUNTED prevents new operations. + * Operations already underway may continue, + * but not for long. + */ + vfsp->vfs_flag |= VFS_UNMOUNTED; + + /* + * Shutdown any outstanding I/O requests on this share, + * and force a tree disconnect. The share object will + * continue to hang around until smb_share_rele(). + * This should also cause most active nodes to be + * released as their operations fail with EIO. + */ + smb_share_kill(smi->smi_share); + + /* + * If we hold the root VP (and we normally do) + * then it's safe to release it now. + */ + if (smi->smi_root) { + rtnp = smi->smi_root; + smi->smi_root = NULL; + VN_RELE(rtnp->r_vnode); /* release root vnode */ + } + + /* + * Remove all nodes from the node hash tables. + * This (indirectly) calls: smb_addfree, smbinactive, + * which will try to flush dirty pages, etc. so + * don't destroy the underlying share just yet. + * + * Also, with a forced unmount, some nodes may + * remain active, and those will get cleaned up + * after their last vn_rele. + */ + smbfs_destroy_table(vfsp); + + /* + * Delete our kstats... + * + * Doing it here, rather than waiting until + * smbfs_freevfs so these are not visible + * after the unmount. + */ + if (smi->smi_io_kstats) { + kstat_delete(smi->smi_io_kstats); + smi->smi_io_kstats = NULL; + } + if (smi->smi_ro_kstats) { + kstat_delete(smi->smi_ro_kstats); + smi->smi_ro_kstats = NULL; + } + + /* + * Note: the smb_share_rele() + * happens in smbfs_freevfs() + */ + + return (0); +} + + +/* + * find root of smbfs + */ +static int +smbfs_root(vfs_t *vfsp, vnode_t **vpp) +{ + smbmntinfo_t *smi; + vnode_t *vp; + + smi = VFTOSMI(vfsp); + + if (curproc->p_zone != smi->smi_zone) + return (EPERM); + + if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + /* + * The root vp is created in mount and held + * until unmount, so this is paranoia. + */ + if (smi->smi_root == NULL) + return (EIO); + + /* Just take a reference and return it. */ + vp = SMBTOV(smi->smi_root); + VN_HOLD(vp); + *vpp = vp; + + return (0); +} + +/* + * Get file system statistics. + */ +static int +smbfs_statvfs(vfs_t *vfsp, statvfs64_t *sbp) +{ + int error; + smbmntinfo_t *smi = VFTOSMI(vfsp); + smb_share_t *ssp = smi->smi_share; + statvfs64_t stvfs; + hrtime_t now; + smb_cred_t scred; + + if (curproc->p_zone != smi->smi_zone) + return (EPERM); + + if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + mutex_enter(&smi->smi_lock); + + /* + * Use cached result if still valid. + */ +recheck: + now = gethrtime(); + if (now < smi->smi_statfstime) { + goto cache_hit; + } + + /* + * FS attributes are stale, so someone + * needs to do an OTW call to get them. + * Serialize here so only one thread + * does the OTW call. + */ + if (smi->smi_status & SM_STATUS_STATFS_BUSY) { + smi->smi_status |= SM_STATUS_STATFS_WANT; + if (!cv_wait_sig(&smi->smi_statvfs_cv, &smi->smi_lock)) { + mutex_exit(&smi->smi_lock); + return (EINTR); + } + /* Hope status is valid now. */ + goto recheck; + } + smi->smi_status |= SM_STATUS_STATFS_BUSY; + mutex_exit(&smi->smi_lock); + + /* + * Do the OTW call. Note: lock NOT held. + */ + smb_credinit(&scred, curproc, NULL); + bzero(&stvfs, sizeof (stvfs)); + error = smbfs_smb_statfs(ssp, &stvfs, &scred); + smb_credrele(&scred); + + mutex_enter(&smi->smi_lock); + if (smi->smi_status & SM_STATUS_STATFS_WANT) + cv_broadcast(&smi->smi_statvfs_cv); + smi->smi_status &= ~(SM_STATUS_STATFS_BUSY | SM_STATUS_STATFS_WANT); + + if (error) { + SMBVDEBUG("statfs error=%d\n", error); + mutex_exit(&smi->smi_lock); + return (error); + } + + /* + * Set a few things the OTW call didn't get. + */ + stvfs.f_frsize = stvfs.f_bsize; + stvfs.f_favail = stvfs.f_ffree; + stvfs.f_fsid = (unsigned long)vfsp->vfs_fsid.val[0]; + strncpy(stvfs.f_basetype, vfw.name, FSTYPSZ); + stvfs.f_flag = vf_to_stf(vfsp->vfs_flag); + stvfs.f_namemax = (uint32_t)MAXNAMELEN - 1; + + /* + * Save the result, update lifetime + */ + now = gethrtime(); + smi->smi_statfstime = now + + (SM_MAX_STATFSTIME * (hrtime_t)NANOSEC); + smi->smi_statvfsbuf = stvfs; /* struct assign! */ + + /* + * Copy the statvfs data to caller's buf. + * Note: struct assignment + */ +cache_hit: + *sbp = smi->smi_statvfsbuf; + mutex_exit(&smi->smi_lock); + return (error); +} + +static kmutex_t smbfs_syncbusy; + +/* + * Flush dirty smbfs files for file system vfsp. + * If vfsp == NULL, all smbfs files are flushed. + */ +/*ARGSUSED*/ +static int +smbfs_sync(vfs_t *vfsp, short flag, cred_t *cr) +{ + /* + * Cross-zone calls are OK here, since this translates to a + * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone. + */ +#ifdef APPLE + if (!(flag & SYNC_ATTR) && mutex_tryenter(&smbfs_syncbusy) != 0) { + smbfs_rflush(vfsp, cr); + mutex_exit(&smbfs_syncbusy); + } +#endif /* APPLE */ + return (0); +} + +/* + * Initialization routine for VFS routines. Should only be called once + */ +int +smbfs_vfsinit(void) +{ + mutex_init(&smbfs_syncbusy, NULL, MUTEX_DEFAULT, NULL); + return (0); +} + +/* + * Shutdown routine for VFS routines. Should only be called once + */ +void +smbfs_vfsfini(void) +{ + mutex_destroy(&smbfs_syncbusy); +} + +void +smbfs_freevfs(vfs_t *vfsp) +{ + smbmntinfo_t *smi; + smb_share_t *ssp; + + /* free up the resources */ + smi = VFTOSMI(vfsp); + + /* + * By this time we should have already deleted the + * smi kstats in the unmount code. If they are still around + * something is wrong + */ + ASSERT(smi->smi_io_kstats == NULL); + + /* + * Drop our reference to the share. + * This usually leads to VC close. + */ + ssp = smi->smi_share; + smi->smi_share = NULL; + ssp->ss_mount = NULL; + + smb_share_rele(ssp); + + zone_rele(smi->smi_zone); + + smbfs_free_smi(smi); + + /* + * Allow _fini() to succeed now, if so desired. + */ + atomic_dec_32(&smbfs_mountcount); +} + +/* + * smbfs_mount_label_policy: + * Determine whether the mount is allowed according to MAC check, + * by comparing (where appropriate) label of the remote server + * against the label of the zone being mounted into. + * + * Returns: + * 0 : access allowed + * -1 : read-only access allowed (i.e., read-down) + * >0 : error code, such as EACCES + * + * NB: + * NFS supports Cipso labels by parsing the vfs_resource + * to see what the Solaris server global zone has shared. + * We can't support that for CIFS since resource names + * contain share names, not paths. + */ +static int +smbfs_mount_label_policy(vfs_t *vfsp, void *ipaddr, int addr_type, cred_t *cr) +{ + bslabel_t *server_sl, *mntlabel; + zone_t *mntzone = NULL; + ts_label_t *zlabel; + tsol_tpc_t *tp; + ts_label_t *tsl = NULL; + int retv; + + /* + * Get the zone's label. Each zone on a labeled system has a label. + */ + mntzone = zone_find_by_any_path(refstr_value(vfsp->vfs_mntpt), B_FALSE); + zlabel = mntzone->zone_slabel; + ASSERT(zlabel != NULL); + label_hold(zlabel); + + retv = EACCES; /* assume the worst */ + + /* + * Next, get the assigned label of the remote server. + */ + tp = find_tpc(ipaddr, addr_type, B_FALSE); + if (tp == NULL) + goto out; /* error getting host entry */ + + if (tp->tpc_tp.tp_doi != zlabel->tsl_doi) + goto rel_tpc; /* invalid domain */ + if ((tp->tpc_tp.host_type != UNLABELED)) + goto rel_tpc; /* invalid hosttype */ + + server_sl = &tp->tpc_tp.tp_def_label; + mntlabel = label2bslabel(zlabel); + + /* + * Now compare labels to complete the MAC check. If the labels + * are equal or if the requestor is in the global zone and has + * NET_MAC_AWARE, then allow read-write access. (Except for + * mounts into the global zone itself; restrict these to + * read-only.) + * + * If the requestor is in some other zone, but his label + * dominates the server, then allow read-down. + * + * Otherwise, access is denied. + */ + if (blequal(mntlabel, server_sl) || + (crgetzoneid(cr) == GLOBAL_ZONEID && + getpflags(NET_MAC_AWARE, cr) != 0)) { + if ((mntzone == global_zone) || + !blequal(mntlabel, server_sl)) + retv = -1; /* read-only */ + else + retv = 0; /* access OK */ + } else if (bldominates(mntlabel, server_sl)) { + retv = -1; /* read-only */ + } else { + retv = EACCES; + } + + if (tsl != NULL) + label_rele(tsl); + +rel_tpc: + /*LINTED*/ + TPC_RELE(tp); +out: + if (mntzone) + zone_rele(mntzone); + label_rele(zlabel); + return (retv); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,2498 @@ +/* + * 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: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $ + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/systm.h> +#include <sys/cred.h> +#include <sys/vnode.h> +#include <sys/vfs.h> +#include <sys/uio.h> +#include <sys/dirent.h> +#include <sys/errno.h> +#include <sys/sysmacros.h> +#include <sys/kmem.h> +#include <sys/cmn_err.h> +#include <sys/dnlc.h> +#include <sys/vfs_opreg.h> +#include <sys/policy.h> + +#include <netsmb/smb_osdep.h> +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> + +#include <smbfs/smbfs.h> +#include <smbfs/smbfs_node.h> +#include <smbfs/smbfs_subr.h> + +#include <fs/fs_subr.h> + +/* + * These characters are illegal in NTFS file names. + * ref: http://support.microsoft.com/kb/147438 + */ +static const char illegal_chars[] = { + '\\', /* back slash */ + '/', /* slash */ + ':', /* colon */ + '*', /* asterisk */ + '?', /* question mark */ + '"', /* double quote */ + '<', /* less than sign */ + '>', /* greater than sign */ + '|', /* vertical bar */ + 0 +}; + +/* + * Turning this on causes nodes to be created in the cache + * during directory listings. The "fast" claim is debatable, + * and the effects on the cache can be undesirable. + */ + +/* local static function defines */ + +static int smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, + int dnlc, caller_context_t *); +static int smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, + cred_t *cr, caller_context_t *); +static int smbfssetattr(vnode_t *, struct vattr *, int, cred_t *); +static int smbfs_accessx(void *, int, cred_t *); +static int smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, + caller_context_t *); +/* + * These are the vnode ops routines which implement the vnode interface to + * the networked file system. These routines just take their parameters, + * make them look networkish by putting the right info into interface structs, + * and then calling the appropriate remote routine(s) to do the work. + * + * Note on directory name lookup cacheing: If we detect a stale fhandle, + * we purge the directory cache relative to that vnode. This way, the + * user won't get burned by the cache repeatedly. See <smbfs/smbnode.h> for + * more details on smbnode locking. + */ + +static int smbfs_open(vnode_t **, int, cred_t *, caller_context_t *); +static int smbfs_close(vnode_t *, int, int, offset_t, cred_t *, + caller_context_t *); +static int smbfs_read(vnode_t *, struct uio *, int, cred_t *, + caller_context_t *); +static int smbfs_write(vnode_t *, struct uio *, int, cred_t *, + caller_context_t *); +static int smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *, + caller_context_t *); +static int smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *, + caller_context_t *); +static int smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *); +static int smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *); +static void smbfs_inactive(vnode_t *, cred_t *, caller_context_t *); +static int smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *, + int, vnode_t *, cred_t *, caller_context_t *, + int *, pathname_t *); +static int smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl, + int, vnode_t **, cred_t *, int, caller_context_t *, + vsecattr_t *); +static int smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *, + int); +static int smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *, + caller_context_t *, int); +static int smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **, + cred_t *, caller_context_t *, int, vsecattr_t *); +static int smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *, + caller_context_t *, int); +static int smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *, + caller_context_t *, int); +static int smbfs_rwlock(vnode_t *, int, caller_context_t *); +static void smbfs_rwunlock(vnode_t *, int, caller_context_t *); +static int smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *); +static int smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t, + struct flk_callback *, cred_t *, caller_context_t *); +static int smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t, + cred_t *, caller_context_t *); +static int smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *, + caller_context_t *); +static int smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *, + caller_context_t *); + +/* Dummy function to use until correct function is ported in */ +int noop_vnodeop() { + return (0); +} + +struct vnodeops *smbfs_vnodeops = NULL; + +/* + * Most unimplemented ops will return ENOSYS because of fs_nosys(). + * The only ops where that won't work are ACCESS (due to open(2) + * failures) and GETSECATTR (due to acl(2) failures). + */ +const fs_operation_def_t smbfs_vnodeops_template[] = { + { VOPNAME_OPEN, { .vop_open = smbfs_open } }, + { VOPNAME_CLOSE, { .vop_close = smbfs_close } }, + { VOPNAME_READ, { .vop_read = smbfs_read } }, + { VOPNAME_WRITE, { .vop_write = smbfs_write } }, + { VOPNAME_IOCTL, { .error = fs_nosys } }, /* smbfs_ioctl, */ + { VOPNAME_GETATTR, { .vop_getattr = smbfs_getattr } }, + { VOPNAME_SETATTR, { .vop_setattr = smbfs_setattr } }, + { VOPNAME_ACCESS, { .vop_access = smbfs_access } }, + { VOPNAME_LOOKUP, { .vop_lookup = smbfs_lookup } }, + { VOPNAME_CREATE, { .vop_create = smbfs_create } }, + { VOPNAME_REMOVE, { .vop_remove = smbfs_remove } }, + { VOPNAME_LINK, { .error = fs_nosys } }, /* smbfs_link, */ + { VOPNAME_RENAME, { .vop_rename = smbfs_rename } }, + { VOPNAME_MKDIR, { .vop_mkdir = smbfs_mkdir } }, + { VOPNAME_RMDIR, { .vop_rmdir = smbfs_rmdir } }, + { VOPNAME_READDIR, { .vop_readdir = smbfs_readdir } }, + { VOPNAME_SYMLINK, { .error = fs_nosys } }, /* smbfs_symlink, */ + { VOPNAME_READLINK, { .error = fs_nosys } }, /* smbfs_readlink, */ + { VOPNAME_FSYNC, { .vop_fsync = smbfs_fsync } }, + { VOPNAME_INACTIVE, { .vop_inactive = smbfs_inactive } }, + { VOPNAME_FID, { .error = fs_nosys } }, /* smbfs_fid, */ + { VOPNAME_RWLOCK, { .vop_rwlock = smbfs_rwlock } }, + { VOPNAME_RWUNLOCK, { .vop_rwunlock = smbfs_rwunlock } }, + { VOPNAME_SEEK, { .vop_seek = smbfs_seek } }, + { VOPNAME_FRLOCK, { .vop_frlock = smbfs_frlock } }, + { VOPNAME_SPACE, { .vop_space = smbfs_space } }, + { VOPNAME_REALVP, { .error = fs_nosys } }, /* smbfs_realvp, */ + { VOPNAME_GETPAGE, { .error = fs_nosys } }, /* smbfs_getpage, */ + { VOPNAME_PUTPAGE, { .error = fs_nosys } }, /* smbfs_putpage, */ + { VOPNAME_MAP, { .error = fs_nosys } }, /* smbfs_map, */ + { VOPNAME_ADDMAP, { .error = fs_nosys } }, /* smbfs_addmap, */ + { VOPNAME_DELMAP, { .error = fs_nosys } }, /* smbfs_delmap, */ + { VOPNAME_DUMP, { .error = fs_nosys } }, /* smbfs_dump, */ + { VOPNAME_PATHCONF, { .vop_pathconf = smbfs_pathconf } }, + { VOPNAME_PAGEIO, { .error = fs_nosys } }, /* smbfs_pageio, */ + { VOPNAME_SETSECATTR, { .error = fs_nosys } }, /* smbfs_setsecattr, */ + { VOPNAME_GETSECATTR, { .error = noop_vnodeop } }, + /* smbfs_getsecattr, */ + { VOPNAME_SHRLOCK, { .vop_shrlock = smbfs_shrlock } }, + { NULL, NULL } +}; + +/* + * XXX + * When new and relevant functionality is enabled, we should be + * calling vfs_set_feature() to inform callers that pieces of + * functionality are available, per PSARC 2007/227, e.g. + * + * VFSFT_XVATTR Supports xvattr for attrs + * VFSFT_CASEINSENSITIVE Supports case-insensitive + * VFSFT_NOCASESENSITIVE NOT case-sensitive + * VFSFT_DIRENTFLAGS Supports dirent flags + * VFSFT_ACLONCREATE Supports ACL on create + * VFSFT_ACEMASKONACCESS Can use ACEMASK for access + */ +/* ARGSUSED */ +static int +smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) +{ + struct vattr va; + smbnode_t *np; + vnode_t *vp; + u_int32_t rights, rightsrcvd; + u_int16_t fid, oldfid; + struct smb_cred scred; + smbmntinfo_t *smi; + cred_t *oldcr; + int attrcacheupdated = 0; + int tmperror; + int error = 0; + + vp = *vpp; + np = VTOSMB(vp); + smi = VTOSMI(vp); + + if (curproc->p_zone != smi->smi_zone) + return (EIO); + + if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */ + SMBVDEBUG("open eacces vtype=%d\n", vp->v_type); + return (EACCES); + } + + /* + * Get exclusive access to n_fid and related stuff. + * No returns after this until out. + */ + if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp))) + return (EINTR); + smb_credinit(&scred, curproc, cr); + + /* + * Directory open is easy. + */ + if (vp->v_type == VDIR) { + np->n_dirrefs++; + goto have_fid; + } + + /* + * If caller specified O_TRUNC/FTRUNC, then be sure to set + * FWRITE (to drive successful setattr(size=0) after open) + */ + if (flag & FTRUNC) + flag |= FWRITE; + + /* + * If we already have it open, check to see if current rights + * are sufficient for this open. + */ + if (np->n_fidrefs) { + int upgrade = 0; + + /* BEGIN CSTYLED */ + if ((flag & FWRITE) && + !(np->n_rights & (SA_RIGHT_FILE_WRITE_DATA | + GENERIC_RIGHT_ALL_ACCESS | + GENERIC_RIGHT_WRITE_ACCESS))) + upgrade = 1; + if ((flag & FREAD) && + !(np->n_rights & (SA_RIGHT_FILE_READ_DATA | + GENERIC_RIGHT_ALL_ACCESS | + GENERIC_RIGHT_READ_ACCESS))) + upgrade = 1; + /* END CSTYLED */ + if (!upgrade) { + /* + * the existing open is good enough + */ + np->n_fidrefs++; + goto have_fid; + } + } + rights = np->n_fidrefs ? np->n_rights : 0; + + /* + * we always ask for READ_CONTROL so we can always get the + * owner/group IDs to satisfy a stat. + * XXX: verify that works with "drop boxes" + */ + rights |= STD_RIGHT_READ_CONTROL_ACCESS; + if ((flag & FREAD)) + rights |= SA_RIGHT_FILE_READ_DATA; + if ((flag & FWRITE)) + rights |= SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_WRITE_DATA; + + /* XXX: open gets the current size, but we don't use it. */ + error = smbfs_smb_open(np, rights, &scred, &attrcacheupdated, &fid, + NULL, 0, 0, NULL, &rightsrcvd); + if (error) + goto out; + + /* + * We have a new FID and access rights. + */ + oldfid = np->n_fid; + np->n_fid = fid; + np->n_rights = rightsrcvd; + np->n_fidrefs++; + if (np->n_fidrefs > 1) { + /* + * We already had it open (presumably because + * it was open with insufficient rights.) + * Close old wire-open. + */ + tmperror = smbfs_smb_close(smi->smi_share, + oldfid, &np->n_mtime, &scred); + if (tmperror) + SMBVDEBUG("error %d closing %s\n", + tmperror, np->n_rpath); + } + + /* + * This thread did the open. + * Save our credentials too. + */ + mutex_enter(&np->r_statelock); + oldcr = np->r_cred; + np->r_cred = cr; + crhold(cr); + if (oldcr) + crfree(oldcr); + mutex_exit(&np->r_statelock); + +have_fid: + /* Get attributes (maybe). */ + + + /* Darwin (derived) code. */ + + va.va_mask = AT_MTIME; + if (np->n_flag & NMODIFIED) + smbfs_attr_cacheremove(np); + + /* + * Try to get attributes, but don't bail on error. + * We already hold r_lkserlock/reader so note: + * this call will recursively take r_lkserlock. + */ + tmperror = smbfsgetattr(vp, &va, cr); + if (tmperror) + SMBERROR("getattr failed, error=%d", tmperror); + else + np->n_mtime.tv_sec = va.va_mtime.tv_sec; + +out: + smb_credrele(&scred); + smbfs_rw_exit(&np->r_lkserlock); + return (error); +} + +/*ARGSUSED*/ +static int +smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr, + caller_context_t *ct) +{ + smbnode_t *np; + int error = 0; + struct smb_cred scred; + + np = VTOSMB(vp); + + /* + * Don't "bail out" for VFS_UNMOUNTED here, + * as we want to do cleanup, etc. + */ + + /* + * zone_enter(2) prevents processes from changing zones with SMBFS files + * open; if we happen to get here from the wrong zone we can't do + * anything over the wire. + */ + if (VTOSMI(vp)->smi_zone != curproc->p_zone) { + /* + * We could attempt to clean up locks, except we're sure + * that the current process didn't acquire any locks on + * the file: any attempt to lock a file belong to another zone + * will fail, and one can't lock an SMBFS file and then change + * zones, as that fails too. + * + * Returning an error here is the sane thing to do. A + * subsequent call to VN_RELE() which translates to a + * smbfs_inactive() will clean up state: if the zone of the + * vnode's origin is still alive and kicking, an async worker + * thread will handle the request (from the correct zone), and + * everything (minus the final smbfs_getattr_otw() call) should + * be OK. If the zone is going away smbfs_async_inactive() will + * throw away cached pages inline. + */ + return (EIO); + } + + /* + * If we are using local locking for this filesystem, then + * release all of the SYSV style record locks. Otherwise, + * we are doing network locking and we need to release all + * of the network locks. All of the locks held by this + * process on this file are released no matter what the + * incoming reference count is. + */ + if (VTOSMI(vp)->smi_flags & SMI_LLOCK) { + cleanlocks(vp, ttoproc(curthread)->p_pid, 0); + cleanshares(vp, ttoproc(curthread)->p_pid); + } + + if (count > 1) + return (0); + /* + * OK, do "last close" stuff. + */ + + + /* + * Do the CIFS close. + * Darwin code + */ + + /* + * Exclusive lock for modifying n_fid stuff. + * Don't want this one ever interruptible. + */ + (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0); + smb_credinit(&scred, curproc, cr); + + error = 0; + if (vp->v_type == VDIR) { + struct smbfs_fctx *fctx; + ASSERT(np->n_dirrefs > 0); + if (--np->n_dirrefs) + goto out; + if ((fctx = np->n_dirseq) != NULL) { + np->n_dirseq = NULL; + error = smbfs_smb_findclose(fctx, &scred); + } + } else { + uint16_t ofid; + ASSERT(np->n_fidrefs > 0); + if (--np->n_fidrefs) + goto out; + if ((ofid = np->n_fid) != SMB_FID_UNUSED) { + np->n_fid = SMB_FID_UNUSED; + error = smbfs_smb_close(np->n_mount->smi_share, + ofid, NULL, &scred); + } + } + if (error) { + SMBERROR("error %d closing %s\n", + error, np->n_rpath); + } + + if (np->n_flag & NATTRCHANGED) + smbfs_attr_cacheremove(np); + +out: + smb_credrele(&scred); + smbfs_rw_exit(&np->r_lkserlock); + + /* don't return any errors */ + return (0); +} + +/* ARGSUSED */ +static int +smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, + caller_context_t *ct) +{ + int error; + struct vattr va; + smbmntinfo_t *smi; + smbnode_t *np; + /* u_offset_t off; */ + /* offset_t diff; */ + + np = VTOSMB(vp); + smi = VTOSMI(vp); + + if (curproc->p_zone != smi->smi_zone) + return (EIO); + + if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER)); + + if (vp->v_type != VREG) + return (EISDIR); + + if (uiop->uio_resid == 0) + return (0); + + /* + * Like NFS3, just check for 63-bit overflow. + * Our SMB layer takes care to return EFBIG + * when it has to fallback to a 32-bit call. + */ + if (uiop->uio_loffset < 0 || + uiop->uio_loffset + uiop->uio_resid < 0) + return (EINVAL); + + /* Shared lock for n_fid use in smbfs_readvnode */ + if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) + return (EINTR); + + /* get vnode attributes from server */ + va.va_mask = AT_SIZE | AT_MTIME; + if (error = smbfsgetattr(vp, &va, cr)) + goto out; + + /* should probably update mtime with mtime from server here */ + + /* + * Darwin had a loop here that handled paging stuff. + * Solaris does paging differently, so no loop needed. + */ + error = smbfs_readvnode(vp, uiop, cr, &va); + +out: + smbfs_rw_exit(&np->r_lkserlock); + return (error); + +} + + +/* ARGSUSED */ +static int +smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, + caller_context_t *ct) +{ + int error; + smbmntinfo_t *smi; + smbnode_t *np; + int timo = SMBWRTTIMO; + + np = VTOSMB(vp); + smi = VTOSMI(vp); + + if (curproc->p_zone != smi->smi_zone) + return (EIO); + + if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER)); + + if (vp->v_type != VREG) + return (EISDIR); + + if (uiop->uio_resid == 0) + return (0); + + /* Shared lock for n_fid use in smbfs_writevnode */ + if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) + return (EINTR); + + + /* + * Darwin had a loop here that handled paging stuff. + * Solaris does paging differently, so no loop needed. + */ + error = smbfs_writevnode(vp, uiop, cr, ioflag, timo); + + smbfs_rw_exit(&np->r_lkserlock); + return (error); + +} + + +/* + * Return either cached or remote attributes. If get remote attr + * use them to check and invalidate caches, then cache the new attributes. + * + * XXX + * This op should eventually support PSARC 2007/315, Extensible Attribute + * Interfaces, for richer metadata. + */ +/* ARGSUSED */ +static int +smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, + caller_context_t *ct) +{ + smbnode_t *np; + smbmntinfo_t *smi; + + smi = VTOSMI(vp); + + if (curproc->p_zone != smi->smi_zone) + return (EIO); + + if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + /* + * If it has been specified that the return value will + * just be used as a hint, and we are only being asked + * for size, fsid or rdevid, then return the client's + * notion of these values without checking to make sure + * that the attribute cache is up to date. + * The whole point is to avoid an over the wire GETATTR + * call. + */ + np = VTOSMB(vp); + if (flags & ATTR_HINT) { + if (vap->va_mask == + (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) { + mutex_enter(&np->r_statelock); + if (vap->va_mask | AT_SIZE) + vap->va_size = np->r_size; + if (vap->va_mask | AT_FSID) + vap->va_fsid = np->r_attr.va_fsid; + if (vap->va_mask | AT_RDEV) + vap->va_rdev = np->r_attr.va_rdev; + mutex_exit(&np->r_statelock); + return (0); + } + } + + + return (smbfsgetattr(vp, vap, cr)); +} + +/* + * Mostly from Darwin smbfs_getattr() + */ +int +smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr) +{ + int error; + smbnode_t *np; + struct smb_cred scred; + struct smbfattr fattr; + + ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone); + + np = VTOSMB(vp); + + /* + * If we've got cached attributes, we're done, otherwise go + * to the server to get attributes, which will update the cache + * in the process. + * + * This section from Darwin smbfs_getattr, + * but then modified a lot. + */ + error = smbfs_attr_cachelookup(vp, vap); + if (error != ENOENT) + return (error); + + /* Shared lock for (possible) n_fid use. */ + if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) + return (EINTR); + smb_credinit(&scred, curproc, cr); + + error = smbfs_smb_getfattr(np, &fattr, &scred); + + smb_credrele(&scred); + smbfs_rw_exit(&np->r_lkserlock); + + if (!error) { + smbfs_attr_cacheenter(vp, &fattr); + error = smbfs_attr_cachelookup(vp, vap); + } + return (error); +} + +/* + * XXX + * This op should eventually support PSARC 2007/315, Extensible Attribute + * Interfaces, for richer metadata. + */ +/*ARGSUSED4*/ +static int +smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, + caller_context_t *ct) +{ + int error; + uint_t mask; + struct vattr oldva; + smbmntinfo_t *smi; + + smi = VTOSMI(vp); + + if (curproc->p_zone != smi->smi_zone) + return (EIO); + + if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + mask = vap->va_mask; + if (mask & AT_NOSET) + return (EINVAL); + + oldva.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; + error = smbfsgetattr(vp, &oldva, cr); + if (error) + return (error); + + error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags, + smbfs_accessx, vp); + if (error) + return (error); + + return (smbfssetattr(vp, vap, flags, cr)); +} + +/* + * Mostly from Darwin smbfs_setattr() + * but then modified a lot. + */ +/* ARGSUSED */ +static int +smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) +{ + int error = 0; + smbnode_t *np = VTOSMB(vp); + smbmntinfo_t *smi = VTOSMI(vp); + uint_t mask = vap->va_mask; + struct timespec *mtime, *atime; + struct smb_cred scred; + int cerror, modified = 0; + unsigned short fid; + int have_fid = 0; + uint32_t rights = 0; + + ASSERT(curproc->p_zone == smi->smi_zone); + + /* + * If our caller is trying to set multiple attributes, they + * can make no assumption about what order they are done in. + * Here we try to do them in order of decreasing likelihood + * of failure, just to minimize the chance we'll wind up + * with a partially complete request. + */ + + /* Shared lock for (possible) n_fid use. */ + if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) + return (EINTR); + smb_credinit(&scred, curproc, cr); + + /* + * Will we need an open handle for this setattr? + * If so, what rights will we need? + */ + if (mask & (AT_ATIME | AT_MTIME)) { + rights |= + SA_RIGHT_FILE_WRITE_ATTRIBUTES | + GENERIC_RIGHT_ALL_ACCESS | + GENERIC_RIGHT_WRITE_ACCESS; + } + if (mask & AT_SIZE) { + rights |= + SA_RIGHT_FILE_WRITE_DATA | + SA_RIGHT_FILE_APPEND_DATA; + /* + * Only SIZE requires a handle. + * XXX May be more reliable to just + * always get the file handle here. + */ + error = smbfs_smb_tmpopen(np, rights, &scred, &fid); + if (error) { + SMBVDEBUG("error %d opening %s\n", + error, np->n_rpath); + goto out; + } + have_fid = 1; + } + + + /* + * If the server supports the UNIX extensions, right here is where + * we'd support changes to uid, gid, mode, and possibly va_flags. + * For now we claim to have made any such changes. + */ + + if (mask & AT_SIZE) { + /* + * If the new file size is less than what the client sees as + * the file size, then just change the size and invalidate + * the pages. + * I am commenting this code at present because the function + * smbfs_putapage() is not yet implemented. + */ + + /* + * Set the file size to vap->va_size. + */ + ASSERT(have_fid); + error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred); + if (error) { + SMBVDEBUG("setsize error %d file %s\n", + error, np->n_rpath); + } else { + /* + * Darwin had code here to zero-extend. + * Tests indicate the server will zero-fill, + * so looks like we don't need to do this. + * Good thing, as this could take forever. + */ + mutex_enter(&np->r_statelock); + np->r_size = vap->va_size; + mutex_exit(&np->r_statelock); + modified = 1; + } + } + + /* + * XXX: When Solaris has create_time, set that too. + * Note: create_time is different from ctime. + */ + mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0); + atime = ((mask & AT_ATIME) ? &vap->va_atime : 0); + + if (mtime || atime) { + /* + * If file is opened with write-attributes capability, + * we use handle-based calls. If not, we use path-based ones. + */ + if (have_fid) { + error = smbfs_smb_setfattr(np, fid, + np->n_dosattr, mtime, atime, &scred); + } else { + error = smbfs_smb_setpattr(np, + np->n_dosattr, mtime, atime, &scred); + } + if (error) { + SMBVDEBUG("set times error %d file %s\n", + error, np->n_rpath); + } else { + /* XXX: set np->n_mtime, etc? */ + modified = 1; + } + } + +out: + if (modified) { + /* + * Invalidate attribute cache in case if server doesn't set + * required attributes. + */ + smbfs_attr_cacheremove(np); + /* + * XXX Darwin called _getattr here to + * update the mtime. Should we? + */ + } + + if (have_fid) { + cerror = smbfs_smb_tmpclose(np, fid, &scred); + if (cerror) + SMBERROR("error %d closing %s\n", + cerror, np->n_rpath); + } + + smb_credrele(&scred); + smbfs_rw_exit(&np->r_lkserlock); + + return (error); +} + +/* + * smbfs_access_rwx() + * Common function for smbfs_access, etc. + * + * The security model implemented by the FS is unusual + * due to our "single user mounts" restriction. + * + * All access under a given mount point uses the CIFS + * credentials established by the owner of the mount. + * The Unix uid/gid/mode information is not (easily) + * provided by CIFS, and is instead fabricated using + * settings held in the mount structure. + * + * Most access checking is handled by the CIFS server, + * but we need sufficient Unix access checks here to + * prevent other local Unix users from having access + * to objects under this mount that the uid/gid/mode + * settings in the mount would not allow. + * + * With this model, there is a case where we need the + * ability to do an access check before we have the + * vnode for an object. This function takes advantage + * of the fact that the uid/gid/mode is per mount, and + * avoids the need for a vnode. + * + * We still (sort of) need a vnode when we call + * secpolicy_vnode_access, but that only uses + * the vtype field, so we can use a pair of fake + * vnodes that have only v_type filled in. + * + * XXX: Later, add a new secpolicy_vtype_access() + * that takes the vtype instead of a vnode, and + * get rid of the tmpl_vxxx fake vnodes below. + */ +static int +smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr) +{ + /* See the secpolicy call below. */ + static const vnode_t tmpl_vdir = { .v_type = VDIR }; + static const vnode_t tmpl_vreg = { .v_type = VREG }; + vattr_t va; + vnode_t *tvp; + struct smbmntinfo *smi = VFTOSMI(vfsp); + int shift = 0; + + /* + * Build our (fabricated) vnode attributes. + * XXX: Could make these templates in the + * per-mount struct and use them here. + */ + bzero(&va, sizeof (va)); + va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; + va.va_type = vtype; + va.va_mode = (vtype == VDIR) ? + smi->smi_args.dir_mode : + smi->smi_args.file_mode; + va.va_uid = smi->smi_args.uid; + va.va_gid = smi->smi_args.gid; + + /* + * Disallow write attempts on read-only file systems, + * unless the file is a device or fifo node. Note: + * Inline vn_is_readonly and IS_DEVVP here because + * we may not have a vnode ptr. Original expr. was: + * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp)) + */ + if ((mode & VWRITE) && + (vfsp->vfs_flag & VFS_RDONLY) && + !(vtype == VCHR || vtype == VBLK || vtype == VFIFO)) + return (EROFS); + + /* + * Disallow attempts to access mandatory lock files. + * Similarly, expand MANDLOCK here. + * XXX: not sure we need this. + */ + if ((mode & (VWRITE | VREAD | VEXEC)) && + va.va_type == VREG && MANDMODE(va.va_mode)) + return (EACCES); + + /* + * Access check is based on only + * one of owner, group, public. + * If not owner, then check group. + * If not a member of the group, + * then check public access. + */ + if (crgetuid(cr) != va.va_uid) { + shift += 3; + if (!groupmember(va.va_gid, cr)) + shift += 3; + } + mode &= ~(va.va_mode << shift); + if (mode == 0) + return (0); + + /* + * We need a vnode for secpolicy_vnode_access, + * but the only thing it looks at is v_type, + * so pass one of the templates above. + */ + tvp = (va.va_type == VDIR) ? + (vnode_t *)&tmpl_vdir : + (vnode_t *)&tmpl_vreg; + return (secpolicy_vnode_access(cr, tvp, va.va_uid, mode)); +} + +/* + * See smbfs_setattr + */ +static int +smbfs_accessx(void *arg, int mode, cred_t *cr) +{ + vnode_t *vp = arg; + /* + * Note: The caller has checked the current zone, + * the SMI_DEAD and VFS_UNMOUNTED flags, etc. + */ + return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr)); +} + +/* + * XXX + * This op should support PSARC 2007/403, Modified Access Checks for CIFS + */ +/* ARGSUSED */ +static int +smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct) +{ + vfs_t *vfsp; + smbmntinfo_t *smi; + + vfsp = vp->v_vfsp; + smi = VFTOSMI(vfsp); + + if (curproc->p_zone != smi->smi_zone) + return (EIO); + + if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr)); +} + + +/* + * Flush local dirty pages to stable storage on the server. + * + * If FNODSYNC is specified, then there is nothing to do because + * metadata changes are not cached on the client before being + * sent to the server. + * + * Currently, this is a no-op since we don't cache data, either. + */ +/* ARGSUSED */ +static int +smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) +{ + int error = 0; + smbmntinfo_t *smi; + + smi = VTOSMI(vp); + + if (curproc->p_zone != smi->smi_zone) + return (EIO); + + if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + if ((syncflag & FNODSYNC) || IS_SWAPVP(vp)) + return (0); + + return (error); +} + +/* + * Last reference to vnode went away. + */ +/* ARGSUSED */ +static void +smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) +{ + smbnode_t *np; + + /* + * Don't "bail out" for VFS_UNMOUNTED here, + * as we want to do cleanup, etc. + * See also pcfs_inactive + */ + + np = VTOSMB(vp); + + /* + * If this is coming from the wrong zone, we let someone in the right + * zone take care of it asynchronously. We can get here due to + * VN_RELE() being called from pageout() or fsflush(). This call may + * potentially turn into an expensive no-op if, for instance, v_count + * gets incremented in the meantime, but it's still correct. + */ + + /* + * Some paranoia from the Darwin code: + * Make sure the FID was closed. + * If we see this, it's a bug! + * + * No rw_enter here, as this should be the + * last ref, and we're just looking... + */ + if (np->n_fidrefs > 0) { + SMBVDEBUG("opencount %d fid %d file %s\n", + np->n_fidrefs, np->n_fid, np->n_rpath); + } + if (np->n_dirrefs > 0) { + uint_t fid = (np->n_dirseq) ? + np->n_dirseq->f_Sid : 0; + SMBVDEBUG("opencount %d fid %d dir %s\n", + np->n_dirrefs, fid, np->n_rpath); + } + + smb_addfree(np); +} + +/* + * Remote file system operations having to do with directory manipulation. + */ +/* ARGSUSED */ +static int +smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, + int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, + int *direntflags, pathname_t *realpnp) +{ + int error; + smbnode_t *dnp; + smbmntinfo_t *smi; + + smi = VTOSMI(dvp); + + if (curproc->p_zone != smi->smi_zone) + return (EPERM); + + if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + dnp = VTOSMB(dvp); + if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp))) { + error = EINTR; + goto out; + } + + error = smbfslookup(dvp, nm, vpp, cr, 1, ct); + + smbfs_rw_exit(&dnp->r_rwlock); + +out: + return (error); +} + +/* ARGSUSED */ +static int +smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int dnlc, + caller_context_t *ct) +{ + int error; + int supplen; /* supported length */ + vnode_t *vp; + smbnode_t *dnp; + smbmntinfo_t *smi; + /* struct smb_vc *vcp; */ + const char *name = (const char *)nm; + int nmlen = strlen(nm); + int rplen; + struct smb_cred scred; + struct smbfattr fa; + + smi = VTOSMI(dvp); + dnp = VTOSMB(dvp); + + ASSERT(curproc->p_zone == smi->smi_zone); + +#ifdef NOT_YET + vcp = SSTOVC(smi->smi_share); + + /* XXX: Should compute this once and store it in smbmntinfo_t */ + supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12; +#else + supplen = 255; +#endif + + /* + * RWlock must be held, either reader or writer. + * XXX: Can we check without looking directly + * inside the struct smbfs_rwlock_t? + */ + ASSERT(dnp->r_rwlock.count != 0); + + /* + * If lookup is for "", just return dvp. Don't need + * to send it over the wire, look it up in the dnlc, + * or perform any access checks. + */ + if (nmlen == 0) { + VN_HOLD(dvp); + *vpp = dvp; + return (0); + } + + /* if the name is longer that what is supported, return an error */ + if (nmlen > supplen) + return (ENAMETOOLONG); + + /* + * Avoid surprises with characters that are + * illegal in Windows file names. + * Todo: CATIA mappings XXX + */ + if (strpbrk(nm, illegal_chars)) + return (EINVAL); + + /* if the dvp is not a directory, return an error */ + if (dvp->v_type != VDIR) + return (ENOTDIR); + + /* Need search permission in the directory. */ + error = smbfs_access(dvp, VEXEC, 0, cr, ct); + if (error) + return (error); + + /* + * If lookup is for ".", just return dvp. Don't need + * to send it over the wire or look it up in the dnlc, + * just need to check access (done above). + */ + if (nmlen == 1 && name[0] == '.') { + VN_HOLD(dvp); + *vpp = dvp; + return (0); + } + +#ifdef NOT_YET + if (dnlc) { + /* + * NOTE: search the dnlc here + */ + } +#endif + + /* + * Handle lookup of ".." which is quite tricky, + * because the protocol gives us little help. + * + * We keep full pathnames (as seen on the server) + * so we can just trim off the last component to + * get the full pathname of the parent. Note: + * We don't actually copy and modify, but just + * compute the trimmed length and pass that with + * the current dir path (not null terminated). + * + * We don't go over-the-wire to get attributes + * for ".." because we know it's a directory, + * and we can just leave the rest "stale" + * until someone does a getattr. + */ + if (nmlen == 2 && name[0] == '.' && name[1] == '.') { + if (dvp->v_flag & VROOT) { + /* + * Already at the root. This can happen + * with directory listings at the root, + * which lookup "." and ".." to get the + * inode numbers. Let ".." be the same + * as "." in the FS root. + */ + VN_HOLD(dvp); + *vpp = dvp; + return (0); + } + + /* + * Find the parent path length. + */ + rplen = dnp->n_rplen; + ASSERT(rplen > 0); + while (--rplen >= 0) { + if (dnp->n_rpath[rplen] == '\\') + break; + } + if (rplen == 0) { + /* Found our way to the root. */ + vp = SMBTOV(smi->smi_root); + VN_HOLD(vp); + *vpp = vp; + return (0); + } + vp = smbfs_make_node(dvp->v_vfsp, + dnp->n_rpath, rplen, + NULL, 0, NULL); + if (vp == NULL) { + return (ENOENT); + } + vp->v_type = VDIR; + + /* Success! */ + *vpp = vp; + return (0); + } + + /* + * Normal lookup of a child node. + * Note we handled "." and ".." above. + * + * First, go over-the-wire to get the + * node type (and attributes). + */ + smb_credinit(&scred, curproc, cr); + /* Note: this can allocate a new "name" */ + error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred); + smb_credrele(&scred); + if (error) + goto out; + + /* + * Find or create the node. + */ + error = smbfs_nget(dvp, name, nmlen, &fa, &vp); + if (error) + goto out; + + /* Success! */ + *vpp = vp; + +out: + /* smbfs_smb_lookup may have allocated name. */ + if (name != nm) + smbfs_name_free(name, nmlen); + + return (error); +} + +/* + * XXX + * vsecattr_t is new to build 77, and we need to eventually support + * it in order to create an ACL when an object is created. + * + * This op should support the new FIGNORECASE flag for case-insensitive + * lookups, per PSARC 2007/244. + */ +/* ARGSUSED */ +static int +smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, + int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct, + vsecattr_t *vsecp) +{ + int error; + int cerror; + vfs_t *vfsp; + vnode_t *vp; +#ifdef NOT_YET + smbnode_t *np; +#endif + smbnode_t *dnp; + smbmntinfo_t *smi; + struct vattr vattr; + struct smbfattr fattr; + struct smb_cred scred; + const char *name = (const char *)nm; + int nmlen = strlen(nm); + uint32_t disp; + uint16_t fid; + + vfsp = dvp->v_vfsp; + smi = VFTOSMI(vfsp); + dnp = VTOSMB(dvp); + vp = NULL; + + if (curproc->p_zone != smi->smi_zone) + return (EPERM); + + if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + /* + * Note: this may break mknod(2) calls to create a directory, + * but that's obscure use. Some other filesystems do this. + * XXX: Later, redirect VDIR type here to _mkdir. + */ + if (va->va_type != VREG) + return (EINVAL); + + /* + * If the pathname is "", just use dvp, no checks. + * Do this outside of the rwlock (like zfs). + */ + if (nmlen == 0) { + VN_HOLD(dvp); + *vpp = dvp; + return (0); + } + + /* Don't allow "." or ".." through here. */ + if ((nmlen == 1 && name[0] == '.') || + (nmlen == 2 && name[0] == '.' && name[1] == '.')) + return (EISDIR); + + /* + * We make a copy of the attributes because the caller does not + * expect us to change what va points to. + */ + vattr = *va; + + if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) + return (EINTR); + smb_credinit(&scred, curproc, cr); + + /* + * XXX: Do we need r_lkserlock too? + * No use of any shared fid or fctx... + */ + + /* + * NFS needs to go over the wire, just to be sure whether the + * file exists or not. Using the DNLC can be dangerous in + * this case when making a decision regarding existence. + * + * The SMB protocol does NOT really need to go OTW here + * thanks to the expressive NTCREATE disposition values. + * Unfortunately, to do Unix access checks correctly, + * we need to know if the object already exists. + * When the object does not exist, we need VWRITE on + * the directory. Note: smbfslookup() checks VEXEC. + */ + error = smbfslookup(dvp, nm, &vp, cr, 0, ct); + if (error == 0) { + /* + * file already exists + */ + if (exclusive == EXCL) { + error = EEXIST; + goto out; + } + /* + * Verify requested access. + */ + error = smbfs_access(vp, mode, 0, cr, ct); + if (error) + goto out; + + /* + * Truncate (if requested). + */ + if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) { + vattr.va_mask = AT_SIZE; + error = smbfssetattr(vp, &vattr, 0, cr); + if (error) + goto out; + } + /* Success! */ +#ifdef NOT_YET + vnevent_create(vp, ct); +#endif + *vpp = vp; + goto out; + } + + /* + * The file did not exist. Need VWRITE in the directory. + */ + error = smbfs_access(dvp, VWRITE, 0, cr, ct); + if (error) + goto out; + + /* + * Now things get tricky. We also need to check the + * requested open mode against the file we may create. + * See comments at smbfs_access_rwx + */ + error = smbfs_access_rwx(vfsp, VREG, mode, cr); + if (error) + goto out; + +#ifdef NOT_YET + /* remove the entry from the negative entry from the dnlc */ + dnlc_remove(dvp, name); +#endif + + /* + * Now the code derived from Darwin, + * but with greater use of NT_CREATE + * disposition options. Much changed. + * + * Create (or open) a new child node. + * Note we handled "." and ".." above. + */ + + if (exclusive == EXCL) + disp = NTCREATEX_DISP_CREATE; + else { + /* Truncate regular files if requested. */ + if ((va->va_type == VREG) && + (va->va_mask & AT_SIZE) && + (va->va_size == 0)) + disp = NTCREATEX_DISP_OVERWRITE_IF; + else + disp = NTCREATEX_DISP_OPEN_IF; + } + error = smbfs_smb_create(dnp, name, nmlen, &scred, &fid, disp, 0); + if (error) + goto out; + + /* + * XXX: Missing some code here to deal with + * the case where we opened an existing file, + * it's size is larger than 32-bits, and we're + * setting the size from a process that's not + * aware of large file offsets. i.e. + * from the NFS3 code: + */ +#if NOT_YET /* XXX */ + if ((vattr.va_mask & AT_SIZE) && + vp->v_type == VREG) { + np = VTOSMB(vp); + /* + * Check here for large file handled + * by LF-unaware process (as + * ufs_create() does) + */ + if (!(lfaware & FOFFMAX)) { + mutex_enter(&np->r_statelock); + if (np->r_size > MAXOFF32_T) + error = EOVERFLOW; + mutex_exit(&np->r_statelock); + } + if (!error) { + vattr.va_mask = AT_SIZE; + error = smbfssetattr(vp, + &vattr, 0, cr); + } + } +#endif /* XXX */ + /* + * Should use the fid to get/set the size + * while we have it opened here. See above. + */ + + cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred); + if (cerror) + SMBERROR("error %d closing %s\\%s\n", + cerror, dnp->n_rpath, name); + + /* + * In the open case, the name may differ a little + * from what we passed to create (case, etc.) + * so call lookup to get the (opened) name. + * + * XXX: Could avoid this extra lookup if the + * "createact" result from NT_CREATE says we + * created the object. + */ + error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred); + if (error) + goto out; + + /* update attr and directory cache */ + smbfs_attr_touchdir(dnp); + + error = smbfs_nget(dvp, name, nmlen, &fattr, &vp); + if (error) + goto out; + +#ifdef NOT_YET + dnlc_update(dvp, name, vp); + /* XXX invalidate pages if we truncated? */ +#endif + + /* Success! */ + *vpp = vp; + error = 0; + +out: + smb_credrele(&scred); + if (name != nm) + smbfs_name_free(name, nmlen); + smbfs_rw_exit(&dnp->r_rwlock); + return (error); +} + +/* + * XXX + * This op should support the new FIGNORECASE flag for case-insensitive + * lookups, per PSARC 2007/244. + */ +/* ARGSUSED */ +static int +smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, + int flags) +{ + int error; + vnode_t *vp; + smbnode_t *np; + smbnode_t *dnp; + struct smb_cred scred; + /* enum smbfsstat status; */ + smbmntinfo_t *smi; + + smi = VTOSMI(dvp); + + if (curproc->p_zone != smi->smi_zone) + return (EPERM); + + if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + dnp = VTOSMB(dvp); + if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) + return (EINTR); + + /* + * Verify access to the dirctory. + */ + error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct); + if (error) + goto out; + + /* + * NOTE: the darwin code gets the "vp" passed in so it looks + * like the "vp" has probably been "lookup"ed by the VFS layer. + * It looks like we will need to lookup the vp to check the + * caches and check if the object being deleted is a directory. + */ + error = smbfslookup(dvp, nm, &vp, cr, 0, ct); + if (error) + goto out; + + /* Never allow link/unlink directories on CIFS. */ + if (vp->v_type == VDIR) { + VN_RELE(vp); + error = EPERM; + goto out; + } + +#ifdef NOT_YET + /* + * First just remove the entry from the name cache, as it + * is most likely the only entry for this vp. + */ + dnlc_remove(dvp, nm); + + /* + * If the file has a v_count > 1 then there may be more than one + * entry in the name cache due multiple links or an open file, + * but we don't have the real reference count so flush all + * possible entries. + */ + if (vp->v_count > 1) + dnlc_purge_vp(vp); +#endif /* NOT_YET */ + + /* + * Now we have the real reference count on the vnode + */ + np = VTOSMB(vp); + mutex_enter(&np->r_statelock); + if (vp->v_count > 1) { + /* + * NFS does a rename on remove here. + * Probably not applicable for SMB. + * Like Darwin, just return EBUSY. + * + * XXX: Todo - Ask the server to set the + * set the delete-on-close flag. + */ + mutex_exit(&np->r_statelock); + error = EBUSY; + goto out; + } else { + mutex_exit(&np->r_statelock); + + smb_credinit(&scred, curproc, cr); + error = smbfs_smb_delete(np, &scred, NULL, 0, 0); + smb_credrele(&scred); + + } + + VN_RELE(vp); + +out: + smbfs_rw_exit(&dnp->r_rwlock); + + return (error); +} + + +/* + * XXX + * This op should support the new FIGNORECASE flag for case-insensitive + * lookups, per PSARC 2007/244. + */ +/* ARGSUSED */ +static int +smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, + caller_context_t *ct, int flags) +{ + /* vnode_t *realvp; */ + + if (curproc->p_zone != VTOSMI(odvp)->smi_zone || + curproc->p_zone != VTOSMI(ndvp)->smi_zone) + return (EPERM); + + if (VTOSMI(odvp)->smi_flags & SMI_DEAD || + VTOSMI(ndvp)->smi_flags & SMI_DEAD || + odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED || + ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct)); +} + +/* + * smbfsrename does the real work of renaming in SMBFS + */ +/* ARGSUSED */ +static int +smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, + caller_context_t *ct) +{ + int error; + int nvp_locked = 0; + vnode_t *nvp = NULL; + vnode_t *ovp = NULL; + smbnode_t *onp; + smbnode_t *odnp; + smbnode_t *ndnp; + struct smb_cred scred; + /* enum smbfsstat status; */ + + ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone); + + if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 || + strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0) + return (EINVAL); + + /* + * Check that everything is on the same filesystem. + * vn_rename checks the fsid's, but in case we don't + * fill those in correctly, check here too. + */ + if (odvp->v_vfsp != ndvp->v_vfsp) + return (EXDEV); + + odnp = VTOSMB(odvp); + ndnp = VTOSMB(ndvp); + + /* + * Avoid deadlock here on old vs new directory nodes + * by always taking the locks in order of address. + * The order is arbitrary, but must be consistent. + */ + if (odnp < ndnp) { + if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER, + SMBINTR(odvp))) + return (EINTR); + if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER, + SMBINTR(ndvp))) { + smbfs_rw_exit(&odnp->r_rwlock); + return (EINTR); + } + } else { + if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER, + SMBINTR(ndvp))) + return (EINTR); + if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER, + SMBINTR(odvp))) { + smbfs_rw_exit(&ndnp->r_rwlock); + return (EINTR); + } + } + /* + * No returns after this point (goto out) + */ + + /* + * Need write access on source and target. + * Server takes care of most checks. + */ + error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct); + if (error) + goto out; + if (odvp != ndvp) { + error = smbfs_access(ndvp, VWRITE, 0, cr, ct); + if (error) + goto out; + } + + /* + * Lookup the source name. Must already exist. + */ + error = smbfslookup(odvp, onm, &ovp, cr, 0, ct); + if (error) + goto out; + + /* + * Lookup the target file. If it exists, it needs to be + * checked to see whether it is a mount point and whether + * it is active (open). + */ + error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct); + if (!error) { + /* + * Target (nvp) already exists. Check that it + * has the same type as the source. The server + * will check this also, (and more reliably) but + * this lets us return the correct error codes. + */ + if (ovp->v_type == VDIR) { + if (nvp->v_type != VDIR) { + error = ENOTDIR; + goto out; + } + } else { + if (nvp->v_type == VDIR) { + error = EISDIR; + goto out; + } + } + + /* + * POSIX dictates that when the source and target + * entries refer to the same file object, rename + * must do nothing and exit without error. + */ + if (ovp == nvp) { + error = 0; + goto out; + } + + /* + * Also must ensure the target is not a mount point, + * and keep mount/umount away until we're done. + */ + if (vn_vfsrlock(nvp)) { + error = EBUSY; + goto out; + } + nvp_locked = 1; + if (vn_mountedvfs(nvp) != NULL) { + error = EBUSY; + goto out; + } + +#ifdef NOT_YET + /* + * Purge the name cache of all references to this vnode + * so that we can check the reference count to infer + * whether it is active or not. + */ + /* + * First just remove the entry from the name cache, as it + * is most likely the only entry for this vp. + */ + dnlc_remove(ndvp, nnm); + /* + * If the file has a v_count > 1 then there may be more + * than one entry in the name cache due multiple links + * or an open file, but we don't have the real reference + * count so flush all possible entries. + */ + if (nvp->v_count > 1) + dnlc_purge_vp(nvp); +#endif + + if (nvp->v_count > 1 && nvp->v_type != VDIR) { + /* + * The target file exists, is not the same as + * the source file, and is active. Other FS + * implementations unlink the target here. + * For SMB, we don't assume we can remove an + * open file. Return an error instead. + * Darwin returned an error here too. + */ + error = EEXIST; + goto out; + } + } /* nvp */ + +#ifdef NOT_YET + dnlc_remove(odvp, onm); + dnlc_remove(ndvp, nnm); +#endif + + onp = VTOSMB(ovp); + smb_credinit(&scred, curproc, cr); + error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred); + smb_credrele(&scred); + + +out: + if (nvp) { + if (nvp_locked) + vn_vfsunlock(nvp); + VN_RELE(nvp); + } + if (ovp) + VN_RELE(ovp); + + smbfs_rw_exit(&odnp->r_rwlock); + smbfs_rw_exit(&ndnp->r_rwlock); + + return (error); +} + +/* + * XXX + * vsecattr_t is new to build 77, and we need to eventually support + * it in order to create an ACL when an object is created. + * + * This op should support the new FIGNORECASE flag for case-insensitive + * lookups, per PSARC 2007/244. + */ +/* ARGSUSED */ +static int +smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, + cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp) +{ + vnode_t *vp; + struct smbnode *dnp = VTOSMB(dvp); + struct smbmntinfo *smi = VTOSMI(dvp); + struct smb_cred scred; + struct smbfattr fattr; + const char *name = (const char *) nm; + int nmlen = strlen(name); + int error, hiderr; + + if (curproc->p_zone != smi->smi_zone) + return (EPERM); + + if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + if ((nmlen == 1 && name[0] == '.') || + (nmlen == 2 && name[0] == '.' && name[1] == '.')) + return (EEXIST); + + if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) + return (EINTR); + smb_credinit(&scred, curproc, cr); + + /* + * XXX: Do we need r_lkserlock too? + * No use of any shared fid or fctx... + */ + + /* + * Require write access in the containing directory. + */ + error = smbfs_access(dvp, VWRITE, 0, cr, ct); + if (error) + goto out; + + error = smbfs_smb_mkdir(dnp, name, nmlen, &scred); + if (error) + goto out; + + error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred); + if (error) + goto out; + + smbfs_attr_touchdir(dnp); + + error = smbfs_nget(dvp, name, nmlen, &fattr, &vp); + if (error) + goto out; + +#ifdef NOT_YET + dnlc_update(dvp, name, vp); +#endif + + if (name[0] == '.') + if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred))) + SMBVDEBUG("hide failure %d\n", hiderr); + + /* Success! */ + *vpp = vp; + error = 0; +out: + smb_credrele(&scred); + smbfs_rw_exit(&dnp->r_rwlock); + + if (name != nm) + smbfs_name_free(name, nmlen); + + return (error); +} + +/* + * XXX + * This op should support the new FIGNORECASE flag for case-insensitive + * lookups, per PSARC 2007/244. + */ +/* ARGSUSED */ +static int +smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr, + caller_context_t *ct, int flags) +{ + vnode_t *vp = NULL; + int vp_locked = 0; + struct smbmntinfo *smi = VTOSMI(dvp); + struct smbnode *dnp = VTOSMB(dvp); + struct smbnode *np; + struct smb_cred scred; + int error; + + if (curproc->p_zone != smi->smi_zone) + return (EPERM); + + if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) + return (EINTR); + smb_credinit(&scred, curproc, cr); + + /* + * Require w/x access in the containing directory. + * Server handles all other access checks. + */ + error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct); + if (error) + goto out; + + /* + * First lookup the entry to be removed. + */ + error = smbfslookup(dvp, nm, &vp, cr, 0, ct); + if (error) + goto out; + np = VTOSMB(vp); + + /* + * Disallow rmdir of "." or current dir, or the FS root. + * Also make sure it's a directory, not a mount point, + * and lock to keep mount/umount away until we're done. + */ + if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) { + error = EINVAL; + goto out; + } + if (vp->v_type != VDIR) { + error = ENOTDIR; + goto out; + } + if (vn_vfsrlock(vp)) { + error = EBUSY; + goto out; + } + vp_locked = 1; + if (vn_mountedvfs(vp) != NULL) { + error = EBUSY; + goto out; + } + + error = smbfs_smb_rmdir(np, &scred); + if (error) + goto out; + + mutex_enter(&np->r_statelock); + dnp->n_flag |= NMODIFIED; + mutex_exit(&np->r_statelock); + smbfs_attr_touchdir(dnp); +#ifdef NOT_YET + dnlc_remove(dvp, nm); + dnlc_purge_vp(vp); +#endif + smb_rmhash(np); + +out: + if (vp) { + if (vp_locked) + vn_vfsunlock(vp); + VN_RELE(vp); + } + smb_credrele(&scred); + smbfs_rw_exit(&dnp->r_rwlock); + + return (error); +} + + +/* ARGSUSED */ +static int +smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp, + caller_context_t *ct, int flags) +{ + struct smbnode *np = VTOSMB(vp); + int error = 0; + smbmntinfo_t *smi; + + smi = VTOSMI(vp); + + if (curproc->p_zone != smi->smi_zone) + return (EIO); + + if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + /* + * Require read access in the directory. + */ + error = smbfs_access(vp, VREAD, 0, cr, ct); + if (error) + return (error); + + ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER)); + + /* + * XXX: Todo readdir cache here + * Note: NFS code is just below this. + * + * I am serializing the entire readdir opreation + * now since we have not yet implemented readdir + * cache. This fix needs to be revisited once + * we implement readdir cache. + */ + if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp))) + return (EINTR); + + error = smbfs_readvdir(vp, uiop, cr, eofp, ct); + + smbfs_rw_exit(&np->r_lkserlock); + + return (error); +} + +/* ARGSUSED */ +static int +smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, + caller_context_t *ct) +{ + size_t dbufsiz; + struct dirent64 *dp; + struct smb_cred scred; + vnode_t *newvp; + struct smbnode *np = VTOSMB(vp); + int nmlen, reclen, error = 0; + long offset, limit; + struct smbfs_fctx *ctx; + + ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone); + + /* Make sure we serialize for n_dirseq use. */ + ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER)); + + /* Min size is DIRENT64_RECLEN(256) rounded up. */ + if (uio->uio_resid < 512 || uio->uio_offset < 0) + return (EINVAL); + + /* + * This dnlc_purge_vp ensures that name cache for this dir will be + * current - it'll only have the items for which the smbfs_nget + * MAKEENTRY happened. + */ +#ifdef NOT_YET + if (smbfs_fastlookup) + dnlc_purge_vp(vp); +#endif + SMBVDEBUG("dirname='%s'\n", np->n_rpath); + smb_credinit(&scred, curproc, cr); + dbufsiz = DIRENT64_RECLEN(MAXNAMELEN); + dp = kmem_alloc(dbufsiz, KM_SLEEP); + + offset = uio->uio_offset; /* NB: "cookie" */ + limit = uio->uio_resid / DIRENT64_RECLEN(1); + SMBVDEBUG("offset=0x%ld, limit=0x%ld\n", offset, limit); + + if (offset == 0) { + /* Don't know EOF until findclose */ + np->n_direof = -1; + } else if (offset == np->n_direof) { + /* Arrived at end of directory. */ + goto out; + } + + /* + * Generate the "." and ".." entries here so we can + * (1) make sure they appear (but only once), and + * (2) deal with getting their I numbers which the + * findnext below does only for normal names. + */ + while (limit && offset < 2) { + limit--; + reclen = DIRENT64_RECLEN(offset + 1); + bzero(dp, reclen); + /*LINTED*/ + dp->d_reclen = reclen; + /* Tricky: offset 0 is ".", offset 1 is ".." */ + dp->d_name[0] = '.'; + dp->d_name[1] = '.'; + dp->d_name[offset + 1] = '\0'; + /* + * Want the real I-numbers for the "." and ".." + * entries. For these two names, we know that + * smbfslookup can do this all locally. + */ + error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct); + if (error) { + dp->d_ino = np->n_ino + offset; /* fiction */ + } else { + dp->d_ino = VTOSMB(newvp)->n_ino; + VN_RELE(newvp); + } + dp->d_off = offset + 1; /* see d_off below */ + error = uiomove(dp, dp->d_reclen, UIO_READ, uio); + if (error) + goto out; + uio->uio_offset = ++offset; + } + if (limit == 0) + goto out; + if (offset != np->n_dirofs || np->n_dirseq == NULL) { + SMBVDEBUG("Reopening search %ld:%ld\n", offset, np->n_dirofs); + if (np->n_dirseq) { + (void) smbfs_smb_findclose(np->n_dirseq, &scred); + np->n_dirseq = NULL; + } + np->n_dirofs = 2; + error = smbfs_smb_findopen(np, "*", 1, + SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, + &scred, &ctx); + if (error) { + SMBVDEBUG("can not open search, error = %d", error); + goto out; + } + np->n_dirseq = ctx; + } else + ctx = np->n_dirseq; + while (np->n_dirofs < offset) { + if (smbfs_smb_findnext(ctx, offset - np->n_dirofs++, + &scred) != 0) { + (void) smbfs_smb_findclose(np->n_dirseq, &scred); + np->n_dirseq = NULL; + np->n_direof = np->n_dirofs; + np->n_dirofs = 0; + *eofp = 1; + error = 0; + goto out; + } + } + error = 0; + for (; limit; limit--) { + error = smbfs_smb_findnext(ctx, limit, &scred); + if (error) { + if (error == EBADRPC) + error = ENOENT; + (void) smbfs_smb_findclose(np->n_dirseq, &scred); + np->n_dirseq = NULL; + np->n_direof = np->n_dirofs; + np->n_dirofs = 0; + *eofp = 1; + error = 0; + break; + } + np->n_dirofs++; + /* Sanity check the name length. */ + nmlen = ctx->f_nmlen; + if (nmlen > (MAXNAMELEN - 1)) { + nmlen = MAXNAMELEN - 1; + SMBVDEBUG("Truncating name: %s\n", ctx->f_name); + } + reclen = DIRENT64_RECLEN(nmlen); + if (uio->uio_resid < reclen) + break; + bzero(dp, reclen); + /*LINTED*/ + dp->d_reclen = reclen; + dp->d_ino = ctx->f_attr.fa_ino; + /* + * Note: d_off is the offset that a user-level program + * should seek to for reading the _next_ directory entry. + * See libc: readdir, telldir, seekdir + */ + dp->d_off = offset + 1; + bcopy(ctx->f_name, dp->d_name, nmlen); + dp->d_name[nmlen] = '\0'; +#ifdef NOT_YET + if (smbfs_fastlookup) { + if (smbfs_nget(vp, ctx->f_name, + ctx->f_nmlen, &ctx->f_attr, &newvp) == 0) + VN_RELE(newvp); + } +#endif /* NOT_YET */ + error = uiomove(dp, dp->d_reclen, UIO_READ, uio); + if (error) + break; + uio->uio_offset = ++offset; + } + if (error == ENOENT) + error = 0; +out: + kmem_free(dp, dbufsiz); + smb_credrele(&scred); + return (error); +} + + +/* + * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK + * are optional functions that are called by: + * getdents, before/after VOP_READDIR + * pread, before/after ... VOP_READ + * pwrite, before/after ... VOP_WRITE + * (other places) + * + * Careful here: None of the above check for any + * error returns from VOP_RWLOCK / VOP_RWUNLOCK! + * In fact, the return value from _rwlock is NOT + * an error code, but V_WRITELOCK_TRUE / _FALSE. + * + * Therefore, it's up to _this_ code to make sure + * the lock state remains balanced, which means + * we can't "bail out" on interrupts, etc. + */ + +/* ARGSUSED2 */ +static int +smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp) +{ + smbnode_t *np = VTOSMB(vp); + + if (!write_lock) { + (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE); + return (V_WRITELOCK_FALSE); + } + + + (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE); + return (V_WRITELOCK_TRUE); +} + +/* ARGSUSED */ +static void +smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp) +{ + smbnode_t *np = VTOSMB(vp); + + smbfs_rw_exit(&np->r_rwlock); +} + + +/* ARGSUSED */ +static int +smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct) +{ + smbmntinfo_t *smi; + + smi = VTOSMI(vp); + + if (curproc->p_zone != smi->smi_zone) + return (EPERM); + + if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + /* + * Because we stuff the readdir cookie into the offset field + * someone may attempt to do an lseek with the cookie which + * we want to succeed. + */ + if (vp->v_type == VDIR) + return (0); + + /* Like NFS3, just check for 63-bit overflow. */ + if (*noffp < 0) + return (EINVAL); + + return (0); +} + + +/* + * XXX + * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service. + */ +static int +smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, + offset_t offset, struct flk_callback *flk_cbp, cred_t *cr, + caller_context_t *ct) +{ + if (curproc->p_zone != VTOSMI(vp)->smi_zone) + return (EIO); + + if (VTOSMI(vp)->smi_flags & SMI_LLOCK) + return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct)); + else + return (ENOSYS); +} + +/* + * Free storage space associated with the specified vnode. The portion + * to be freed is specified by bfp->l_start and bfp->l_len (already + * normalized to a "whence" of 0). + * + * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc. + */ +/* ARGSUSED */ +static int +smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, + offset_t offset, cred_t *cr, caller_context_t *ct) +{ + int error; + smbmntinfo_t *smi; + + smi = VTOSMI(vp); + + if (curproc->p_zone != smi->smi_zone) + return (EIO); + + if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + ASSERT(vp->v_type == VREG); + if (cmd != F_FREESP) + return (EINVAL); + + /* + * Like NFS3, no 32-bit offset checks here. + * Our SMB layer takes care to return EFBIG + * when it has to fallback to a 32-bit call. + */ + + error = convoff(vp, bfp, 0, offset); + if (!error) { + ASSERT(bfp->l_start >= 0); + if (bfp->l_len == 0) { + struct vattr va; + + /* + * ftruncate should not change the ctime and + * mtime if we truncate the file to its + * previous size. + */ + va.va_mask = AT_SIZE; + error = smbfsgetattr(vp, &va, cr); + if (error || va.va_size == bfp->l_start) + return (error); + va.va_mask = AT_SIZE; + va.va_size = bfp->l_start; + error = smbfssetattr(vp, &va, 0, cr); + } else + error = EINVAL; + } + + return (error); +} + +/* ARGSUSED */ +static int +smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, + caller_context_t *ct) +{ + smbmntinfo_t *smi; + struct smb_share *ssp; + + smi = VTOSMI(vp); + + if (curproc->p_zone != smi->smi_zone) + return (EIO); + + if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + return (EIO); + + switch (cmd) { + case _PC_FILESIZEBITS: + ssp = smi->smi_share; + if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) + *valp = 64; + else + *valp = 32; + break; + + case _PC_LINK_MAX: + /* We only ever report one link to an object */ + *valp = 1; + break; + + case _PC_SYMLINK_MAX: /* No symlinks until we do Unix extensions */ + case _PC_ACL_ENABLED: /* No ACLs yet - see FILE_PERSISTENT_ACLS bit */ + case _PC_XATTR_EXISTS: /* No xattrs yet */ + *valp = 0; + break; + + default: + return (fs_pathconf(vp, cmd, valp, cr, ct)); + } + return (0); +} + + + +/* + * XXX + * This op should eventually support PSARC 2007/268. + */ +static int +smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr, + caller_context_t *ct) +{ + if (curproc->p_zone != VTOSMI(vp)->smi_zone) + return (EIO); + + if (VTOSMI(vp)->smi_flags & SMI_LLOCK) + return (fs_shrlock(vp, cmd, shr, flag, cr, ct)); + else + return (ENOSYS); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/netsmb/mchain.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,204 @@ +/* + * 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. + * + * $FreeBSD: src/sys/sys/mchain.h,v 1.1 2001/02/24 15:44:30 bp Exp $ + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _MCHAIN_H_ +#define _MCHAIN_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/isa_defs.h> +#include <sys/byteorder.h> + +#ifdef _LITTLE_ENDIAN + +/* little-endian values on little-endian */ +#define htoles(x) ((uint16_t)(x)) +#define letohs(x) ((uint16_t)(x)) +#define htolel(x) ((uint32_t)(x)) +#define letohl(x) ((uint32_t)(x)) +#define htoleq(x) ((uint64_t)(x)) +#define letohq(x) ((uint64_t)(x)) + +/* + * big-endian values on little-endian (swap) + * + * Use the BSWAP macros because they're fastest, and they're + * available in all environments where we use this header. + */ +#define htobes(x) BSWAP_16(x) +#define betohs(x) BSWAP_16(x) +#define htobel(x) BSWAP_32(x) +#define betohl(x) BSWAP_32(x) +#define htobeq(x) BSWAP_64(x) +#define betohq(x) BSWAP_64(x) + +#else /* (BYTE_ORDER == LITTLE_ENDIAN) */ + +/* little-endian values on big-endian (swap) */ +#define letohs(x) BSWAP_16(x) +#define htoles(x) BSWAP_16(x) +#define letohl(x) BSWAP_32(x) +#define htolel(x) BSWAP_32(x) +#define letohq(x) BSWAP_64(x) +#define htoleq(x) BSWAP_64(x) + +/* big-endian values on big-endian */ +#define htobes(x) ((uint16_t)(x)) +#define betohs(x) ((uint16_t)(x)) +#define htobel(x) ((uint32_t)(x)) +#define betohl(x) ((uint32_t)(x)) +#define htobeq(x) ((uint64_t)(x)) +#define betohq(x) ((uint64_t)(x)) +#endif /* (BYTE_ORDER == LITTLE_ENDIAN) */ + + +#ifdef _KERNEL + +/* BEGIN CSTYLED */ +/* + * BSD-style mbufs, vs SysV-style mblks: + * One big difference: the mbuf payload is: + * m_data ... (m_data + m_len) + * In Unix STREAMS, the mblk payload is: + * b_rptr ... b_wptr + * + * Here are some handy conversion notes: + * + * struct mbuf struct mblk + * m->m_next m->b_cont + * m->m_nextpkt m->b_next + * m->m_data m->b_rptr + * m->m_len MBLKL(m) + * m->m_dat[] m->b_datap->db_base + * &m->m_dat[MLEN] m->b_datap->db_lim + * M_TRAILINGSPACE(m) MBLKTAIL(m) + * m_freem(m) freemsg(m) + * + * Note that mbufs chains also have a special "packet" header, + * which has the length of the whole message. In STREAMS one + * typically just calls msgdsize(m) to get that. + */ +/* END CSTYLED */ + +#include <sys/stream.h> /* mblk_t */ + +/* + * Type of copy for mb_{put|get}_mem() + */ +#define MB_MSYSTEM 0 /* use bcopy() */ +#define MB_MUSER 1 /* use copyin()/copyout() */ +#define MB_MINLINE 2 /* use an inline copy loop */ +#define MB_MZERO 3 /* bzero(), mb_put_mem only */ +#define MB_MCUSTOM 4 /* use an user defined function */ + +struct mbchain { + mblk_t *mb_top; + mblk_t *mb_cur; + uint_t mb_count; +}; +typedef struct mbchain mbchain_t; + +struct mdchain { + mblk_t *md_top; /* head of mblk chain */ + mblk_t *md_cur; /* current mblk */ + uchar_t *md_pos; /* offset in the current mblk */ +}; +typedef struct mdchain mdchain_t; + +int m_fixhdr(mblk_t *m); + +int mb_init(struct mbchain *mbp); +void mb_initm(struct mbchain *mbp, mblk_t *m); +void mb_done(struct mbchain *mbp); +mblk_t *mb_detach(struct mbchain *mbp); +int mb_fixhdr(struct mbchain *mbp); +void *mb_reserve(struct mbchain *mbp, int size); + +int mb_put_padbyte(struct mbchain *mbp); +int mb_put_uint8(struct mbchain *mbp, uint8_t x); +int mb_put_uint16be(struct mbchain *mbp, uint16_t x); +int mb_put_uint16le(struct mbchain *mbp, uint16_t x); +int mb_put_uint32be(struct mbchain *mbp, uint32_t x); +int mb_put_uint32le(struct mbchain *mbp, uint32_t x); +int mb_put_uint64be(struct mbchain *mbp, uint64_t x); +int mb_put_uint64le(struct mbchain *mbp, uint64_t x); +int mb_put_mem(struct mbchain *mbp, const char *src, int size, int type); + +int mb_put_mblk(struct mbchain *mbp, mblk_t *m); +int mb_put_uio(struct mbchain *mbp, uio_t *uiop, int size); + +int md_init(struct mdchain *mdp); +void md_initm(struct mdchain *mbp, mblk_t *m); +void md_done(struct mdchain *mdp); +void md_append_record(struct mdchain *mdp, mblk_t *top); +int md_next_record(struct mdchain *mdp); +int md_get_uint8(struct mdchain *mdp, uint8_t *x); +int md_get_uint16(struct mdchain *mdp, uint16_t *x); +int md_get_uint16le(struct mdchain *mdp, uint16_t *x); +int md_get_uint16be(struct mdchain *mdp, uint16_t *x); +int md_get_uint32(struct mdchain *mdp, uint32_t *x); +int md_get_uint32be(struct mdchain *mdp, uint32_t *x); +int md_get_uint32le(struct mdchain *mdp, uint32_t *x); +int md_get_uint64(struct mdchain *mdp, uint64_t *x); +int md_get_uint64be(struct mdchain *mdp, uint64_t *x); +int md_get_uint64le(struct mdchain *mdp, uint64_t *x); +int md_get_mem(struct mdchain *mdp, caddr_t target, int size, int type); +int md_get_mblk(struct mdchain *mdp, int size, mblk_t **m); +int md_get_uio(struct mdchain *mdp, uio_t *uiop, int size); + +/* + * Additions for Solaris to replace things that came from + * <sys/mbuf.h> in the Darwin code. These are mostly just + * wrappers for streams functions. See: subr_mchain.c + */ + +#define mtod(m, t) ((t)((m)->b_rptr)) + +/* length to m_copym to copy all */ +#define M_COPYALL -1 + +mblk_t *m_copym(mblk_t *, int, int, int); +mblk_t *m_pullup(mblk_t *, int); +mblk_t *m_split(mblk_t *, int, int); +void m_cat(mblk_t *, mblk_t *); +#define m_freem(x) freemsg(x) +mblk_t *m_getblk(int, int); + +#endif /* ifdef _KERNEL */ +#endif /* !_MCHAIN_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/netsmb/netbios.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,160 @@ +/* + * 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: netbios.h,v 1.5 2004/03/19 01:49:45 lindak Exp $ + */ + +#ifndef _NETSMB_NETBIOS_H_ +#define _NETSMB_NETBIOS_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef _NETINET_IN_H_ +#include <netinet/in.h> +#endif + +/* + * This is a fake address family number, used to + * recognize our fake sockaddr_nb objects. + * This is never handed to bind or connect. + */ +#ifndef AF_NETBIOS +#define AF_NETBIOS (AF_MAX+2) +#endif + +#define PF_NETBIOS AF_NETBIOS + +/* + * NetBIOS port numbers by the names used in the Darwin code. + * XXX: Change the code to use IPPORT_xxx from in.h directly. + * XXX: Add IPPORT_SMB_OVER_TCP or some such (port 445) + */ +#define NBNS_UDP_PORT IPPORT_NETBIOS_NS /* 137 */ +#define SMB_TCP_PORT IPPORT_NETBIOS_SSN /* 139 */ + +#define NBPROTO_TCPSSN 1 /* NETBIOS session over TCP */ + +#define NB_NAMELEN 16 +#define NB_ENCNAMELEN NB_NAMELEN * 2 +#define NB_MAXLABLEN 63 + +#define NB_MINSALEN (sizeof (struct sockaddr_nb)) + +/* + * name types + */ +#define NBT_WKSTA 0x00 +#define NBT_CLIENT 0x03 +#define NBT_RASSRVR 0x06 +#define NBT_DMB 0x1B +#define NBT_IP 0x1C +#define NBT_MB 0x1D +#define NBT_BS 0x1E +#define NBT_NETDDE 0x1F +#define NBT_SERVER 0x20 +#define NBT_RASCLNT 0x21 +#define NBT_NMAGENT 0xBE +#define NBT_NMUTIL 0xBF + +/* + * Session packet types + */ +#define NB_SSN_MESSAGE 0x0 +#define NB_SSN_REQUEST 0x81 +#define NB_SSN_POSRESP 0x82 +#define NB_SSN_NEGRESP 0x83 +#define NB_SSN_RTGRESP 0x84 +#define NB_SSN_KEEPALIVE 0x85 + +/* + * resolver: Opcodes + */ +#define NBNS_OPCODE_QUERY 0x00 +#define NBNS_OPCODE_REGISTER 0x05 +#define NBNS_OPCODE_RELEASE 0x06 +#define NBNS_OPCODE_WACK 0x07 +#define NBNS_OPCODE_REFRESH 0x08 +#define NBNS_OPCODE_RESPONSE 0x10 /* or'ed with other opcodes */ + +/* + * resolver: NM_FLAGS + */ +#define NBNS_NMFLAG_BCAST 0x01 +#define NBNS_NMFLAG_RA 0x08 /* recursion available */ +#define NBNS_NMFLAG_RD 0x10 /* recursion desired */ +#define NBNS_NMFLAG_TC 0x20 /* truncation occured */ +#define NBNS_NMFLAG_AA 0x40 /* authoritative answer */ + +/* + * resolver: Question types + */ +#define NBNS_QUESTION_TYPE_NB 0x0020 +#define NBNS_QUESTION_TYPE_NBSTAT 0x0021 + +/* + * resolver: Question class + */ +#define NBNS_QUESTION_CLASS_IN 0x0001 + +/* + * resolver: Limits + */ +#define NBNS_MAXREDIRECTS 3 /* max number of accepted redirects */ +#define NBDG_MAXSIZE 576 /* maximum nbns datagram size */ + +/* + * NETBIOS addressing + */ + +struct nb_name { + uint_t nn_type; + char nn_name[NB_NAMELEN]; + char *nn_scope; +}; +typedef struct nb_name nb_name_t; + +/* + * Our private NetBIOS socket address format. + * Note that it's LARGER than sockaddr. + * + * XXX: Also note that the library code is sloppy about + * casting this to sockaddr_in so let's keep snb_ipaddr + * at the same offset, at least until that's fixed. + */ +struct sockaddr_nb { + sa_family_t snb_family; /* address family */ + uint16_t snb_flags; /* NBNS_GROUPFLG, etc. */ + uint32_t snb_ipaddr; /* always IPv4 */ + char snb_name[NB_NAMELEN]; /* NOT encoded */ +}; +typedef struct sockaddr_nb sockaddr_nb_t; + +#endif /* !_NETSMB_NETBIOS_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/netsmb/smb.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,1522 @@ +/* + * Copyright (c) 2000-2001 Boris Popov + * All rights reserved. + * + * Now many of these defines are from samba4 code, by Andrew Tridgell. + * (Permission given to Conrad Minshall at CIFS plugfest Aug 13 2003.) + * (Note the main decision was whether to use defines found in MS includes + * and web pages, versus Samba, and the deciding factor is which developers + * are more likely to be looking at this code base.) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb.h,v 1.36.90.1 2005/05/27 02:35:29 lindak Exp $ + */ + +/* + * Common definintions and structures for SMB/CIFS protocol + */ + +#ifndef _NETSMB_SMB_H_ +#define _NETSMB_SMB_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This file should be purely SMB protocol definition stuff. + * (Please don't make it a catch-all:) + */ + +/* + * SMB dialects that we have to deal with. + */ +enum smb_dialects { + SMB_DIALECT_NONE, + SMB_DIALECT_CORE, /* PC NETWORK PROGRAM 1.0, PCLAN1.0 */ + SMB_DIALECT_COREPLUS, /* MICROSOFT NETWORKS 1.03 */ + SMB_DIALECT_LANMAN1_0, /* MICROSOFT NETWORKS 3.0, LANMAN1.0 */ + SMB_DIALECT_LANMAN2_0, /* LM1.2X002, DOS LM1.2X002, Samba */ + SMB_DIALECT_LANMAN2_1, /* DOS LANMAN2.1, LANMAN2.1 */ + SMB_DIALECT_NTLM0_12 /* NT LM 0.12, Windows for Workgroups */ + /* 3.1a, * NT LANMAN 1.0 */ +}; + +/* + * Formats of data/string buffers + */ +#define SMB_DT_DATA 1 +#define SMB_DT_DIALECT 2 +#define SMB_DT_PATHNAME 3 +#define SMB_DT_ASCII 4 +#define SMB_DT_VARIABLE 5 + +/* + * SMB header + */ +#define SMB_SIGNATURE "\xFFSMB" +#define SMB_SIGLEN 4 +#define SMB_HDRCMD(p) (*((uchar_t *)(p) + SMB_SIGLEN)) +#define SMB_HDRMID(p) (letohs(*(ushort_t *)((uchar_t *)(p) + 30))) +#define SMB_HDRLEN 32 +/* + * bits in the smb_flags field + */ +#define SMB_FLAGS_SUPPORT_LOCKREAD 0x01 +#define SMB_FLAGS_CLIENT_BUF_AVAIL 0x02 +#define SMB_FLAGS_CASELESS 0x08 +#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10 +#define SMB_FLAGS_REQUEST_OPLOCK 0x20 +#define SMB_FLAGS_REQUEST_BATCH_OPLOCK 0x40 +#define SMB_FLAGS_SERVER_RESP 0x80 + +/* + * bits in the smb_flags2 field + */ +#define SMB_FLAGS2_KNOWS_LONG_NAMES 0x0001 +#define SMB_FLAGS2_KNOWS_EAS 0x0002 /* client know about EAs */ +#define SMB_FLAGS2_SECURITY_SIGNATURE 0x0004 /* check SMB integrity */ +#define SMB_FLAGS2_IS_LONG_NAME 0x0040 /* any path name is long name */ +#define SMB_FLAGS2_EXT_SEC 0x0800 /* client aware of Extended */ + /* Security negotiation */ +#define SMB_FLAGS2_DFS 0x1000 /* resolve paths in DFS */ +#define SMB_FLAGS2_PAGING_IO 0x2000 /* for exec */ +#define SMB_FLAGS2_ERR_STATUS 0x4000 /* 1 - status.status */ +#define SMB_FLAGS2_UNICODE 0x8000 /* use Unicode for strings */ + +#define SMB_UID_UNKNOWN 0xffff +#define SMB_TID_UNKNOWN 0xffff +#define SMB_FID_UNUSED 0xffff + +/* + * Security mode bits + */ +#define SMB_SM_USER 0x01 /* server in the user security mode */ +#define SMB_SM_ENCRYPT 0x02 /* use challenge/responce */ +#define SMB_SM_SIGS 0x04 +#define SMB_SM_SIGS_REQUIRE 0x08 + +/* + * Action bits in session setup reply + */ +#define SMB_ACT_GUEST 0x01 + +/* + * NTLM capabilities + */ +#define SMB_CAP_RAW_MODE 0x0001 +#define SMB_CAP_MPX_MODE 0x0002 +#define SMB_CAP_UNICODE 0x0004 +#define SMB_CAP_LARGE_FILES 0x0008 /* 64 bit offsets supported */ +#define SMB_CAP_NT_SMBS 0x0010 +#define SMB_CAP_RPC_REMOTE_APIS 0x0020 +#define SMB_CAP_STATUS32 0x0040 +#define SMB_CAP_LEVEL_II_OPLOCKS 0x0080 +#define SMB_CAP_LOCK_AND_READ 0x0100 +#define SMB_CAP_NT_FIND 0x0200 +#define SMB_CAP_DFS 0x1000 +#define SMB_CAP_INFOLEVEL_PASSTHRU 0x2000 +#define SMB_CAP_LARGE_READX 0x4000 +#define SMB_CAP_LARGE_WRITEX 0x8000 +#define SMB_CAP_UNIX 0x00800000 +#define SMB_CAP_BULK_TRANSFER 0x20000000 +#define SMB_CAP_COMPRESSED_DATA 0x40000000 +#define SMB_CAP_EXT_SECURITY 0x80000000 + +/* + * File attributes + */ +#define SMB_FA_RDONLY 0x01 +#define SMB_FA_HIDDEN 0x02 +#define SMB_FA_SYSTEM 0x04 +#define SMB_FA_VOLUME 0x08 +#define SMB_FA_DIR 0x10 +#define SMB_FA_ARCHIVE 0x20 + +/* + * Extended file attributes + */ +#define SMB_EFA_RDONLY 0x00000001 +#define SMB_EFA_HIDDEN 0x00000002 +#define SMB_EFA_SYSTEM 0x00000004 +#define SMB_EFA_VOLUME 0x00000008 +#define SMB_EFA_DIRECTORY 0x00000010 +#define SMB_EFA_ARCHIVE 0x00000020 +#define SMB_EFA_DEVICE 0x00000040 +#define SMB_EFA_NORMAL 0x00000080 +#define SMB_EFA_TEMPORARY 0x00000100 +#define SMB_EFA_SPARSE 0x00000200 +#define SMB_EFA_REPARSE_POINT 0x00000400 +#define SMB_EFA_COMPRESSED 0x00000800 +#define SMB_EFA_OFFLINE 0x00001000 +#define SMB_EFA_NONINDEXED 0x00002000 +#define SMB_EFA_ENCRYPTED 0x00004000 +#define SMB_EFA_POSIX_SEMANTICS 0x01000000 +#define SMB_EFA_BACKUP_SEMANTICS 0x02000000 +#define SMB_EFA_DELETE_ON_CLOSE 0x04000000 +#define SMB_EFA_SEQUENTIAL_SCAN 0x08000000 +#define SMB_EFA_RANDOM_ACCESS 0x10000000 +#define SMB_EFA_NO_BUFFERING 0x20000000 +#define SMB_EFA_WRITE_THROUGH 0x80000000 + +/* + * Access Mode Encoding + */ +#define SMB_AM_OPENREAD 0x0000 +#define SMB_AM_OPENWRITE 0x0001 +#define SMB_AM_OPENRW 0x0002 +#define SMB_AM_OPENEXEC 0x0003 +#define SMB_AM_OPENMODE 0x0003 /* mask for access mode bits */ +#define SMB_SM_COMPAT 0x0000 +#define SMB_SM_EXCLUSIVE 0x0010 +#define SMB_SM_DENYWRITE 0x0020 +#define SMB_SM_DENYREADEXEC 0x0030 +#define SMB_SM_DENYNONE 0x0040 + +/* NT_CREATE_ANDX flags */ +#define NTCREATEX_FLAGS_REQUEST_OPLOCK 0x02 +#define NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK 0x04 +#define NTCREATEX_FLAGS_OPEN_DIRECTORY 0x08 +#define NTCREATEX_FLAGS_EXTENDED 0x10 + +/* NT_CREATE_ANDX share_access (share mode) */ +#define NTCREATEX_SHARE_ACCESS_NONE 0 +#define NTCREATEX_SHARE_ACCESS_READ 1 +#define NTCREATEX_SHARE_ACCESS_WRITE 2 +#define NTCREATEX_SHARE_ACCESS_DELETE 4 +#define NTCREATEX_SHARE_ACCESS_ALL 7 + +/* NT_CREATE_ANDX open_disposition */ +#define NTCREATEX_DISP_SUPERSEDE 0 /* if file exists supersede it */ +#define NTCREATEX_DISP_OPEN 1 /* exists ? open it : fail */ +#define NTCREATEX_DISP_CREATE 2 /* exists ? fail : create it */ +#define NTCREATEX_DISP_OPEN_IF 3 /* exists ? open it : create it */ +#define NTCREATEX_DISP_OVERWRITE 4 /* exists ? overwrite : fail */ +#define NTCREATEX_DISP_OVERWRITE_IF 5 /* exists ? overwrite : create */ + +/* NT_CREATE_ANDX create_options */ +#define NTCREATEX_OPTIONS_DIRECTORY 0x0001 +#define NTCREATEX_OPTIONS_WRITE_THROUGH 0x0002 +#define NTCREATEX_OPTIONS_SEQUENTIAL_ONLY 0x0004 +#define NTCREATEX_OPTIONS_SYNC_ALERT 0x0010 +#define NTCREATEX_OPTIONS_ASYNC_ALERT 0x0020 +#define NTCREATEX_OPTIONS_NON_DIRECTORY_FILE 0x0040 +#define NTCREATEX_OPTIONS_NO_EA_KNOWLEDGE 0x0200 +#define NTCREATEX_OPTIONS_EIGHT_DOT_THREE_ONLY 0x0400 +#define NTCREATEX_OPTIONS_RANDOM_ACCESS 0x0800 +#define NTCREATEX_OPTIONS_DELETE_ON_CLOSE 0x1000 +#define NTCREATEX_OPTIONS_OPEN_BY_FILE_ID 0x2000 + +/* NT_CREATE_ANDX "impersonation" */ +#define NTCREATEX_IMPERSONATION_ANONYMOUS 0 +#define NTCREATEX_IMPERSONATION_IDENTIFICATION 1 +#define NTCREATEX_IMPERSONATION_IMPERSONATION 2 +#define NTCREATEX_IMPERSONATION_DELEGATION 3 + +/* NT_CREATE_ANDX security flags */ +#define NTCREATEX_SECURITY_DYNAMIC 1 +#define NTCREATEX_SECURITY_ALL 2 + +/* NT_CREATE_ANDX create_action in reply */ +#define NTCREATEX_ACTION_EXISTED 1 +#define NTCREATEX_ACTION_CREATED 2 +#define NTCREATEX_ACTION_TRUNCATED 3 + +/* SMB_TRANS2_FIND_FIRST2/SMB_TRANS2_FIND_NEXT2 flags */ +#define FIND2_CLOSE_AFTER_REQUEST 0x0001 +#define FIND2_CLOSE_ON_EOS 0x0002 +#define FIND2_RETURN_RESUME_KEYS 0x0004 +#define FIND2_CONTINUE_SEARCH 0x0008 +#define FIND2_BACKUP_INTENT 0x0010 + +/* + * SMB commands + */ +#define SMB_COM_CREATE_DIRECTORY 0x00 +#define SMB_COM_DELETE_DIRECTORY 0x01 +#define SMB_COM_OPEN 0x02 +#define SMB_COM_CREATE 0x03 +#define SMB_COM_CLOSE 0x04 +#define SMB_COM_FLUSH 0x05 +#define SMB_COM_DELETE 0x06 +#define SMB_COM_RENAME 0x07 +#define SMB_COM_QUERY_INFORMATION 0x08 +#define SMB_COM_SET_INFORMATION 0x09 +#define SMB_COM_READ 0x0A +#define SMB_COM_WRITE 0x0B +#define SMB_COM_LOCK_BYTE_RANGE 0x0C +#define SMB_COM_UNLOCK_BYTE_RANGE 0x0D +#define SMB_COM_CREATE_TEMPORARY 0x0E +#define SMB_COM_CREATE_NEW 0x0F +#define SMB_COM_CHECK_DIRECTORY 0x10 +#define SMB_COM_PROCESS_EXIT 0x11 +#define SMB_COM_SEEK 0x12 +#define SMB_COM_LOCK_AND_READ 0x13 +#define SMB_COM_WRITE_AND_UNLOCK 0x14 +#define SMB_COM_READ_RAW 0x1A +#define SMB_COM_READ_MPX 0x1B +#define SMB_COM_READ_MPX_SECONDARY 0x1C +#define SMB_COM_WRITE_RAW 0x1D +#define SMB_COM_WRITE_MPX 0x1E +#define SMB_COM_WRITE_COMPLETE 0x20 +#define SMB_COM_SET_INFORMATION2 0x22 +#define SMB_COM_QUERY_INFORMATION2 0x23 +#define SMB_COM_LOCKING_ANDX 0x24 +#define SMB_COM_TRANSACTION 0x25 +#define SMB_COM_TRANSACTION_SECONDARY 0x26 +#define SMB_COM_IOCTL 0x27 +#define SMB_COM_IOCTL_SECONDARY 0x28 +#define SMB_COM_COPY 0x29 +#define SMB_COM_MOVE 0x2A +#define SMB_COM_ECHO 0x2B +#define SMB_COM_WRITE_AND_CLOSE 0x2C +#define SMB_COM_OPEN_ANDX 0x2D +#define SMB_COM_READ_ANDX 0x2E +#define SMB_COM_WRITE_ANDX 0x2F +#define SMB_COM_CLOSE_AND_TREE_DISC 0x31 +#define SMB_COM_TRANSACTION2 0x32 +#define SMB_COM_TRANSACTION2_SECONDARY 0x33 +#define SMB_COM_FIND_CLOSE2 0x34 +#define SMB_COM_FIND_NOTIFY_CLOSE 0x35 +#define SMB_COM_TREE_CONNECT 0x70 +#define SMB_COM_TREE_DISCONNECT 0x71 +#define SMB_COM_NEGOTIATE 0x72 +#define SMB_COM_SESSION_SETUP_ANDX 0x73 +#define SMB_COM_LOGOFF_ANDX 0x74 +#define SMB_COM_TREE_CONNECT_ANDX 0x75 +#define SMB_COM_QUERY_INFORMATION_DISK 0x80 +#define SMB_COM_SEARCH 0x81 +#define SMB_COM_FIND 0x82 +#define SMB_COM_FIND_UNIQUE 0x83 +#define SMB_COM_NT_TRANSACT 0xA0 +#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 +#define SMB_COM_NT_CREATE_ANDX 0xA2 +#define SMB_COM_NT_CANCEL 0xA4 +#define SMB_COM_OPEN_PRINT_FILE 0xC0 +#define SMB_COM_WRITE_PRINT_FILE 0xC1 +#define SMB_COM_CLOSE_PRINT_FILE 0xC2 +#define SMB_COM_GET_PRINT_QUEUE 0xC3 +#define SMB_COM_READ_BULK 0xD8 +#define SMB_COM_WRITE_BULK 0xD9 +#define SMB_COM_WRITE_BULK_DATA 0xDA + +/* + * SMB_COM_TRANSACTION2 subcommands + */ +#define SMB_TRANS2_OPEN2 0x00 +#define SMB_TRANS2_FIND_FIRST2 0x01 +#define SMB_TRANS2_FIND_NEXT2 0x02 +#define SMB_TRANS2_QUERY_FS_INFORMATION 0x03 +#define SMB_TRANS2_SETFSINFO 0x04 +#define SMB_TRANS2_QUERY_PATH_INFORMATION 0x05 +#define SMB_TRANS2_SET_PATH_INFORMATION 0x06 +#define SMB_TRANS2_QUERY_FILE_INFORMATION 0x07 +#define SMB_TRANS2_SET_FILE_INFORMATION 0x08 +#define SMB_TRANS2_FSCTL 0x09 +#define SMB_TRANS2_IOCTL2 0x0A +#define SMB_TRANS2_FIND_NOTIFY_FIRST 0x0B +#define SMB_TRANS2_FIND_NOTIFY_NEXT 0x0C +#define SMB_TRANS2_CREATE_DIRECTORY 0x0D +#define SMB_TRANS2_SESSION_SETUP 0x0E +#define SMB_TRANS2_GET_DFS_REFERRAL 0x10 +#define SMB_TRANS2_REPORT_DFS_INCONSISTENCY 0x11 + +/* + * SMB_COM_NT_TRANSACT subcommands + */ +#define NT_TRANSACT_CREATE 0x01 +#define NT_TRANSACT_IOCTL 0x02 +#define NT_TRANSACT_SET_SECURITY_DESC 0x03 +#define NT_TRANSACT_NOTIFY_CHANGE 0x04 +#define NT_TRANSACT_RENAME 0x05 +#define NT_TRANSACT_QUERY_SECURITY_DESC 0x06 +#define NT_TRANSACT_GET_USER_QUOTA 0x07 +#define NT_TRANSACT_SET_USER_QUOTA 0x08 + +/* + * SMB_TRANS2_QUERY_FS_INFORMATION levels + */ +#define SMB_QFS_ALLOCATION 1 +#define SMB_QFS_VOLUME 2 +#define SMB_QFS_LABEL_INFO 0x101 +#define SMB_QFS_VOLUME_INFO 0x102 +#define SMB_QFS_SIZE_INFO 0x103 +#define SMB_QFS_DEVICE_INFO 0x104 +#define SMB_QFS_ATTRIBUTE_INFO 0x105 +#define SMB_QFS_UNIX_INFO 0x200 +#define SMB_QFS_MAC_FS_INFO 0x301 +#define SMB_QFS_VOLUME_INFORMATION 1001 +#define SMB_QFS_SIZE_INFORMATION 1003 +#define SMB_QFS_DEVICE_INFORMATION 1004 +#define SMB_QFS_ATTRIBUTE_INFORMATION 1005 +#define SMB_QFS_QUOTA_INFORMATION 1006 +#define SMB_QFS_FULL_SIZE_INFORMATION 1007 +#define SMB_QFS_OBJECTID_INFORMATION 1008 + + +/* + * SMB_QFS_ATTRIBUTE_INFO bits. + * The following info found in msdn + * (http://msdn.microsoft.com/library/default.asp? + * url=/library/en-us/wmisdk/wmi/win32_cdromdrive.asp) + * Naming is mostly as in samba, to help Those Who Google. + */ +#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 +#define FILE_CASE_PRESERVED_NAMES 0x00000002 +#define FILE_UNICODE_ON_DISK 0x00000004 +#define FILE_PERSISTENT_ACLS 0x00000008 +#define FILE_FILE_COMPRESSION 0x00000010 +#define FILE_VOLUME_QUOTAS 0x00000020 +#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 +#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 +#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 +#define FILE_SUPPORTS_LONG_NAMES 0x00004000 +#define FILE_VOLUME_IS_COMPRESSED 0x00008000 +#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 +#define FILE_SUPPORTS_ENCRYPTION 0x00020000 +#define FILE_NAMED_STREAMS 0x00040000 + +/* + * SMB_TRANS2_QUERY_PATH levels + */ +#define SMB_QFILEINFO_STANDARD 1 +#define SMB_QFILEINFO_EA_SIZE 2 +#define SMB_QFILEINFO_EAS_FROM_LIST 3 +#define SMB_QFILEINFO_ALL_EAS 4 +#define SMB_QFILEINFO_IS_NAME_VALID 6 /* QPATHINFO only? */ +#define SMB_QFILEINFO_BASIC_INFO 0x101 +#define SMB_QFILEINFO_STANDARD_INFO 0x102 +#define SMB_QFILEINFO_EA_INFO 0x103 +#define SMB_QFILEINFO_NAME_INFO 0x104 +#define SMB_QFILEINFO_ALLOCATION_INFO 0x105 +#define SMB_QFILEINFO_END_OF_FILE_INFO 0x106 +#define SMB_QFILEINFO_ALL_INFO 0x107 +#define SMB_QFILEINFO_ALT_NAME_INFO 0x108 +#define SMB_QFILEINFO_STREAM_INFO 0x109 +#define SMB_QFILEINFO_COMPRESSION_INFO 0x10b +#define SMB_QFILEINFO_UNIX_BASIC 0x200 +#define SMB_QFILEINFO_UNIX_LINK 0x201 +#define SMB_QFILEINFO_MAC_DT_GET_APPL 0x306 +#define SMB_QFILEINFO_MAC_DT_GET_ICON 0x307 +#define SMB_QFILEINFO_MAC_DT_GET_ICON_INFO 0x308 +#define SMB_QFILEINFO_BASIC_INFORMATION 1004 +#define SMB_QFILEINFO_STANDARD_INFORMATION 1005 +#define SMB_QFILEINFO_INTERNAL_INFORMATION 1006 +#define SMB_QFILEINFO_EA_INFORMATION 1007 +#define SMB_QFILEINFO_ACCESS_INFORMATION 1008 +#define SMB_QFILEINFO_NAME_INFORMATION 1009 +#define SMB_QFILEINFO_POSITION_INFORMATION 1014 +#define SMB_QFILEINFO_MODE_INFORMATION 1016 +#define SMB_QFILEINFO_ALIGNMENT_INFORMATION 1017 +#define SMB_QFILEINFO_ALL_INFORMATION 1018 +#define SMB_QFILEINFO_ALT_NAME_INFORMATION 1021 +#define SMB_QFILEINFO_STREAM_INFORMATION 1022 +#define SMB_QFILEINFO_COMPRESSION_INFORMATION 1028 +#define SMB_QFILEINFO_NETWORK_OPEN_INFORMATION 1034 +#define SMB_QFILEINFO_ATTRIBUTE_TAG_INFORMATION 1035 + +/* + * SMB_TRANS2_FIND_FIRST2 information levels + */ +#define SMB_FIND_STANDARD 1 +#define SMB_FIND_EA_SIZE 2 +#define SMB_FIND_EAS_FROM_LIST 3 +#define SMB_FIND_DIRECTORY_INFO 0x101 +#define SMB_FIND_FULL_DIRECTORY_INFO 0x102 +#define SMB_FIND_NAME_INFO 0x103 +#define SMB_FIND_BOTH_DIRECTORY_INFO 0x104 +#define SMB_FIND_UNIX_INFO 0x200 + +/* + * Selectors for NT_TRANSACT_QUERY_SECURITY_DESC and + * NT_TRANSACT_SET_SECURITY_DESC. Details found in the MSDN + * library by searching on security_information. + * Note the protected/unprotected bits did not exist in NT. + */ + +#define OWNER_SECURITY_INFORMATION 0x00000001 +#define GROUP_SECURITY_INFORMATION 0x00000002 +#define DACL_SECURITY_INFORMATION 0x00000004 +#define SACL_SECURITY_INFORMATION 0x00000008 +#define UNPROTECTED_SACL_SECURITY_INFORMATION 0x10000000 +#define UNPROTECTED_DACL_SECURITY_INFORMATION 0x20000000 +#define PROTECTED_SACL_SECURITY_INFORMATION 0x40000000 +#define PROTECTED_DACL_SECURITY_INFORMATION 0x80000000 + +/* + * security descriptor header + * it is followed by the optional SIDs and ACLs + * note this is "raw", ie little-endian + */ +struct ntsecdesc { + uint8_t sd_revision; /* 0x01 observed between W2K */ + uint8_t sd_pad1; + uint16_t sd_flags; + uint32_t sd_owneroff; /* offset to owner SID */ + uint32_t sd_groupoff; /* offset to group SID */ + uint32_t sd_sacloff; /* offset to system/audit ACL */ + uint32_t sd_dacloff; /* offset to discretionary ACL */ +}; /* XXX: __attribute__((__packed__)); */ +typedef struct ntsecdesc ntsecdesc_t; + +#define wset_sdrevision(s) ((s)->sd_revision = 0x01) +#define sdflags(s) (letohs((s)->sd_flags)) +#define wset_sdflags(s, f) ((s)->sd_flags = letohs(f)) +#define sdowner(s) \ + ((struct ntsid *)((s)->sd_owneroff ? \ + (char *)(s) + letohl((s)->sd_owneroff) : \ + NULL)) +#define wset_sdowneroff(s, o) ((s)->sd_owneroff = htolel(o)) +#define sdgroup(s) \ + ((struct ntsid *)((s)->sd_groupoff ? \ + (char *)(s) + letohl((s)->sd_groupoff) : \ + NULL)) +#define wset_sdgroupoff(s, o) ((s)->sd_groupoff = htolel(o)) +#define sdsacl(s) \ + ((struct ntacl *)((s)->sd_sacloff ? \ + (char *)(s) + letohl((s)->sd_sacloff) : \ + NULL)) +#define wset_sdsacloff(s, o) ((s)->sd_sacloff = htolel(o)) +#define sddacl(s) \ + ((struct ntacl *)((s)->sd_dacloff ? \ + (char *)(s) + letohl((s)->sd_dacloff) : \ + NULL)) +#define wset_sddacloff(s, o) ((s)->sd_dacloff = htolel(o)) + +/* + * sd_flags bits + */ +#define SD_OWNER_DEFAULTED 0x0001 +#define SD_GROUP_DEFAULTED 0x0002 +#define SD_DACL_PRESENT 0x0004 +#define SD_DACL_DEFAULTED 0x0008 +#define SD_SACL_PRESENT 0x0010 +#define SD_SACL_DEFAULTED 0x0020 +#define SD_DACL_TRUSTED 0x0040 +#define SD_SERVER_SECURITY 0x0080 +#define SD_DACL_AUTO_INHERIT_REQ 0x0100 +#define SD_SACL_AUTO_INHERIT_REQ 0x0200 +#define SD_DACL_AUTO_INHERITED 0x0400 +#define SD_SACL_AUTO_INHERITED 0x0800 +#define SD_DACL_PROTECTED 0x1000 +#define SD_SACL_PROTECTED 0x2000 +#define SD_RM_CONTROL_VALID 0x4000 +#define SD_SELF_RELATIVE 0x8000 + +/* + * access control list header + * it is followed by the ACEs + * note this is "raw", ie little-endian + */ +struct ntacl { + uint8_t acl_revision; /* 0x02 observed with W2K */ + uint8_t acl_pad1; + uint16_t acl_len; /* bytes; includes this header */ + uint16_t acl_acecount; + uint16_t acl_pad2; +}; /* XXX: __attribute__((__packed__)); */ +typedef struct ntacl ntacl_t; + +#define wset_aclrevision(a) ((a)->acl_revision = 0x02) +#define acllen(a) (letohs((a)->acl_len)) +#define wset_acllen(a, l) ((a)->acl_len = htoles(l)) +#define aclacecount(a) (letohs((a)->acl_acecount)) +#define wset_aclacecount(a, c) ((a)->acl_acecount = htoles(c)) +#define aclace(a) ((struct ntace *)((char *)(a) + sizeof (struct ntacl))) + +/* + * access control entry header + * it is followed by type-specific ace data, + * which for the simple types is just a SID + * note this is "raw", ie little-endian + */ +struct ntace { + uint8_t ace_type; + uint8_t ace_flags; + uint16_t ace_len; /* bytes; includes this header */ + uint32_t ace_rights; /* generic, standard, specific, etc */ +}; /* XXX: __attribute__((__packed__)); */ + +#define acetype(a) ((a)->ace_type) +#define wset_acetype(a, t) ((a)->ace_type = (t)) +#define aceflags(a) ((a)->ace_flags) +#define wset_aceflags(a, f) ((a)->ace_flags = (f)) +#define acelen(a) (letohs((a)->ace_len)) +#define wset_acelen(a, l) ((a)->ace_len = htoles(l)) +#define acerights(a) (letohl((a)->ace_rights)) +#define wset_acerights(a, r) ((a)->ace_rights = htolel(r)) +#define aceace(a) ((struct ntace *)((char *)(a) + acelen(a))) +#define acesid(a) ((struct ntsid *)((char *)(a) + sizeof (struct ntace))) + +/* + * ace_rights + * (Samba bit names are used here, with permission, as the shorter Windows + * names are more likely to cause namespace collisions) + */ +#define SA_RIGHT_FILE_READ_DATA 0x00000001 +#define SA_RIGHT_FILE_WRITE_DATA 0x00000002 +#define SA_RIGHT_FILE_APPEND_DATA 0x00000004 +#define SA_RIGHT_FILE_READ_EA 0x00000008 +#define SA_RIGHT_FILE_WRITE_EA 0x00000010 +#define SA_RIGHT_FILE_EXECUTE 0x00000020 +#define SA_RIGHT_FILE_DELETE_CHILD 0x00000040 +#define SA_RIGHT_FILE_READ_ATTRIBUTES 0x00000080 +#define SA_RIGHT_FILE_WRITE_ATTRIBUTES 0x00000100 +#define SA_RIGHT_FILE_ALL_ACCESS 0x000001FF + +#define STD_RIGHT_DELETE_ACCESS 0x00010000 +#define STD_RIGHT_READ_CONTROL_ACCESS 0x00020000 +#define STD_RIGHT_WRITE_DAC_ACCESS 0x00040000 +#define STD_RIGHT_WRITE_OWNER_ACCESS 0x00080000 +#define STD_RIGHT_SYNCHRONIZE_ACCESS 0x00100000 +#define STD_RIGHT_ALL_ACCESS 0x001F0000 + +#define SEC_RIGHT_SYSTEM_SECURITY 0x01000000 +/* + * Don't use MAXIMUM_ALLOWED as Samba (2.2.3 at least) will + * return NT_STATUS_INVALID_LOCK_SEQUENCE + */ +#define SEC_RIGHT_MAXIMUM_ALLOWED 0x02000000 + +#define GENERIC_RIGHT_ALL_ACCESS 0x10000000 +#define GENERIC_RIGHT_EXECUTE_ACCESS 0x20000000 +#define GENERIC_RIGHT_WRITE_ACCESS 0x40000000 +#define GENERIC_RIGHT_READ_ACCESS 0x80000000 + +/* + * these mappings are from Windows sample code but are likely incomplete + * + * GENERIC_RIGHT_READ_ACCESS : + * STD_RIGHT_SYNCHRONIZE_ACCESS | + * STD_RIGHT_READ_CONTROL_ACCESS | + * SA_RIGHT_FILE_READ_ATTRIBUTES | + * SA_RIGHT_FILE_READ_EA | + * SA_RIGHT_FILE_READ_DATA + * GENERIC_RIGHT_WRITE_ACCESS : + * STD_RIGHT_SYNCHRONIZE_ACCESS | + * STD_RIGHT_READ_CONTROL_ACCESS | + * SA_RIGHT_FILE_WRITE_ATTRIBUTES | + * SA_RIGHT_FILE_WRITE_EA | + * SA_RIGHT_FILE_APPEND_DATA | + * SA_RIGHT_FILE_WRITE_DATA + * GENERIC_RIGHT_EXECUTE_ACCESS : + * STD_RIGHT_SYNCHRONIZE_ACCESS | + * STD_RIGHT_READ_CONTROL_ACCESS | + * SA_RIGHT_FILE_READ_ATTRIBUTES | + * SA_RIGHT_FILE_EXECUTE + * GENERIC_RIGHT_ALL_ACCESS : + * STD_RIGHT_SYNCHRONIZE_ACCESS | + * STD_RIGHT_WRITE_OWNER_ACCESS | + * STD_RIGHT_WRITE_DAC_ACCESS | + * STD_RIGHT_READ_CONTROL_ACCESS | + * STD_RIGHT_DELETE_ACCESS | + * SA_RIGHT_FILE_ALL_ACCESS + */ + +/* + * security identifier header + * it is followed by sid_numauth sub-authorities, + * which are 32 bits each. + * note the subauths are little-endian on the wire, but + * need to be big-endian for memberd/DS + */ +#define SIDAUTHSIZE 6 +struct ntsid { + uint8_t sid_revision; + uint8_t sid_subauthcount; + uint8_t sid_authority[SIDAUTHSIZE]; /* ie not little endian */ +}; /* XXX: __attribute__((__packed__)); */ +typedef struct ntsid ntsid_t; + +#define sidsubauthcount(s) (s->sid_subauthcount) +#define sidlen(s) (sizeof (struct ntsid) + 4 * (s)->sid_subauthcount) +#define MAXSIDLEN (sizeof (struct ntsid) + 4 * KAUTH_NTSID_MAX_AUTHORITIES) +#define sidsub(s) ((uint32_t *)((char *)(s) + sizeof (struct ntsid))) + +/* + * MS' defined values for ace_type + */ +#define ACCESS_ALLOWED_ACE_TYPE 0x0 +#define ACCESS_DENIED_ACE_TYPE 0x1 +#define SYSTEM_AUDIT_ACE_TYPE 0x2 +#define SYSTEM_ALARM_ACE_TYPE 0x3 +#define ACCESS_ALLOWED_COMPOUND_ACE_TYPE 0x4 +#define ACCESS_ALLOWED_OBJECT_ACE_TYPE 0x5 +#define ACCESS_DENIED_OBJECT_ACE_TYPE 0x6 +#define SYSTEM_AUDIT_OBJECT_ACE_TYPE 0x7 +#define SYSTEM_ALARM_OBJECT_ACE_TYPE 0x8 +#define ACCESS_ALLOWED_CALLBACK_ACE_TYPE 0x9 +#define ACCESS_DENIED_CALLBACK_ACE_TYPE 0xA +#define ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE 0xB +#define ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE 0xC +#define SYSTEM_AUDIT_CALLBACK_ACE_TYPE 0xD +#define SYSTEM_ALARM_CALLBACK_ACE_TYPE 0xE +#define SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE 0xF +#define SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE 0x10 + +/* + * MS' defined values for ace_flags + */ +#define OBJECT_INHERIT_ACE_FLAG 0x01 +#define CONTAINER_INHERIT_ACE_FLAG 0x02 +#define NO_PROPAGATE_INHERIT_ACE_FLAG 0x04 +#define INHERIT_ONLY_ACE_FLAG 0x08 +#define INHERITED_ACE_FLAG 0x10 +#define UNDEF_ACE_FLAG 0x20 /* MS doesn't define it */ +#define VALID_INHERIT_ACE_FLAGS 0x1F +#define SUCCESSFUL_ACCESS_ACE_FLAG 0x40 +#define FAILED_ACCESS_ACE_FLAG 0x80 + +/* + * Set PATH/FILE information levels + */ +#define SMB_SFILEINFO_STANDARD 1 +#define SMB_SFILEINFO_EA_SET 2 +#define SMB_SFILEINFO_BASIC_INFO 0x101 +#define SMB_SFILEINFO_DISPOSITION_INFO 0x102 +#define SMB_SFILEINFO_ALLOCATION_INFO 0x103 +#define SMB_SFILEINFO_END_OF_FILE_INFO 0x104 +#define SMB_SFILEINFO_UNIX_BASIC 0x200 +#define SMB_SFILEINFO_UNIX_LINK 0x201 +#define SMB_SFILEINFO_UNIX_HLINK 0x203 +#define SMB_SFILEINFO_DIRECTORY_INFORMATION 1001 +#define SMB_SFILEINFO_FULL_DIRECTORY_INFORMATION 1002 +#define SMB_SFILEINFO_BOTH_DIRECTORY_INFORMATION 1003 +#define SMB_SFILEINFO_BASIC_INFORMATION 1004 +#define SMB_SFILEINFO_STANDARD_INFORMATION 1005 +#define SMB_SFILEINFO_INTERNAL_INFORMATION 1006 +#define SMB_SFILEINFO_EA_INFORMATION 1007 +#define SMB_SFILEINFO_ACCESS_INFORMATION 1008 +#define SMB_SFILEINFO_NAME_INFORMATION 1009 +#define SMB_SFILEINFO_RENAME_INFORMATION 1010 +#define SMB_SFILEINFO_LINK_INFORMATION 1011 +#define SMB_SFILEINFO_NAMES_INFORMATION 1012 +#define SMB_SFILEINFO_DISPOSITION_INFORMATION 1013 +#define SMB_SFILEINFO_POSITION_INFORMATION 1014 +#define SMB_SFILEINFO_1015 1015 /* ? */ +#define SMB_SFILEINFO_MODE_INFORMATION 1016 +#define SMB_SFILEINFO_ALIGNMENT_INFORMATION 1017 +#define SMB_SFILEINFO_ALL_INFORMATION 1018 +#define SMB_SFILEINFO_ALLOCATION_INFORMATION 1019 +#define SMB_SFILEINFO_END_OF_FILE_INFORMATION 1020 +#define SMB_SFILEINFO_ALT_NAME_INFORMATION 1021 +#define SMB_SFILEINFO_STREAM_INFORMATION 1022 +#define SMB_SFILEINFO_PIPE_INFORMATION 1023 +#define SMB_SFILEINFO_PIPE_LOCAL_INFORMATION 1024 +#define SMB_SFILEINFO_PIPE_REMOTE_INFORMATION 1025 +#define SMB_SFILEINFO_MAILSLOT_QUERY_INFORMATION 1026 +#define SMB_SFILEINFO_MAILSLOT_SET_INFORMATION 1027 +#define SMB_SFILEINFO_COMPRESSION_INFORMATION 1028 +#define SMB_SFILEINFO_OBJECT_ID_INFORMATION 1029 +#define SMB_SFILEINFO_COMPLETION_INFORMATION 1030 +#define SMB_SFILEINFO_MOVE_CLUSTER_INFORMATION 1031 +#define SMB_SFILEINFO_QUOTA_INFORMATION 1032 +#define SMB_SFILEINFO_REPARSE_POINT_INFORMATION 1033 +#define SMB_SFILEINFO_NETWORK_OPEN_INFORMATION 1034 +#define SMB_SFILEINFO_ATTRIBUTE_TAG_INFORMATION 1035 +#define SMB_SFILEINFO_TRACKING_INFORMATION 1036 +#define SMB_SFILEINFO_MAXIMUM_INFORMATION 1037 + +/* + * LOCKING_ANDX LockType flags + */ +#define SMB_LOCKING_ANDX_SHARED_LOCK 0x01 +#define SMB_LOCKING_ANDX_OPLOCK_RELEASE 0x02 +#define SMB_LOCKING_ANDX_CHANGE_LOCKTYPE 0x04 +#define SMB_LOCKING_ANDX_CANCEL_LOCK 0x08 +#define SMB_LOCKING_ANDX_LARGE_FILES 0x10 + +/* + * Some names length limitations. Some of them aren't declared by specs, + * but we need reasonable limits. + */ +#define SMB_MAXSRVNAMELEN 15 /* NetBIOS limit */ +#define SMB_MAXUSERNAMELEN 128 +#define SMB_MAXPASSWORDLEN 128 +#define SMB_MAXSHARENAMELEN 128 +#define SMB_MAXPKTLEN 0x1FFFF +#define SMB_MAXCHALLENGELEN 8 +#define SMB_MAXFNAMELEN 255 /* Keep in sync with MAXNAMLEN */ + +#define SMB_RCNDELAY 2 /* seconds between reconnect attempts */ +/* + * leave this zero - we can't ssecond guess server side effects of + * duplicate ops, this isn't nfs! + */ +#define SMBMAXRESTARTS 0 +#define SMB_MAXSETUPWORDS 3 /* max # of setup words in trans/t2 */ + +/* + * Error classes + */ +#define SMBSUCCESS 0x00 +#define ERRDOS 0x01 +#define ERRSRV 0x02 +#define ERRHRD 0x03 /* Error is an hardware error. */ +#define ERRCMD 0xFF /* Command was not in the "SMB" format. */ + +/* + * Error codes for the ERRDOS class + */ +#define ERRbadfunc 1 /* Invalid function */ +#define ERRbadfile 2 /* File not found (last component) */ +#define ERRbadpath 3 /* Directory invalid */ +#define ERRnofids 4 /* Too many open files */ +#define ERRnoaccess 5 /* Access denied */ +#define ERRbadfid 6 /* Invalid file handle */ +#define ERRbadmcb 7 /* Memory control blocks destroyed (huh ?) */ +#define ERRnomem 8 /* Insufficient memory */ +#define ERRbadmem 9 /* Invalid memory block address */ +#define ERRbadenv 10 /* Invalid environment */ +#define ERRbadformat 11 /* Invalid format */ +#define ERRbadaccess 12 /* Invalid open mode */ +#define ERRbaddata 13 /* Invalid data */ +#define ERRoutofmem 14 /* out of memory */ +#define ERRbaddrive 15 /* Invalid drive specified */ +#define ERRremcd 16 /* An attempt to delete current directory */ +#define ERRdiffdevice 17 /* cross fs rename/move */ +#define ERRnofiles 18 /* no more files found in file search */ +#define ERRwriteprotect 19 +#define ERRnotready 21 +#define ERRbadcmd 22 +#define ERRcrc 23 +#define ERRbadlength 24 +#define ERRsectornotfound 27 +#define ERRbadshare 32 /* Share mode can't be granted */ +#define ERRlock 33 /* Lock conflicts with existing lock */ +#define ERRwrongdisk 34 +#define ERRhandleeof 38 +#define ERRunsup 50 /* unsupported - Win 95 */ +#define ERRnetnamedel 64 +#define ERRnoipc 66 /* ipc unsupported */ +#define ERRnosuchshare 67 /* invalid share name */ +#define ERRtoomanynames 68 +#define ERRfilexists 80 /* requested file name already exists */ +#define ERRinvalidparam 87 +#define ERRcannotopen 110 /* cannot open the file */ +#define ERRinsufficientbuffer 122 +#define ERRinvalidname 123 +#define ERRunknownlevel 124 +#define ERRdirnotempty 145 +#define ERRnotlocked 158 /* region was not locked by this context */ +#define ERRrename 183 +#define ERRbadpipe 230 /* named pipe invalid */ +#define ERRpipebusy 231 /* all pipe instances are busy */ +#define ERRpipeclosing 232 /* close in progress */ +#define ERRnotconnected 233 /* nobody on other end of pipe */ +#define ERRmoredata 234 /* more data to be returned */ +#define ERRnomoreitems 259 +#define ERRbaddirectory 267 /* invalid directory name */ +#define ERReasunsupported 282 /* extended attributes not supported */ +#define ERRlogonfailure 1326 +#define ERRbuftoosmall 2123 +#define ERRunknownipc 2142 +#define ERRnosuchprintjob 2151 +#define ERRinvgroup 2455 + +/* + * Error codes for the ERRSRV class + */ +#define ERRerror 1 /* Non-specific error code */ +#define ERRbadpw 2 /* Bad password */ +#define ERRbadtype 3 /* reserved */ +#define ERRaccess 4 /* client doesn't have enough access rights */ +#define ERRinvnid 5 /* The Tid specified in a command is invalid */ +#define ERRinvnetname 6 /* Invalid server name in the tree connect */ +#define ERRinvdevice 7 /* Printer and not printer devices are mixed */ +#define ERRqfull 49 /* Print queue full */ +#define ERRqtoobig 50 /* Print queue full - no space */ +#define ERRinvpfid 52 /* Invalid print file FID */ +#define ERRsmbcmd 64 /* The server did not recognise the command */ +#define ERRsrverror 65 /* The server encountered and internal error */ +#define ERRfilespecs 67 /* The Fid and path name contains an */ + /* invalid combination */ +#define ERRbadpermits 69 /* Access mode invalid */ +#define ERRsetattrmode 71 /* Attribute mode invalid */ +#define ERRpaused 81 /* Server is paused */ +#define ERRmsgoff 82 /* Not receiving messages */ +#define ERRnoroom 83 /* No room to buffer message */ +#define ERRrmuns 87 /* Too many remote user names */ +#define ERRtimeout 88 /* Operation timed out */ +#define ERRnoresource 89 /* No resources currently available for req */ +#define ERRtoomanyuids 90 /* Too many UIDs active on this session */ +#define ERRbaduid 91 /* The UID is not known in this session */ +#define ERRusempx 250 /* Temporarily unable to support Raw, */ + /* use MPX mode */ +#define ERRusestd 251 /* Temporarily unable to support Raw, */ + /* use stdandard r/w */ +#define ERRcontmpx 252 /* Continue in MPX mode */ +#define ERRacctexpired 2239 +#define ERRnosupport 65535 /* Invalid function */ + +/* + * Error codes for the ERRHRD class + */ +#define ERRnowrite 19 /* write protected media */ +#define ERRbadunit 20 /* Unknown unit */ +#define ERRnotready 21 /* Drive not ready */ +#define ERRbadcmd 22 /* Unknown command */ +#define ERRdata 23 /* Data error (CRC) */ +#define ERRbadreq 24 /* Bad request structure length */ +#define ERRseek 25 /* Seek error */ +#define ERRbadmedia 26 /* Unknown media type */ +#define ERRbadsector 27 /* Sector not found */ +#define ERRnopaper 28 /* Printer out of paper */ +#define ERRwrite 29 /* Write fault */ +#define ERRread 30 /* Read fault */ +#define ERRgeneral 31 /* General failure */ +#define ERRbadshare 32 /* A open conflicts with an existing open */ +#define ERRlock 33 /* lock/unlock conflict */ +#define ERRwrongdisk 34 /* The wrong disk was found in a drive */ +#define ERRFCBunavail 35 /* No FCBs available */ +#define ERRsharebufexc 36 /* A sharing buffer has been exceeded */ +#define ERRdiskfull 39 + +/* + * RAP error codes (it seems that they returned not only by RAP) + */ +#define SMB_ERROR_ACCESS_DENIED 5 +#define SMB_ERROR_NETWORK_ACCESS_DENIED 65 +#define SMB_ERROR_MORE_DATA ERRmoredata + +/* + * An INCOMPLETE list of 32 bit error codes + * For more detail see MSDN and ntstatus.h in the MS DDK + * + * XXX - these should have the severity and "customer defined" fields + * added back in, and smb_maperr32() shouldn't mask those fields out; + * 0x80000005 is STATUS_BUFFER_OVERFLOW, with 0xC0000000 is + * STATUS_ACCESS_VIOLATION, and we need to distinguish between them. + * We use STATUS_BUFFER_OVERFLOW, and need to know its exact value, + * so we #define it correctly here; don't strip off the leading + * 0x80000000 from it! + */ +#define NT_STATUS_BUFFER_OVERFLOW 0x80000005 +#define NT_STATUS_UNSUCCESSFUL 0x0001 +#define NT_STATUS_NOT_IMPLEMENTED 0x0002 +#define NT_STATUS_INVALID_INFO_CLASS 0x0003 +#define NT_STATUS_INFO_LENGTH_MISMATCH 0x0004 +#define NT_STATUS_ACCESS_VIOLATION 0x0005 +#define NT_STATUS_IN_PAGE_ERROR 0x0006 +#define NT_STATUS_PAGEFILE_QUOTA 0x0007 +#define NT_STATUS_INVALID_HANDLE 0x0008 +#define NT_STATUS_BAD_INITIAL_STACK 0x0009 +#define NT_STATUS_BAD_INITIAL_PC 0x000a +#define NT_STATUS_INVALID_CID 0x000b +#define NT_STATUS_TIMER_NOT_CANCELED 0x000c +#define NT_STATUS_INVALID_PARAMETER 0x000d +#define NT_STATUS_NO_SUCH_DEVICE 0x000e +#define NT_STATUS_NO_SUCH_FILE 0x000f +#define NT_STATUS_INVALID_DEVICE_REQUEST 0x0010 +#define NT_STATUS_END_OF_FILE 0x0011 +#define NT_STATUS_WRONG_VOLUME 0x0012 +#define NT_STATUS_NO_MEDIA_IN_DEVICE 0x0013 +#define NT_STATUS_UNRECOGNIZED_MEDIA 0x0014 +#define NT_STATUS_NONEXISTENT_SECTOR 0x0015 +#define NT_STATUS_MORE_PROCESSING_REQUIRED 0x0016 +#define NT_STATUS_NO_MEMORY 0x0017 +#define NT_STATUS_CONFLICTING_ADDRESSES 0x0018 +#define NT_STATUS_NOT_MAPPED_VIEW 0x0019 +#define NT_STATUS_UNABLE_TO_FREE_VM 0x001a +#define NT_STATUS_UNABLE_TO_DELETE_SECTION 0x001b +#define NT_STATUS_INVALID_SYSTEM_SERVICE 0x001c +#define NT_STATUS_ILLEGAL_INSTRUCTION 0x001d +#define NT_STATUS_INVALID_LOCK_SEQUENCE 0x001e +#define NT_STATUS_INVALID_VIEW_SIZE 0x001f +#define NT_STATUS_INVALID_FILE_FOR_SECTION 0x0020 +#define NT_STATUS_ALREADY_COMMITTED 0x0021 +#define NT_STATUS_ACCESS_DENIED 0x0022 +#define NT_STATUS_BUFFER_TOO_SMALL 0x0023 +#define NT_STATUS_OBJECT_TYPE_MISMATCH 0x0024 +#define NT_STATUS_NONCONTINUABLE_EXCEPTION 0x0025 +#define NT_STATUS_INVALID_DISPOSITION 0x0026 +#define NT_STATUS_UNWIND 0x0027 +#define NT_STATUS_BAD_STACK 0x0028 +#define NT_STATUS_INVALID_UNWIND_TARGET 0x0029 +#define NT_STATUS_NOT_LOCKED 0x002a +#define NT_STATUS_PARITY_ERROR 0x002b +#define NT_STATUS_UNABLE_TO_DECOMMIT_VM 0x002c +#define NT_STATUS_NOT_COMMITTED 0x002d +#define NT_STATUS_INVALID_PORT_ATTRIBUTES 0x002e +#define NT_STATUS_PORT_MESSAGE_TOO_LONG 0x002f +#define NT_STATUS_INVALID_PARAMETER_MIX 0x0030 +#define NT_STATUS_INVALID_QUOTA_LOWER 0x0031 +#define NT_STATUS_DISK_CORRUPT_ERROR 0x0032 +#define NT_STATUS_OBJECT_NAME_INVALID 0x0033 +#define NT_STATUS_OBJECT_NAME_NOT_FOUND 0x0034 +#define NT_STATUS_OBJECT_NAME_COLLISION 0x0035 +#define NT_STATUS_HANDLE_NOT_WAITABLE 0x0036 +#define NT_STATUS_PORT_DISCONNECTED 0x0037 +#define NT_STATUS_DEVICE_ALREADY_ATTACHED 0x0038 +#define NT_STATUS_OBJECT_PATH_INVALID 0x0039 +#define NT_STATUS_OBJECT_PATH_NOT_FOUND 0x003a +#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD 0x003b +#define NT_STATUS_DATA_OVERRUN 0x003c +#define NT_STATUS_DATA_LATE_ERROR 0x003d +#define NT_STATUS_DATA_ERROR 0x003e +#define NT_STATUS_CRC_ERROR 0x003f +#define NT_STATUS_SECTION_TOO_BIG 0x0040 +#define NT_STATUS_PORT_CONNECTION_REFUSED 0x0041 +#define NT_STATUS_INVALID_PORT_HANDLE 0x0042 +#define NT_STATUS_SHARING_VIOLATION 0x0043 +#define NT_STATUS_QUOTA_EXCEEDED 0x0044 +#define NT_STATUS_INVALID_PAGE_PROTECTION 0x0045 +#define NT_STATUS_MUTANT_NOT_OWNED 0x0046 +#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED 0x0047 +#define NT_STATUS_PORT_ALREADY_SET 0x0048 +#define NT_STATUS_SECTION_NOT_IMAGE 0x0049 +#define NT_STATUS_SUSPEND_COUNT_EXCEEDED 0x004a +#define NT_STATUS_THREAD_IS_TERMINATING 0x004b +#define NT_STATUS_BAD_WORKING_SET_LIMIT 0x004c +#define NT_STATUS_INCOMPATIBLE_FILE_MAP 0x004d +#define NT_STATUS_SECTION_PROTECTION 0x004e +#define NT_STATUS_EAS_NOT_SUPPORTED 0x004f +#define NT_STATUS_EA_TOO_LARGE 0x0050 +#define NT_STATUS_NONEXISTENT_EA_ENTRY 0x0051 +#define NT_STATUS_NO_EAS_ON_FILE 0x0052 +#define NT_STATUS_EA_CORRUPT_ERROR 0x0053 +#define NT_STATUS_FILE_LOCK_CONFLICT 0x0054 +#define NT_STATUS_LOCK_NOT_GRANTED 0x0055 +#define NT_STATUS_DELETE_PENDING 0x0056 +#define NT_STATUS_CTL_FILE_NOT_SUPPORTED 0x0057 +#define NT_STATUS_UNKNOWN_REVISION 0x0058 +#define NT_STATUS_REVISION_MISMATCH 0x0059 +#define NT_STATUS_INVALID_OWNER 0x005a +#define NT_STATUS_INVALID_PRIMARY_GROUP 0x005b +#define NT_STATUS_NO_IMPERSONATION_TOKEN 0x005c +#define NT_STATUS_CANT_DISABLE_MANDATORY 0x005d +#define NT_STATUS_NO_LOGON_SERVERS 0x005e +#define NT_STATUS_NO_SUCH_LOGON_SESSION 0x005f +#define NT_STATUS_NO_SUCH_PRIVILEGE 0x0060 +#define NT_STATUS_PRIVILEGE_NOT_HELD 0x0061 +#define NT_STATUS_INVALID_ACCOUNT_NAME 0x0062 +#define NT_STATUS_USER_EXISTS 0x0063 +#define NT_STATUS_NO_SUCH_USER 0x0064 +#define NT_STATUS_GROUP_EXISTS 0x0065 +#define NT_STATUS_NO_SUCH_GROUP 0x0066 +#define NT_STATUS_MEMBER_IN_GROUP 0x0067 +#define NT_STATUS_MEMBER_NOT_IN_GROUP 0x0068 +#define NT_STATUS_LAST_ADMIN 0x0069 +#define NT_STATUS_WRONG_PASSWORD 0x006a +#define NT_STATUS_ILL_FORMED_PASSWORD 0x006b +#define NT_STATUS_PASSWORD_RESTRICTION 0x006c +#define NT_STATUS_LOGON_FAILURE 0x006d +#define NT_STATUS_ACCOUNT_RESTRICTION 0x006e +#define NT_STATUS_INVALID_LOGON_HOURS 0x006f +#define NT_STATUS_INVALID_WORKSTATION 0x0070 +#define NT_STATUS_PASSWORD_EXPIRED 0x0071 +#define NT_STATUS_ACCOUNT_DISABLED 0x0072 +#define NT_STATUS_NONE_MAPPED 0x0073 +#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED 0x0074 +#define NT_STATUS_LUIDS_EXHAUSTED 0x0075 +#define NT_STATUS_INVALID_SUB_AUTHORITY 0x0076 +#define NT_STATUS_INVALID_ACL 0x0077 +#define NT_STATUS_INVALID_SID 0x0078 +#define NT_STATUS_INVALID_SECURITY_DESCR 0x0079 +#define NT_STATUS_PROCEDURE_NOT_FOUND 0x007a +#define NT_STATUS_INVALID_IMAGE_FORMAT 0x007b +#define NT_STATUS_NO_TOKEN 0x007c +#define NT_STATUS_BAD_INHERITANCE_ACL 0x007d +#define NT_STATUS_RANGE_NOT_LOCKED 0x007e +#define NT_STATUS_DISK_FULL 0x007f +#define NT_STATUS_SERVER_DISABLED 0x0080 +#define NT_STATUS_SERVER_NOT_DISABLED 0x0081 +#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED 0x0082 +#define NT_STATUS_GUIDS_EXHAUSTED 0x0083 +#define NT_STATUS_INVALID_ID_AUTHORITY 0x0084 +#define NT_STATUS_AGENTS_EXHAUSTED 0x0085 +#define NT_STATUS_INVALID_VOLUME_LABEL 0x0086 +#define NT_STATUS_SECTION_NOT_EXTENDED 0x0087 +#define NT_STATUS_NOT_MAPPED_DATA 0x0088 +#define NT_STATUS_RESOURCE_DATA_NOT_FOUND 0x0089 +#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND 0x008a +#define NT_STATUS_RESOURCE_NAME_NOT_FOUND 0x008b +#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED 0x008c +#define NT_STATUS_FLOAT_DENORMAL_OPERAND 0x008d +#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO 0x008e +#define NT_STATUS_FLOAT_INEXACT_RESULT 0x008f +#define NT_STATUS_FLOAT_INVALID_OPERATION 0x0090 +#define NT_STATUS_FLOAT_OVERFLOW 0x0091 +#define NT_STATUS_FLOAT_STACK_CHECK 0x0092 +#define NT_STATUS_FLOAT_UNDERFLOW 0x0093 +#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO 0x0094 +#define NT_STATUS_INTEGER_OVERFLOW 0x0095 +#define NT_STATUS_PRIVILEGED_INSTRUCTION 0x0096 +#define NT_STATUS_TOO_MANY_PAGING_FILES 0x0097 +#define NT_STATUS_FILE_INVALID 0x0098 +#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED 0x0099 +#define NT_STATUS_INSUFFICIENT_RESOURCES 0x009a +#define NT_STATUS_DFS_EXIT_PATH_FOUND 0x009b +#define NT_STATUS_DEVICE_DATA_ERROR 0x009c +#define NT_STATUS_DEVICE_NOT_CONNECTED 0x009d +#define NT_STATUS_DEVICE_POWER_FAILURE 0x009e +#define NT_STATUS_FREE_VM_NOT_AT_BASE 0x009f +#define NT_STATUS_MEMORY_NOT_ALLOCATED 0x00a0 +#define NT_STATUS_WORKING_SET_QUOTA 0x00a1 +#define NT_STATUS_MEDIA_WRITE_PROTECTED 0x00a2 +#define NT_STATUS_DEVICE_NOT_READY 0x00a3 +#define NT_STATUS_INVALID_GROUP_ATTRIBUTES 0x00a4 +#define NT_STATUS_BAD_IMPERSONATION_LEVEL 0x00a5 +#define NT_STATUS_CANT_OPEN_ANONYMOUS 0x00a6 +#define NT_STATUS_BAD_VALIDATION_CLASS 0x00a7 +#define NT_STATUS_BAD_TOKEN_TYPE 0x00a8 +#define NT_STATUS_BAD_MASTER_BOOT_RECORD 0x00a9 +#define NT_STATUS_INSTRUCTION_MISALIGNMENT 0x00aa +#define NT_STATUS_INSTANCE_NOT_AVAILABLE 0x00ab +#define NT_STATUS_PIPE_NOT_AVAILABLE 0x00ac +#define NT_STATUS_INVALID_PIPE_STATE 0x00ad +#define NT_STATUS_PIPE_BUSY 0x00ae +#define NT_STATUS_ILLEGAL_FUNCTION 0x00af +#define NT_STATUS_PIPE_DISCONNECTED 0x00b0 +#define NT_STATUS_PIPE_CLOSING 0x00b1 +#define NT_STATUS_PIPE_CONNECTED 0x00b2 +#define NT_STATUS_PIPE_LISTENING 0x00b3 +#define NT_STATUS_INVALID_READ_MODE 0x00b4 +#define NT_STATUS_IO_TIMEOUT 0x00b5 +#define NT_STATUS_FILE_FORCED_CLOSED 0x00b6 +#define NT_STATUS_PROFILING_NOT_STARTED 0x00b7 +#define NT_STATUS_PROFILING_NOT_STOPPED 0x00b8 +#define NT_STATUS_COULD_NOT_INTERPRET 0x00b9 +#define NT_STATUS_FILE_IS_A_DIRECTORY 0x00ba +#define NT_STATUS_NOT_SUPPORTED 0x00bb +#define NT_STATUS_REMOTE_NOT_LISTENING 0x00bc +#define NT_STATUS_DUPLICATE_NAME 0x00bd +#define NT_STATUS_BAD_NETWORK_PATH 0x00be +#define NT_STATUS_NETWORK_BUSY 0x00bf +#define NT_STATUS_DEVICE_DOES_NOT_EXIST 0x00c0 +#define NT_STATUS_TOO_MANY_COMMANDS 0x00c1 +#define NT_STATUS_ADAPTER_HARDWARE_ERROR 0x00c2 +#define NT_STATUS_INVALID_NETWORK_RESPONSE 0x00c3 +#define NT_STATUS_UNEXPECTED_NETWORK_ERROR 0x00c4 +#define NT_STATUS_BAD_REMOTE_ADAPTER 0x00c5 +#define NT_STATUS_PRINT_QUEUE_FULL 0x00c6 +#define NT_STATUS_NO_SPOOL_SPACE 0x00c7 +#define NT_STATUS_PRINT_CANCELLED 0x00c8 +#define NT_STATUS_NETWORK_NAME_DELETED 0x00c9 +#define NT_STATUS_NETWORK_ACCESS_DENIED 0x00ca +#define NT_STATUS_BAD_DEVICE_TYPE 0x00cb +#define NT_STATUS_BAD_NETWORK_NAME 0x00cc +#define NT_STATUS_TOO_MANY_NAMES 0x00cd +#define NT_STATUS_TOO_MANY_SESSIONS 0x00ce +#define NT_STATUS_SHARING_PAUSED 0x00cf +#define NT_STATUS_REQUEST_NOT_ACCEPTED 0x00d0 +#define NT_STATUS_REDIRECTOR_PAUSED 0x00d1 +#define NT_STATUS_NET_WRITE_FAULT 0x00d2 +#define NT_STATUS_PROFILING_AT_LIMIT 0x00d3 +#define NT_STATUS_NOT_SAME_DEVICE 0x00d4 +#define NT_STATUS_FILE_RENAMED 0x00d5 +#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED 0x00d6 +#define NT_STATUS_NO_SECURITY_ON_OBJECT 0x00d7 +#define NT_STATUS_CANT_WAIT 0x00d8 +#define NT_STATUS_PIPE_EMPTY 0x00d9 +#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO 0x00da +#define NT_STATUS_CANT_TERMINATE_SELF 0x00db +#define NT_STATUS_INVALID_SERVER_STATE 0x00dc +#define NT_STATUS_INVALID_DOMAIN_STATE 0x00dd +#define NT_STATUS_INVALID_DOMAIN_ROLE 0x00de +#define NT_STATUS_NO_SUCH_DOMAIN 0x00df +#define NT_STATUS_DOMAIN_EXISTS 0x00e0 +#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED 0x00e1 +#define NT_STATUS_OPLOCK_NOT_GRANTED 0x00e2 +#define NT_STATUS_INVALID_OPLOCK_PROTOCOL 0x00e3 +#define NT_STATUS_INTERNAL_DB_CORRUPTION 0x00e4 +#define NT_STATUS_INTERNAL_ERROR 0x00e5 +#define NT_STATUS_GENERIC_NOT_MAPPED 0x00e6 +#define NT_STATUS_BAD_DESCRIPTOR_FORMAT 0x00e7 +#define NT_STATUS_INVALID_USER_BUFFER 0x00e8 +#define NT_STATUS_UNEXPECTED_IO_ERROR 0x00e9 +#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR 0x00ea +#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR 0x00eb +#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR 0x00ec +#define NT_STATUS_NOT_LOGON_PROCESS 0x00ed +#define NT_STATUS_LOGON_SESSION_EXISTS 0x00ee +#define NT_STATUS_INVALID_PARAMETER_1 0x00ef +#define NT_STATUS_INVALID_PARAMETER_2 0x00f0 +#define NT_STATUS_INVALID_PARAMETER_3 0x00f1 +#define NT_STATUS_INVALID_PARAMETER_4 0x00f2 +#define NT_STATUS_INVALID_PARAMETER_5 0x00f3 +#define NT_STATUS_INVALID_PARAMETER_6 0x00f4 +#define NT_STATUS_INVALID_PARAMETER_7 0x00f5 +#define NT_STATUS_INVALID_PARAMETER_8 0x00f6 +#define NT_STATUS_INVALID_PARAMETER_9 0x00f7 +#define NT_STATUS_INVALID_PARAMETER_10 0x00f8 +#define NT_STATUS_INVALID_PARAMETER_11 0x00f9 +#define NT_STATUS_INVALID_PARAMETER_12 0x00fa +#define NT_STATUS_REDIRECTOR_NOT_STARTED 0x00fb +#define NT_STATUS_REDIRECTOR_STARTED 0x00fc +#define NT_STATUS_STACK_OVERFLOW 0x00fd +#define NT_STATUS_NO_SUCH_PACKAGE 0x00fe +#define NT_STATUS_BAD_FUNCTION_TABLE 0x00ff +#define NT_STATUS_VARIABLE_NOT_FOUND 0x0100 +#define NT_STATUS_DIRECTORY_NOT_EMPTY 0x0101 +#define NT_STATUS_FILE_CORRUPT_ERROR 0x0102 +#define NT_STATUS_NOT_A_DIRECTORY 0x0103 +#define NT_STATUS_BAD_LOGON_SESSION_STATE 0x0104 +#define NT_STATUS_LOGON_SESSION_COLLISION 0x0105 +#define NT_STATUS_NAME_TOO_LONG 0x0106 +#define NT_STATUS_FILES_OPEN 0x0107 +#define NT_STATUS_CONNECTION_IN_USE 0x0108 +#define NT_STATUS_MESSAGE_NOT_FOUND 0x0109 +#define NT_STATUS_PROCESS_IS_TERMINATING 0x010a +#define NT_STATUS_INVALID_LOGON_TYPE 0x010b +#define NT_STATUS_NO_GUID_TRANSLATION 0x010c +#define NT_STATUS_CANNOT_IMPERSONATE 0x010d +#define NT_STATUS_IMAGE_ALREADY_LOADED 0x010e +#define NT_STATUS_ABIOS_NOT_PRESENT 0x010f +#define NT_STATUS_ABIOS_LID_NOT_EXIST 0x0110 +#define NT_STATUS_ABIOS_LID_ALREADY_OWNED 0x0111 +#define NT_STATUS_ABIOS_NOT_LID_OWNER 0x0112 +#define NT_STATUS_ABIOS_INVALID_COMMAND 0x0113 +#define NT_STATUS_ABIOS_INVALID_LID 0x0114 +#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE 0x0115 +#define NT_STATUS_ABIOS_INVALID_SELECTOR 0x0116 +#define NT_STATUS_NO_LDT 0x0117 +#define NT_STATUS_INVALID_LDT_SIZE 0x0118 +#define NT_STATUS_INVALID_LDT_OFFSET 0x0119 +#define NT_STATUS_INVALID_LDT_DESCRIPTOR 0x011a +#define NT_STATUS_INVALID_IMAGE_NE_FORMAT 0x011b +#define NT_STATUS_RXACT_INVALID_STATE 0x011c +#define NT_STATUS_RXACT_COMMIT_FAILURE 0x011d +#define NT_STATUS_MAPPED_FILE_SIZE_ZERO 0x011e +#define NT_STATUS_TOO_MANY_OPENED_FILES 0x011f +#define NT_STATUS_CANCELLED 0x0120 +#define NT_STATUS_CANNOT_DELETE 0x0121 +#define NT_STATUS_INVALID_COMPUTER_NAME 0x0122 +#define NT_STATUS_FILE_DELETED 0x0123 +#define NT_STATUS_SPECIAL_ACCOUNT 0x0124 +#define NT_STATUS_SPECIAL_GROUP 0x0125 +#define NT_STATUS_SPECIAL_USER 0x0126 +#define NT_STATUS_MEMBERS_PRIMARY_GROUP 0x0127 +#define NT_STATUS_FILE_CLOSED 0x0128 +#define NT_STATUS_TOO_MANY_THREADS 0x0129 +#define NT_STATUS_THREAD_NOT_IN_PROCESS 0x012a +#define NT_STATUS_TOKEN_ALREADY_IN_USE 0x012b +#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED 0x012c +#define NT_STATUS_COMMITMENT_LIMIT 0x012d +#define NT_STATUS_INVALID_IMAGE_LE_FORMAT 0x012e +#define NT_STATUS_INVALID_IMAGE_NOT_MZ 0x012f +#define NT_STATUS_INVALID_IMAGE_PROTECT 0x0130 +#define NT_STATUS_INVALID_IMAGE_WIN_16 0x0131 +#define NT_STATUS_LOGON_SERVER_CONFLICT 0x0132 +#define NT_STATUS_TIME_DIFFERENCE_AT_DC 0x0133 +#define NT_STATUS_SYNCHRONIZATION_REQUIRED 0x0134 +#define NT_STATUS_DLL_NOT_FOUND 0x0135 +#define NT_STATUS_OPEN_FAILED 0x0136 +#define NT_STATUS_IO_PRIVILEGE_FAILED 0x0137 +#define NT_STATUS_ORDINAL_NOT_FOUND 0x0138 +#define NT_STATUS_ENTRYPOINT_NOT_FOUND 0x0139 +#define NT_STATUS_CONTROL_C_EXIT 0x013a +#define NT_STATUS_LOCAL_DISCONNECT 0x013b +#define NT_STATUS_REMOTE_DISCONNECT 0x013c +#define NT_STATUS_REMOTE_RESOURCES 0x013d +#define NT_STATUS_LINK_FAILED 0x013e +#define NT_STATUS_LINK_TIMEOUT 0x013f +#define NT_STATUS_INVALID_CONNECTION 0x0140 +#define NT_STATUS_INVALID_ADDRESS 0x0141 +#define NT_STATUS_DLL_INIT_FAILED 0x0142 +#define NT_STATUS_MISSING_SYSTEMFILE 0x0143 +#define NT_STATUS_UNHANDLED_EXCEPTION 0x0144 +#define NT_STATUS_APP_INIT_FAILURE 0x0145 +#define NT_STATUS_PAGEFILE_CREATE_FAILED 0x0146 +#define NT_STATUS_NO_PAGEFILE 0x0147 +#define NT_STATUS_INVALID_LEVEL 0x0148 +#define NT_STATUS_WRONG_PASSWORD_CORE 0x0149 +#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT 0x014a +#define NT_STATUS_PIPE_BROKEN 0x014b +#define NT_STATUS_REGISTRY_CORRUPT 0x014c +#define NT_STATUS_REGISTRY_IO_FAILED 0x014d +#define NT_STATUS_NO_EVENT_PAIR 0x014e +#define NT_STATUS_UNRECOGNIZED_VOLUME 0x014f +#define NT_STATUS_SERIAL_NO_DEVICE_INITED 0x0150 +#define NT_STATUS_NO_SUCH_ALIAS 0x0151 +#define NT_STATUS_MEMBER_NOT_IN_ALIAS 0x0152 +#define NT_STATUS_MEMBER_IN_ALIAS 0x0153 +#define NT_STATUS_ALIAS_EXISTS 0x0154 +#define NT_STATUS_LOGON_NOT_GRANTED 0x0155 +#define NT_STATUS_TOO_MANY_SECRETS 0x0156 +#define NT_STATUS_SECRET_TOO_LONG 0x0157 +#define NT_STATUS_INTERNAL_DB_ERROR 0x0158 +#define NT_STATUS_FULLSCREEN_MODE 0x0159 +#define NT_STATUS_TOO_MANY_CONTEXT_IDS 0x015a +#define NT_STATUS_LOGON_TYPE_NOT_GRANTED 0x015b +#define NT_STATUS_NOT_REGISTRY_FILE 0x015c +#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED 0x015d +#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR 0x015e +#define NT_STATUS_FT_MISSING_MEMBER 0x015f +#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY 0x0160 +#define NT_STATUS_ILLEGAL_CHARACTER 0x0161 +#define NT_STATUS_UNMAPPABLE_CHARACTER 0x0162 +#define NT_STATUS_UNDEFINED_CHARACTER 0x0163 +#define NT_STATUS_FLOPPY_VOLUME 0x0164 +#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND 0x0165 +#define NT_STATUS_FLOPPY_WRONG_CYLINDER 0x0166 +#define NT_STATUS_FLOPPY_UNKNOWN_ERROR 0x0167 +#define NT_STATUS_FLOPPY_BAD_REGISTERS 0x0168 +#define NT_STATUS_DISK_RECALIBRATE_FAILED 0x0169 +#define NT_STATUS_DISK_OPERATION_FAILED 0x016a +#define NT_STATUS_DISK_RESET_FAILED 0x016b +#define NT_STATUS_SHARED_IRQ_BUSY 0x016c +#define NT_STATUS_FT_ORPHANING 0x016d +#define NT_STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT 0x016e +#define NT_STATUS_16F 0x016f +#define NT_STATUS_170 0x0170 +#define NT_STATUS_171 0x0171 +#define NT_STATUS_PARTITION_FAILURE 0x0172 +#define NT_STATUS_INVALID_BLOCK_LENGTH 0x0173 +#define NT_STATUS_DEVICE_NOT_PARTITIONED 0x0174 +#define NT_STATUS_UNABLE_TO_LOCK_MEDIA 0x0175 +#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA 0x0176 +#define NT_STATUS_EOM_OVERFLOW 0x0177 +#define NT_STATUS_NO_MEDIA 0x0178 +#define NT_STATUS_179 0x0179 +#define NT_STATUS_NO_SUCH_MEMBER 0x017a +#define NT_STATUS_INVALID_MEMBER 0x017b +#define NT_STATUS_KEY_DELETED 0x017c +#define NT_STATUS_NO_LOG_SPACE 0x017d +#define NT_STATUS_TOO_MANY_SIDS 0x017e +#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED 0x017f +#define NT_STATUS_KEY_HAS_CHILDREN 0x0180 +#define NT_STATUS_CHILD_MUST_BE_VOLATILE 0x0181 +#define NT_STATUS_DEVICE_CONFIGURATION_ERROR 0x0182 +#define NT_STATUS_DRIVER_INTERNAL_ERROR 0x0183 +#define NT_STATUS_INVALID_DEVICE_STATE 0x0184 +#define NT_STATUS_IO_DEVICE_ERROR 0x0185 +#define NT_STATUS_DEVICE_PROTOCOL_ERROR 0x0186 +#define NT_STATUS_BACKUP_CONTROLLER 0x0187 +#define NT_STATUS_LOG_FILE_FULL 0x0188 +#define NT_STATUS_TOO_LATE 0x0189 +#define NT_STATUS_NO_TRUST_LSA_SECRET 0x018a +#define NT_STATUS_NO_TRUST_SAM_ACCOUNT 0x018b +#define NT_STATUS_TRUSTED_DOMAIN_FAILURE 0x018c +#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 0x018d +#define NT_STATUS_EVENTLOG_FILE_CORRUPT 0x018e +#define NT_STATUS_EVENTLOG_CANT_START 0x018f +#define NT_STATUS_TRUST_FAILURE 0x0190 +#define NT_STATUS_MUTANT_LIMIT_EXCEEDED 0x0191 +#define NT_STATUS_NETLOGON_NOT_STARTED 0x0192 +#define NT_STATUS_ACCOUNT_EXPIRED 0x0193 +#define NT_STATUS_POSSIBLE_DEADLOCK 0x0194 +#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT 0x0195 +#define NT_STATUS_REMOTE_SESSION_LIMIT 0x0196 +#define NT_STATUS_EVENTLOG_FILE_CHANGED 0x0197 +#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 0x0198 +#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 0x0199 +#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 0x019a +#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT 0x019b +#define NT_STATUS_FS_DRIVER_REQUIRED 0x019c +#define NT_STATUS_NO_USER_SESSION_KEY 0x0202 +#define NT_STATUS_USER_SESSION_DELETED 0x0203 +#define NT_STATUS_RESOURCE_LANG_NOT_FOUND 0x0204 +#define NT_STATUS_INSUFF_SERVER_RESOURCES 0x0205 +#define NT_STATUS_INVALID_BUFFER_SIZE 0x0206 +#define NT_STATUS_INVALID_ADDRESS_COMPONENT 0x0207 +#define NT_STATUS_INVALID_ADDRESS_WILDCARD 0x0208 +#define NT_STATUS_TOO_MANY_ADDRESSES 0x0209 +#define NT_STATUS_ADDRESS_ALREADY_EXISTS 0x020a +#define NT_STATUS_ADDRESS_CLOSED 0x020b +#define NT_STATUS_CONNECTION_DISCONNECTED 0x020c +#define NT_STATUS_CONNECTION_RESET 0x020d +#define NT_STATUS_TOO_MANY_NODES 0x020e +#define NT_STATUS_TRANSACTION_ABORTED 0x020f +#define NT_STATUS_TRANSACTION_TIMED_OUT 0x0210 +#define NT_STATUS_TRANSACTION_NO_RELEASE 0x0211 +#define NT_STATUS_TRANSACTION_NO_MATCH 0x0212 +#define NT_STATUS_TRANSACTION_RESPONDED 0x0213 +#define NT_STATUS_TRANSACTION_INVALID_ID 0x0214 +#define NT_STATUS_TRANSACTION_INVALID_TYPE 0x0215 +#define NT_STATUS_NOT_SERVER_SESSION 0x0216 +#define NT_STATUS_NOT_CLIENT_SESSION 0x0217 +#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE 0x0218 +#define NT_STATUS_DEBUG_ATTACH_FAILED 0x0219 +#define NT_STATUS_SYSTEM_PROCESS_TERMINATED 0x021a +#define NT_STATUS_DATA_NOT_ACCEPTED 0x021b +#define NT_STATUS_NO_BROWSER_SERVERS_FOUND 0x021c +#define NT_STATUS_VDM_HARD_ERROR 0x021d +#define NT_STATUS_DRIVER_CANCEL_TIMEOUT 0x021e +#define NT_STATUS_REPLY_MESSAGE_MISMATCH 0x021f +#define NT_STATUS_MAPPED_ALIGNMENT 0x0220 +#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH 0x0221 +#define NT_STATUS_LOST_WRITEBEHIND_DATA 0x0222 +#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID 0x0223 +#define NT_STATUS_PASSWORD_MUST_CHANGE 0x0224 +#define NT_STATUS_NOT_FOUND 0x0225 +#define NT_STATUS_NOT_TINY_STREAM 0x0226 +#define NT_STATUS_RECOVERY_FAILURE 0x0227 +#define NT_STATUS_STACK_OVERFLOW_READ 0x0228 +#define NT_STATUS_FAIL_CHECK 0x0229 +#define NT_STATUS_DUPLICATE_OBJECTID 0x022a +#define NT_STATUS_OBJECTID_EXISTS 0x022b +#define NT_STATUS_CONVERT_TO_LARGE 0x022c +#define NT_STATUS_RETRY 0x022d +#define NT_STATUS_FOUND_OUT_OF_SCOPE 0x022e +#define NT_STATUS_ALLOCATE_BUCKET 0x022f +#define NT_STATUS_PROPSET_NOT_FOUND 0x0230 +#define NT_STATUS_MARSHALL_OVERFLOW 0x0231 +#define NT_STATUS_INVALID_VARIANT 0x0232 +#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND 0x0233 +#define NT_STATUS_ACCOUNT_LOCKED_OUT 0x0234 +#define NT_STATUS_HANDLE_NOT_CLOSABLE 0x0235 +#define NT_STATUS_CONNECTION_REFUSED 0x0236 +#define NT_STATUS_GRACEFUL_DISCONNECT 0x0237 +#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED 0x0238 +#define NT_STATUS_ADDRESS_NOT_ASSOCIATED 0x0239 +#define NT_STATUS_CONNECTION_INVALID 0x023a +#define NT_STATUS_CONNECTION_ACTIVE 0x023b +#define NT_STATUS_NETWORK_UNREACHABLE 0x023c +#define NT_STATUS_HOST_UNREACHABLE 0x023d +#define NT_STATUS_PROTOCOL_UNREACHABLE 0x023e +#define NT_STATUS_PORT_UNREACHABLE 0x023f +#define NT_STATUS_REQUEST_ABORTED 0x0240 +#define NT_STATUS_CONNECTION_ABORTED 0x0241 +#define NT_STATUS_BAD_COMPRESSION_BUFFER 0x0242 +#define NT_STATUS_USER_MAPPED_FILE 0x0243 +#define NT_STATUS_AUDIT_FAILED 0x0244 +#define NT_STATUS_TIMER_RESOLUTION_NOT_SET 0x0245 +#define NT_STATUS_CONNECTION_COUNT_LIMIT 0x0246 +#define NT_STATUS_LOGIN_TIME_RESTRICTION 0x0247 +#define NT_STATUS_LOGIN_WKSTA_RESTRICTION 0x0248 +#define NT_STATUS_IMAGE_MP_UP_MISMATCH 0x0249 +#define NT_STATUS_INSUFFICIENT_LOGON_INFO 0x0250 +#define NT_STATUS_BAD_DLL_ENTRYPOINT 0x0251 +#define NT_STATUS_BAD_SERVICE_ENTRYPOINT 0x0252 +#define NT_STATUS_LPC_REPLY_LOST 0x0253 +#define NT_STATUS_IP_ADDRESS_CONFLICT1 0x0254 +#define NT_STATUS_IP_ADDRESS_CONFLICT2 0x0255 +#define NT_STATUS_REGISTRY_QUOTA_LIMIT 0x0256 +#define NT_STATUS_PATH_NOT_COVERED 0x0257 +#define NT_STATUS_NO_CALLBACK_ACTIVE 0x0258 +#define NT_STATUS_LICENSE_QUOTA_EXCEEDED 0x0259 +#define NT_STATUS_PWD_TOO_SHORT 0x025a +#define NT_STATUS_PWD_TOO_RECENT 0x025b +#define NT_STATUS_PWD_HISTORY_CONFLICT 0x025c +#define NT_STATUS_PLUGPLAY_NO_DEVICE 0x025e +#define NT_STATUS_UNSUPPORTED_COMPRESSION 0x025f +#define NT_STATUS_INVALID_HW_PROFILE 0x0260 +#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH 0x0261 +#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND 0x0262 +#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND 0x0263 +#define NT_STATUS_RESOURCE_NOT_OWNED 0x0264 +#define NT_STATUS_TOO_MANY_LINKS 0x0265 +#define NT_STATUS_QUOTA_LIST_INCONSISTENT 0x0266 +#define NT_STATUS_FILE_IS_OFFLINE 0x0267 + +#define NT_STATUS_LICENSE_VIOLATION 0x026a + +#define NT_STATUS_DFS_UNAVAILABLE 0x026d +#define NT_STATUS_VOLUME_DISMOUNTED 0x026e + +#define NT_STATUS_NOT_A_REPARSE_POINT 0x0275 + +#define NT_STATUS_REPARSE_POINT_NOT_RESOLVED 0x0280 +#define NT_STATUS_DIRECTORY_IS_A_REPARSE_POINT 0x0281 + +#define NT_STATUS_ENCRYPTION_FAILED 0x028a +#define NT_STATUS_DECRYPTION_FAILED 0x028b +#define NT_STATUS_RANGE_NOT_FOUND 0x028c +#define NT_STATUS_NO_RECOVERY_POLICY 0x028d +#define NT_STATUS_NO_EFS 0x028e +#define NT_STATUS_WRONG_EFS 0x028f +#define NT_STATUS_NO_USER_KEYS 0x0290 +#define NT_STATUS_FILE_NOT_ENCRYPTED 0x0291 + +#define NT_STATUS_FILE_ENCRYPTED 0x0293 + +#define NT_STATUS_VOLUME_NOT_UPGRADED 0x029c + +#define NT_STATUS_KDC_CERT_EXPIRED 0x040e +/* + * 0x00010000-0x0001ffff are "DBG" errors + * 0x00020000-0x0003ffff are "RPC" errors + * 0x00040000-0x0004ffff are "PNP" errors + * 0x000A0000-0x000Affff are "CTX" errors + * 0x00130000-0x0013ffff are "CLUSTER" errors + * 0x00140000-0x0014ffff are "ACPI" errors + * 0x00150000-0x0015ffff are "SXS" errors + */ + +/* + * size of the GUID returned in an extended security negotiate response + */ +#define SMB_GUIDLEN 16 + +typedef uint16_t smbfh; + +/* + * NTLMv2 blob header structure. + */ +struct ntlmv2_blobhdr { + uint32_t header; + uint32_t reserved; + uint64_t timestamp; + uint64_t client_nonce; + uint32_t unknown1; +}; +typedef struct ntlmv2_blobhdr ntlmv2_blobhdr_t; + +/* + * NTLMv2 name header structure, for names in a blob. + */ +struct ntlmv2_namehdr { + uint16_t type; + uint16_t len; +}; +typedef struct ntlmv2_namehdr ntlmv2_namehdr_t; + +#define NAMETYPE_EOL 0x0000 /* end of list of names */ +#define NAMETYPE_MACHINE_NB 0x0001 /* NetBIOS machine name */ +#define NAMETYPE_DOMAIN_NB 0x0002 /* NetBIOS domain name */ +#define NAMETYPE_MACHINE_DNS 0x0003 /* DNS machine name */ +#define NAMETYPE_DOMAIN_DNS 0x0004 /* DNS Active Directory domain name */ + +/* + * Named pipe commands. + */ +#define TRANS_CALL_NAMED_PIPE 0x54 /* open/write/read/close pipe */ +#define TRANS_WAIT_NAMED_PIPE 0x53 /* wait for pipe to be !busy */ +#define TRANS_PEEK_NAMED_PIPE 0x23 /* read but don't remove data */ +#define TRANS_Q_NAMED_PIPE_HAND_STATE 0x21 /* query pipe handle modes */ +#define TRANS_SET_NAMED_PIPE_HAND_STATE 0x01 /* set pipe handle modes */ +#define TRANS_Q_NAMED_PIPE_INFO 0x22 /* query pipe attributes */ +#define TRANS_TRANSACT_NAMED_PIPE 0x26 /* r/w operation on pipe */ +#define TRANS_READ_NAMED_PIPE 0x11 /* read pipe in "raw" mode */ + /* (non message mode) */ +#define TRANS_WRITE_NAMED_PIPE 0x31 /* write pipe "raw" mode */ + /* (non message mode) */ + +/* + * Share types, visible via NetShareEnum + */ +#define STYPE_DISKTREE 0x00000000 +#define STYPE_PRINTQ 0x00000001 +#define STYPE_DEVICE 0x00000002 +#define STYPE_IPC 0x00000003 +#define STYPE_UNKNOWN 0x00000004 +#define STYPE_MASK 0x0000000F +#define STYPE_TEMPORARY 0x40000000 +#define STYPE_HIDDEN 0x80000000 + +#endif /* _NETSMB_SMB_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/netsmb/smb_dev.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2000-2001 Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smb_dev.h,v 1.10.178.1 2005/05/27 02:35:29 lindak Exp $ + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _NETSMB_DEV_H_ +#define _NETSMB_DEV_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This file defines an internal ABI for the "nsmb" driver, + * particularly the various data structures passed to ioctl. + * In order to avoid some messy 32-bit to 64-bit conversions + * in the driver, we take pains to define all data structures + * that pass across the user/kernel boundary in a way that + * makes them invariant across 32-bit and 64-bit ABIs. + * This invariance is checked during the driver build + * using a mechanism similar to genassym.h builds. + * + * If you change any of the ioctl data structures in + * this file, YOU MUST ALSO edit this file: + * uts/common/fs/smbclnt/netsmb/offsets.in + * and then verify the invariance describe above. + * + * Also, remember to "bump" NSMB_VER below when + * any part of this user/kernel I/F changes. + */ + +#ifndef _KERNEL +#include <sys/types.h> +#endif + +#include <sys/socket_impl.h> +#include <netsmb/smb.h> +#include <netsmb/netbios.h> + +#define NSMB_NAME "nsmb" + +/* + * Update NSMB_VER* if any of the ioctl codes and/or + * associated structures change in ways that would + * make them incompatible with an old driver. + */ +#define NSMB_VERMAJ 1 +#define NSMB_VERMIN 3500 +#define NSMB_VERSION (NSMB_VERMAJ * 100000 + NSMB_VERMIN) +#define NSMB_VER_STR "1.35" + +#define NSMBFL_OPEN 0x0001 +#define NSMBFL_NEWVC 0x0002 + +/* + * Hack-ish errno values we need to expose to the library. + * EBADRPC is used for message decoding errors. + * EAUTH is used for CIFS authentication errors. + */ +#ifndef EBADRPC +#define EBADRPC 113 /* XXX */ +#endif +#ifndef EAUTH +#define EAUTH 114 /* XXX */ +#endif + +/* + * "Level" in the connection object hierarchy + */ +#define SMBL_SM 0 +#define SMBL_VC 1 +#define SMBL_SHARE 2 +#define SMBL_NUM 3 +#define SMBL_NONE (-1) + +/* + * Upper/lower case options + */ +#define SMB_CS_NONE 0x0000 +#define SMB_CS_UPPER 0x0001 /* convert passed string to upper case */ +#define SMB_CS_LOWER 0x0002 /* convert passed string to lower case */ + +/* + * access mode stuff (see also smb_lib.h) + */ +#define SMBM_ANY_OWNER ((uid_t)-1) +#define SMBM_ANY_GROUP ((gid_t)-1) +#define SMBM_MASK 0777 +#define SMBM_EXACT 010000 /* check for specified mode exactly */ +#ifdef _KERNEL +/* In-kernel, we prefer the vnode.h names. */ +#define SMBM_READ VREAD /* (S_IRUSR) read conn attrs. */ +#define SMBM_WRITE VWRITE /* (S_IWUSR) modify conn attrs */ +#define SMBM_EXEC VEXEC /* (S_IXUSR) can send SMB requests */ +#endif + +/* + * Option flags in smbioc_ossn.ioc_opt + * and vcspec.optflags + */ +#define SMBVOPT_CREATE 0x0001 /* create object if necessary */ +#define SMBVOPT_PRIVATE 0x0002 /* connection should be private */ +#define SMBVOPT_SINGLESHARE 0x0004 /* keep only one share at this VC */ +#define SMBVOPT_PERMANENT 0x0010 /* object will keep last reference */ +#define SMBVOPT_EXT_SEC 0x0020 /* extended security negotiation */ +#define SMBVOPT_USE_KEYCHAIN 0x0040 /* get p/w from keychain */ +#define SMBVOPT_KC_DOMAIN 0x0080 /* keychain lookup uses domain */ +/* XXX: How about a separate field for these? */ +#define SMBVOPT_MINAUTH 0x7000 /* min. auth. level (mask) */ +#define SMBVOPT_MINAUTH_NONE 0x0000 /* any authentication OK */ +#define SMBVOPT_MINAUTH_LM 0x1000 /* no plaintext passwords */ +#define SMBVOPT_MINAUTH_NTLM 0x2000 /* don't send LM reply */ +#define SMBVOPT_MINAUTH_NTLMV2 0x3000 /* don't fall back to NTLMv1 */ +#define SMBVOPT_MINAUTH_KERBEROS 0x4000 /* don't do NTLMv1 or v2 */ + +/* + * Option flags in smbioc_oshare.ioc_opt + * and sharespec.optflags + */ +#define SMBSOPT_CREATE SMBVOPT_CREATE +#define SMBSOPT_PERMANENT SMBVOPT_PERMANENT + +#define MAX_STR_LEN 8 /* Maxilum length of the minor device name */ + +/* + * We're now using structures that are invariant + * across 32-bit vs 64-bit compilers for all + * member sizes and offsets. Scalar members + * simply have to use fixed-size types. + * Pointers are a little harder... + * We use this union for all pointers that + * must pass between user and kernel. + */ +typedef union lptr { + uint64_t lp_ll; +#ifdef _LP64 + void *lp_ptr; +#endif +#ifdef _ILP32 + void *_lp_p2[2]; +#ifdef _LITTLE_ENDIAN +#define lp_ptr _lp_p2[0] +#define lp_pad _lp_p2[1] +#else /* _ENDIAN */ +#define lp_pad _lp_p2[0] +#define lp_ptr _lp_p2[1] +#endif /* _ENDIAN */ +#endif /* _ILP32 */ +} lptr_t; + +/* + * Handy union of sockaddr types we use. + * Type discriminator is sa_family + */ +union sockaddr_any { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_nb nb; +}; + + +/* + * SMBIOC_LOOKUP flags + */ +#define SMBLK_CREATE SMBVOPT_CREATE + +#define DEF_SEC_TOKEN_LEN 2048 + +struct smbioc_ossn { + union sockaddr_any ioc_server; + union sockaddr_any ioc_local; + char ioc_localcs[16]; /* local charset */ + char ioc_servercs[16]; /* server charset */ + char ioc_srvname[SMB_MAXSRVNAMELEN + 1]; + char ioc_user[SMB_MAXUSERNAMELEN + 1]; + char ioc_workgroup[SMB_MAXUSERNAMELEN + 1]; + char ioc_password[SMB_MAXPASSWORDLEN + 1]; + int32_t ioc_opt; + int32_t ioc_timeout; /* ignored?! XXX */ + int32_t ioc_retrycount; /* number of retries before giveup */ + uid_t ioc_owner; /* proposed owner */ + gid_t ioc_group; /* proposed group */ + mode_t ioc_mode; /* desired access mode */ + mode_t ioc_rights; /* SMBM_* */ + int32_t ioc_intoklen; + int32_t ioc_outtoklen; + /* copyout ends at this offset */ + lptr_t _ioc_intok; + lptr_t _ioc_outtok; +}; +typedef struct smbioc_ossn smbioc_ossn_t; +#define ioc_intok _ioc_intok.lp_ptr +#define ioc_outtok _ioc_outtok.lp_ptr + + +struct smbioc_oshare { + char ioc_share[SMB_MAXSHARENAMELEN + 1]; + char ioc_password[SMB_MAXPASSWORDLEN + 1]; + int32_t ioc_opt; + int32_t ioc_stype; /* share type */ + uid_t ioc_owner; /* proposed owner of share */ + gid_t ioc_group; /* proposed group of share */ + mode_t ioc_mode; /* desired access mode to share */ + mode_t ioc_rights; /* SMBM_* */ + /* + * Hack: need the size of this to be 8-byte aligned + * so that the ioc_ossn following it in smbioc_lookup + * is correctly aligned... + */ + int32_t ioc__pad; +}; +typedef struct smbioc_oshare smbioc_oshare_t; + +typedef struct smbioc_rq { + uchar_t ioc_cmd; + uchar_t ioc_twc; /* _twords */ + ushort_t ioc_tbc; /* _tbytes */ + int32_t ioc_rpbufsz; /* _rpbuf */ + uchar_t ioc__pad1; + uchar_t ioc_rwc; + ushort_t ioc_rbc; + uchar_t ioc__pad2; + uint8_t ioc_errclass; + uint16_t ioc_serror; + uint32_t ioc_error; + uint32_t ioc__pad3; + /* + * Copyout all but the pointers, which + * we may have set to kernel memory. + * See ..._COPYOUT_SIZE + */ + lptr_t _ioc_twords; + lptr_t _ioc_tbytes; + lptr_t _ioc_rpbuf; +} smbioc_rq_t; +#define ioc_twords _ioc_twords.lp_ptr +#define ioc_tbytes _ioc_tbytes.lp_ptr +#define ioc_rpbuf _ioc_rpbuf.lp_ptr +#define SMBIOC_RQ_COPYOUT_SIZE \ + (offsetof(smbioc_rq_t, _ioc_twords)) + + +typedef struct smbioc_t2rq { + uint16_t ioc_setup[SMB_MAXSETUPWORDS]; + int32_t ioc_setupcnt; + char ioc_name[128]; + ushort_t ioc_tparamcnt; + ushort_t ioc_tdatacnt; + ushort_t ioc_rparamcnt; + ushort_t ioc_rdatacnt; + uint8_t ioc__pad1; + uint8_t ioc_errclass; + uint16_t ioc_serror; + uint32_t ioc_error; + uint16_t ioc_rpflags2; + uint16_t ioc__pad2; + /* + * Copyout all but the pointers, which + * we may have set to kernel memory. + * See ..._COPYOUT_SIZE + */ + lptr_t _ioc_tparam; + lptr_t _ioc_tdata; + lptr_t _ioc_rparam; + lptr_t _ioc_rdata; +} smbioc_t2rq_t; +#define ioc_tparam _ioc_tparam.lp_ptr +#define ioc_tdata _ioc_tdata.lp_ptr +#define ioc_rparam _ioc_rparam.lp_ptr +#define ioc_rdata _ioc_rdata.lp_ptr +#define SMBIOC_T2RQ_COPYOUT_SIZE \ + (offsetof(smbioc_t2rq_t, _ioc_tparam)) + + +typedef struct smbioc_flags { + int32_t ioc_level; /* 0 - session, 1 - share */ + int32_t ioc_mask; + int32_t ioc_flags; +} smbioc_flags_t; + +typedef struct smbioc_lookup { + int32_t ioc_level; + int32_t ioc_flags; + struct smbioc_oshare ioc_sh; + struct smbioc_ossn ioc_ssn; +} smbioc_lookup_t; +#define SMBIOC_LOOK_COPYOUT_SIZE \ + (offsetof(smbioc_lookup_t, ioc_ssn._ioc_intok)) + +typedef struct smbioc_rw { + uint16_t ioc_fh; + uint32_t ioc_cnt; + lloff_t _ioc_offset; + lptr_t _ioc_base; +} smbioc_rw_t; +#define ioc_offset _ioc_offset._f +#define ioc_base _ioc_base.lp_ptr +#define SMBIOC_RW_COPYOUT_SIZE \ + (offsetof(smbioc_rw_t, _ioc_base)) + +/* Password Keychain (PK) support. */ +#define SMBIOC_PK_MAXLEN 255 +typedef struct smbioc_pk { + uid_t pk_uid; /* UID for PAM use */ + char pk_dom[SMBIOC_PK_MAXLEN+1]; /* CIFS domain name */ + char pk_usr[SMBIOC_PK_MAXLEN+1]; /* CIFS user name */ + char pk_pass[SMBIOC_PK_MAXLEN+1]; /* CIFS password */ +} smbioc_pk_t; + + +/* + * Device IOCTLs + * + * Define ioctl codes the way ZFS does. + * The "base" value is arbitrary, and can + * occupy the high word if we like, because + * our driver does its own copyin/copyout. + * Keep GETVERS first and use it to verify + * driver compatibility with the library. + */ +#define SMBIOC_BASE ((('n' << 8) | 's') << 8) +typedef enum nsmb_ioc { + SMBIOC_GETVERS = SMBIOC_BASE, + SMBIOC_REQUEST, + SMBIOC_T2RQ, + SMBIOC_LOOKUP, + SMBIOC_READ, + SMBIOC_WRITE, + SMBIOC_NEGOTIATE, + SMBIOC_SSNSETUP, + SMBIOC_TCON, + SMBIOC_TDIS, + SMBIOC_FLAGS2, + /* Password Keychain (PK) support. */ + SMBIOC_PK_ADD, /* Add/Modify a password entry */ + SMBIOC_PK_CHK, /* Check for a password entry */ + SMBIOC_PK_DEL, /* Delete specified password entry */ + SMBIOC_PK_DEL_OWNER, /* all owned by the caller */ + SMBIOC_PK_DEL_EVERYONE /* all owned by everyone */ +} nsmb_ioc_t; + +#ifdef _KERNEL +#include <sys/dditypes.h> /* for dev_info_t */ + +#define SMBST_CONNECTED 1 + +/* Size of storage for p/w hashes. */ +#define SMB_PWH_MAX 24 + +extern const uint32_t nsmb_version; + +struct smb_cred; +struct smb_share; +struct smb_vc; + +typedef struct smb_dev { + int sd_opened; /* Opened or not */ + int sd_level; /* Future use */ + struct smb_vc *sd_vc; /* Reference to VC */ + struct smb_share *sd_share; /* Reference to share if any */ + int sd_poll; /* Future use */ + int sd_seq; /* Kind of minor number/instance no */ + int sd_flags; /* State of connection */ + zoneid_t zoneid; /* Zone id */ + dev_info_t *smb_dip; /* ptr to dev_info node */ + void *sd_devfs; /* Dont know how to use this. but */ + struct cred *smb_cred; /* per dev credentails. Future use */ +} smb_dev_t; + +/* + * Compound user interface + */ +int smb_usr_negotiate(struct smbioc_lookup *dp, struct smb_cred *scred, + struct smb_vc **vcpp); +int smb_usr_ssnsetup(struct smbioc_lookup *dp, struct smb_cred *scred, + struct smb_vc *vcp); +int smb_usr_tcon(struct smbioc_lookup *dp, struct smb_cred *scred, + struct smb_vc *vcp, struct smb_share **sspp); +int smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *data, + struct smb_cred *scred); +int smb_usr_t2request(struct smb_share *ssp, struct smbioc_t2rq *data, + struct smb_cred *scred); +int smb_usr_rw(struct smb_share *ssp, smbioc_rw_t *dp, + int cmd, struct smb_cred *scred); +int smb_dev2share(int fd, struct smb_share **sspp); + +#endif /* _KERNEL */ +#endif /* _NETSMB_DEV_H_ */
--- a/usr/src/uts/common/os/policy.c Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/uts/common/os/policy.c Wed Feb 13 19:51:22 2008 -0800 @@ -2096,3 +2096,24 @@ return (0); } + +/* + * secpolicy_smbfs_login + * + * Determines if the caller can add and delete the smbfs login + * password in the the nsmb kernel module for the CIFS client. + * + * Returns: + * 0 access is allowed. + * EPERM access is NOT allowed. + */ +int +secpolicy_smbfs_login(const cred_t *cr, uid_t uid) +{ + uid_t cruid = crgetruid(cr); + + if (cruid == uid) + return (0); + return (PRIV_POLICY(cr, PRIV_PROC_OWNER, B_FALSE, + EPERM, NULL)); +}
--- a/usr/src/uts/common/os/vfs_conf.c Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/uts/common/os/vfs_conf.c Wed Feb 13 19:51:22 2008 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -81,6 +81,7 @@ { "objfs" }, /* OBJFS */ { "sharefs" }, /* SHAREFS */ { "dcfs" }, /* DCFS */ + { "smbfs" }, /* SMBFS */ { "" }, /* reserved for loadable fs */ { "" }, { "" }, @@ -94,7 +95,6 @@ { "" }, { "" }, { "" }, - { "" }, }; const int nfstype = (sizeof (vfssw) / sizeof (vfssw[0]));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/sys/fs/smbfs_mount.h Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,109 @@ +/* + * 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: smbfs.h,v 1.30.100.1 2005/05/27 02:35:28 lindak Exp $ + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SMBFS_MOUNT_H +#define _SMBFS_MOUNT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This file defines the interface used by mount_smbfs. + * Some of this came from the Darwin file: + * smb-217.2/kernel/fs/smbfs/smbfs.h + */ + +#define SMBFS_VERMAJ 1 +#define SMBFS_VERMIN 3200 +#define SMBFS_VERSION (SMBFS_VERMAJ*100000 + SMBFS_VERMIN) +#define SMBFS_VER_STR "1.32" + +#define SMBFS_VFSNAME "smbfs" + +/* Values for flags */ +#define SMBFS_MOUNT_SOFT 0x0001 +#define SMBFS_MOUNT_INTR 0x0002 +#define SMBFS_MOUNT_STRONG 0x0004 +#define SMBFS_MOUNT_HAVE_NLS 0x0008 +#define SMBFS_MOUNT_NO_LONG 0x0010 +#define SMBFS_MOUNT_HOSTNAME 0x020 +#define SMBFS_MOUNT_SEMISOFT 0x200000 /* read soft, modify hard */ +#define SMBFS_MOUNT_NOPRINT 0x400000 /* don't print messages */ + +#define MNT_RDONLY 0x0001 +#define MNT_NODEV 0x0002 +#define MNT_NOEXEC 0x0004 +#define MNT_NOSUID 0x0008 +#define MNT_UNION 0x0010 +#define MNT_DONTBROWSE 0x0020 +#define MNT_AUTOMOUNTED 0x0040 + +/* Layout of the mount control block for an smb file system. */ +struct smbfs_args { + int version; /* smbfs mount version */ + int devfd; /* file descriptor */ + uint_t flags; /* mount options, eg: soft */ + mode_t file_mode; /* octal srwx for files */ + mode_t dir_mode; /* octal srwx for dirs */ + int caseopt; /* convert upper|lower|none */ + caddr_t addr; /* file server address */ + caddr_t hostname; /* server's hostname */ + caddr_t sharename; /* server's sharename */ + uid_t uid; /* octal user id */ + gid_t gid; /* octal group id */ +}; + +#ifdef _SYSCALL32 + +/* Layout of the mount control block for an smb file system. */ +struct smbfs_args32 { + int32_t version; /* smbfs mount version */ + int32_t devfd; /* file descriptor */ + uint_t flags; /* mount options, eg: soft */ + mode_t file_mode; /* octal srwx for files */ + mode_t dir_mode; /* octal srwx for dirs */ + int32_t caseopt; /* convert upper|lower|none */ + caddr32_t addr; /* file server address */ + caddr32_t hostname; /* server's hostname */ + caddr32_t sharename; /* server's sharename */ + uid32_t uid; /* octal user id */ + gid32_t gid; /* octal group id */ +}; + +#endif /* _SYSCALL32 */ +#endif /* _SMBFS_MOUNT_H */
--- a/usr/src/uts/common/sys/mntent.h Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/uts/common/sys/mntent.h Wed Feb 13 19:51:22 2008 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T @@ -41,6 +41,7 @@ #define MNTTYPE_ZFS "zfs" /* ZFS file system */ #define MNTTYPE_UFS "ufs" /* Unix file system */ +#define MNTTYPE_SMBFS "smbfs" /* SMBFS file system */ #define MNTTYPE_NFS "nfs" /* NFS file system */ #define MNTTYPE_NFS3 "nfs3" /* NFS Version 3 file system */ #define MNTTYPE_NFS4 "nfs4" /* NFS Version 4 file system */
--- a/usr/src/uts/common/sys/policy.h Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/uts/common/sys/policy.h Wed Feb 13 19:51:22 2008 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -130,6 +130,7 @@ int secpolicy_setpriority(const cred_t *); int secpolicy_settime(const cred_t *); int secpolicy_smb(const cred_t *); +int secpolicy_smbfs_login(const cred_t *, uid_t); int secpolicy_spec_open(const cred_t *, struct vnode *, int); int secpolicy_sti(const cred_t *); int secpolicy_swapctl(const cred_t *);
--- a/usr/src/uts/intel/Makefile Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/uts/intel/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -20,7 +20,7 @@ # # uts/intel/Makefile # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -33,7 +33,9 @@ include Makefile.intel -LINT_KMODLIBS = $(LINT_KMODS:e1000g=) +LINT_KMODS_X1 = $(LINT_KMODS:nsmb=) +LINT_KMODS_X2 = $(LINT_KMODS_X1:smbfs=) +LINT_KMODLIBS = $(LINT_KMODS_X2:e1000g=) LINT_LIBS = $(LINT_LIB) $(GEN_LINT_LIB) \ $(LINT_KMODLIBS:%=$(LINT_LIB_DIR)/llib-l%.ln) \ $(CLOSED_LINT_KMODS:%=$(LINT_LIB_DIR)/llib-l%.ln)
--- a/usr/src/uts/intel/Makefile.intel.shared Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/uts/intel/Makefile.intel.shared Wed Feb 13 19:51:22 2008 -0800 @@ -323,6 +323,7 @@ DRV_KMODS += xge DRV_KMODS += zcons DRV_KMODS += chxge +DRV_KMODS += nsmb # # Don't build some of these for OpenSolaris, since they will be @@ -467,6 +468,7 @@ FS_KMODS += autofs cachefs ctfs dev devfs fdfs fifofs hsfs lofs FS_KMODS += lx_afs lx_proc mntfs namefs nfs objfs zfs FS_KMODS += pcfs procfs sockfs specfs tmpfs udfs ufs sharefs +FS_KMODS += smbfs # # Streams Modules (/kernel/strmod):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/nsmb/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,108 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# uts/intel/nsmb/Makefile +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# intel architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = nsmb +OBJECTS = $(NSMB_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(NSMB_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(USR_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/common/fs/smbclnt/netsmb +OFFSETS_SRC = $(CONF_SRCDIR)/offsets.in +IOC_CHECK_H = $(OBJS_DIR)/ioc_check.h + +# +# Include common rules. +# +include $(UTSBASE)/intel/Makefile.intel + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFILE) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# Overrides. +# +MODSTUBS_DIR = $(OBJS_DIR) +$(MODSTUBS_O) := AS_CPPFLAGS += -DNSMB_MODULE +CLEANFILES += $(MODSTUBS_O) $(IOC_CHECK_H) +C99MODE = $(C99_ENABLE) +CERRWARN += -erroff=E_STATEMENT_NOT_REACHED +INC_PATH += -I$(UTSBASE)/common/fs/smbclnt +LDFLAGS += -dy -Ncrypto/md4 -Ncrypto/md5 -Nmisc/tlimod + +LINTTAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2 +LINTTAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2 + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Create ioc_check.h and compare with the saved +# ioc_check.ref to ensure 32/64-bit invariance. +# +$(OBJECTS) : $(IOC_CHECK_H) +$(IOC_CHECK_H): $(OFFSETS_SRC) + $(OFFSETS_CREATE) <$(OFFSETS_SRC) >$@.tmp + cmp -s ioc_check.ref $@.tmp && \ + mv -f $@.tmp $@ + +# +# Include common targets. +# +include $(UTSBASE)/intel/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/nsmb/ioc_check.ref Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,92 @@ +#define SIZEOF_SOCKADDR_ANY 0x18 +#define SIZEOF_SOCKADDR_IN 0x10 +#define SIZEOF_SOCKADDR_NB 0x18 +#define SIZEOF_SMBIOC_OSSN 0x218 +#define IOC_SERVER 0x0 +#define IOC_LOCAL 0x18 +#define IOC_LOCALCS 0x30 +#define IOC_LOCALCS_INCR 0x1 +#define IOC_SERVERCS 0x40 +#define IOC_SERVERCS_INCR 0x1 +#define IOC_SRVNAME 0x50 +#define IOC_SRVNAME_INCR 0x1 +#define IOC_USER 0x60 +#define IOC_USER_INCR 0x1 +#define IOC_WORKGROUP 0xe1 +#define IOC_WORKGROUP_INCR 0x1 +#define IOC_SSN_PASSWD 0x162 +#define IOC_SSN_PASSWD_INCR 0x1 +#define IOC_SSN_OPT 0x1e4 +#define IOC_TIMEOUT 0x1e8 +#define IOC_RETRYCOUNT 0x1ec +#define IOC_SSN_OWNER 0x1f0 +#define IOC_SSN_GROUP 0x1f4 +#define IOC_SSN_MODE 0x1f8 +#define IOC_SSN_RIGHTS 0x1fc +#define IOC_INTOKLEN 0x200 +#define IOC_OUTTOKLEN 0x204 +#define _IOC_INTOK 0x208 +#define _IOC_OUTTOK 0x210 +#define SIZEOF_SMBIOC_OSHARE 0x120 +#define IOC_SHARE 0x0 +#define IOC_SHARE_INCR 0x1 +#define IOC_SH_PASSWD 0x81 +#define IOC_SH_PASSWD_INCR 0x1 +#define IOC_SH_OPT 0x104 +#define IOC_STYPE 0x108 +#define IOC_SH_OWNER 0x10c +#define IOC_SH_GROUP 0x110 +#define IOC_SH_MODE 0x114 +#define IOC_SH_RIGHTS 0x118 +#define SIZEOF_SMBIOC_RQ 0x30 +#define IOC_CMD 0x0 +#define IOC_TWC 0x1 +#define IOC_TBC 0x2 +#define IOC_RPBUFSZ 0x4 +#define IOC_RWC 0x9 +#define IOC_RBC 0xa +#define IOC_RQ_ERRCLASS 0xd +#define IOC_RQ_SERROR 0xe +#define IOC_RQ_ERROR 0x10 +#define _IOC_TWORDS 0x18 +#define _IOC_TBYTES 0x20 +#define _IOC_RPBUF 0x28 +#define SIZEOF_SMBIOC_T2RQ 0xc0 +#define IOC_SETUP 0x0 +#define IOC_SETUP_INCR 0x2 +#define IOC_SETUPCNT 0x8 +#define IOC_NAME 0xc +#define IOC_NAME_INCR 0x1 +#define IOC_TPARAMCNT 0x8c +#define IOC_TDATACNT 0x8e +#define IOC_RPARAMCNT 0x90 +#define IOC_RDATACNT 0x92 +#define IOC_T2_ERRCLASS 0x95 +#define IOC_T2_SERROR 0x96 +#define IOC_T2_ERROR 0x98 +#define IOC_RPFLAGS2 0x9c +#define _IOC_TPARAM 0xa0 +#define _IOC_TDATA 0xa8 +#define _IOC_RPARAM 0xb0 +#define _IOC_RDATA 0xb8 +#define SIZEOF_SMBIOC_FLAGS 0xc +#define IOC_LEVEL 0x0 +#define IOC_MASK 0x4 +#define IOC_FLAGS 0x8 +#define SIZEOF_SMBIOC_LOOKUP 0x340 +#define IOC_LOOK_LEVEL 0x0 +#define IOC_LOOK_FLAGS 0x4 +#define IOC_SH 0x8 +#define IOC_SSN 0x128 +#define SIZEOF_SMBIOC_RW 0x18 +#define IOC_FH 0x0 +#define IOC_CNT 0x4 +#define _IOC_OFFSET 0x8 +#define _IOC_BASE 0x10 +#define SIZEOF_SMBIOC_PK 0x304 +#define PK_DOM 0x4 +#define PK_DOM_INCR 0x1 +#define PK_USR 0x104 +#define PK_USR_INCR 0x1 +#define PK_PASS 0x204 +#define PK_PASS_INCR 0x1
--- a/usr/src/uts/intel/os/minor_perm Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/uts/intel/os/minor_perm Wed Feb 13 19:51:22 2008 -0800 @@ -166,3 +166,4 @@ afe:* 0666 root sys mxfe:* 0666 root sys vscan:* 0640 root sys +nsmb:* 0666 root sys
--- a/usr/src/uts/intel/os/name_to_major Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/uts/intel/os/name_to_major Wed Feb 13 19:51:22 2008 -0800 @@ -148,3 +148,4 @@ pit_beep 253 vscan 254 softmac 255 +nsmb 256
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/smbfs/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,98 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# uts/intel/smbfs/Makefile +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the smbfs (Server +# message block file system) kernel module. +# +# intel architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = smbfs +OBJECTS = $(SMBFS_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(SMBFS_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(USR_FS_DIR)/$(MODULE) +ROOTLINK = $(USR_SYS_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/intel/Makefile.intel + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) + +# +# Overrides. +# +MODSTUBS_DIR = $(OBJS_DIR) +$(MODSTUBS_O) := AS_CPPFLAGS += -DSMBFS_MODULE +CLEANFILES += $(MODSTUBS_O) +C99MODE = $(C99_ENABLE) +INC_PATH += -I$(UTSBASE)/common/fs/smbclnt +LDFLAGS += -dy -Ndrv/nsmb + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +$(ROOTLINK): $(USR_SYS_DIR) $(ROOTMODULE) + -$(RM) $@; ln $(ROOTMODULE) $@ + +# +# Include common targets. +# +include $(UTSBASE)/intel/Makefile.targ
--- a/usr/src/uts/sparc/Makefile Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/uts/sparc/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -21,7 +21,7 @@ # #ident "%Z%%M% %I% %E% SMI" # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # uts/sparc/Makefile @@ -35,9 +35,11 @@ include Makefile.sparc -LINT_KMODLIBS = $(LINT_KMODS:e1000g=) -LINT_LIBS = $(LINT_LIB) $(GEN_LINT_LIB) \ - $(LINT_KMODLIBS:%=$(LINT_LIB_DIR)/llib-l%.ln) +LINT_KMODS_X1 = $(LINT_KMODS:nsmb=) +LINT_KMODS_X2 = $(LINT_KMODS_X1:smbfs=) +LINT_KMODLIBS = $(LINT_KMODS_X2:e1000g=) +LINT_LIBS = $(LINT_LIB) $(GEN_LINT_LIB) \ + $(LINT_KMODLIBS:%=$(LINT_LIB_DIR)/llib-l%.ln) $(CLOSED_BUILD)LINT_LIBS += $(CLOSED_LINT_KMODS:%=$(LINT_LIB_DIR)/llib-l%.ln)
--- a/usr/src/uts/sparc/Makefile.sparc.shared Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/uts/sparc/Makefile.sparc.shared Wed Feb 13 19:51:22 2008 -0800 @@ -236,6 +236,7 @@ DRV_KMODS += chxge DRV_KMODS += smbsrv DRV_KMODS += vscan +DRV_KMODS += nsmb # # Don't build some of these for OpenSolaris, since they will be @@ -337,7 +338,7 @@ # FS_KMODS += dev devfs fdfs fifofs hsfs lofs namefs nfs pcfs tmpfs zfs FS_KMODS += specfs udfs ufs autofs cachefs procfs sockfs mntfs -FS_KMODS += ctfs objfs sharefs dcfs +FS_KMODS += ctfs objfs sharefs dcfs smbfs # # Streams Modules (/kernel/strmod):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/sparc/nsmb/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,135 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# uts/sparc/nsmb/Makefile +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# sparc architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = nsmb +OBJECTS = $(NSMB_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(NSMB_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(USR_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/common/fs/smbclnt/netsmb +OFFSETS_SRC = $(CONF_SRCDIR)/offsets.in +IOC_CHECK_H = $(OBJS_DIR)/ioc_check.h + +# +# Include common rules. +# +include $(UTSBASE)/sparc/Makefile.sparc + +# +# Define targets +# +ALL_TARGET = $(ALL_TARGET_$(OBJS_DIR)) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(INSTALL_TARGET_$(OBJS_DIR)) + +# +# Overrides. +# +# We need some unusual overrides here so we'll +# build ioc_check.h for both 32-bit/64-bit, +# but only build 64-bit binaries. +# + +# Build 32-bit also... +DEF_BUILDS = $(DEF_BUILDS64) $(DEF_BUILDS32) +ALL_BUILDS = $(ALL_BUILDS64) $(ALL_BUILDS32) +# ... but don't build any 32-bit objects +ALL_TARGET_debug32 = $(IOC_CHECK_H) +ALL_TARGET_debug64 = $(BINARY) $(SRC_CONFILE) +ALL_TARGET_obj32 = $(IOC_CHECK_H) +ALL_TARGET_obj64 = $(BINARY) $(SRC_CONFILE) +# ... and remove -xcg92 (not supported by cw) +CFLAGS_32= +# ... same deal for install targets +INSTALL_TARGET_debug32 = $(IOC_CHECK_H) +INSTALL_TARGET_debug64 = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) +INSTALL_TARGET_obj32 = $(IOC_CHECK_H) +INSTALL_TARGET_obj64 = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# Now the normal overrides... +# +MODSTUBS_DIR = $(OBJS_DIR) +$(MODSTUBS_O) := AS_CPPFLAGS += -DNSMB_MODULE +CLEANFILES += $(MODSTUBS_O) $(IOC_CHECK_H) +C99MODE = $(C99_ENABLE) +CERRWARN += -erroff=E_STATEMENT_NOT_REACHED +INC_PATH += -I$(UTSBASE)/common/fs/smbclnt +LDFLAGS += -dy -Ncrypto/md4 -Ncrypto/md5 -Nmisc/tlimod + +LINTTAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2 +LINTTAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2 + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Create ioc_check.h and compare with the saved +# ioc_check.ref to ensure 32/64-bit invariance. +# We don't need _ASM_INLINES for this, and it +# causes #error "port me" in 32-bit builds. +# +$(OBJECTS) : $(IOC_CHECK_H) +$(IOC_CHECK_H): $(OFFSETS_SRC) + $(OFFSETS_CREATE) -U_ASM_INLINES \ + <$(OFFSETS_SRC) >$@.tmp + cmp -s ioc_check.ref $@.tmp && \ + mv -f $@.tmp $@ + +# +# Include common targets. +# +include $(UTSBASE)/sparc/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/sparc/nsmb/inc.flg Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,40 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# Find the CIFS sources. + +find_files "s.*.c" usr/src/uts/common/fs/smbclnt/netsmb + +# Find header files. + +find_files "s.*.h" \ + usr/src/uts/common/fs \ + usr/src/uts/common/netinet \ + usr/src/uts/common/vm \ + usr/src/uts/sparc/sys \ + usr/src/uts/sun/sys +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/sparc/nsmb/ioc_check.ref Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,92 @@ +#define SIZEOF_SOCKADDR_ANY 0x18 +#define SIZEOF_SOCKADDR_IN 0x10 +#define SIZEOF_SOCKADDR_NB 0x18 +#define SIZEOF_SMBIOC_OSSN 0x218 +#define IOC_SERVER 0x0 +#define IOC_LOCAL 0x18 +#define IOC_LOCALCS 0x30 +#define IOC_LOCALCS_INCR 0x1 +#define IOC_SERVERCS 0x40 +#define IOC_SERVERCS_INCR 0x1 +#define IOC_SRVNAME 0x50 +#define IOC_SRVNAME_INCR 0x1 +#define IOC_USER 0x60 +#define IOC_USER_INCR 0x1 +#define IOC_WORKGROUP 0xe1 +#define IOC_WORKGROUP_INCR 0x1 +#define IOC_SSN_PASSWD 0x162 +#define IOC_SSN_PASSWD_INCR 0x1 +#define IOC_SSN_OPT 0x1e4 +#define IOC_TIMEOUT 0x1e8 +#define IOC_RETRYCOUNT 0x1ec +#define IOC_SSN_OWNER 0x1f0 +#define IOC_SSN_GROUP 0x1f4 +#define IOC_SSN_MODE 0x1f8 +#define IOC_SSN_RIGHTS 0x1fc +#define IOC_INTOKLEN 0x200 +#define IOC_OUTTOKLEN 0x204 +#define _IOC_INTOK 0x208 +#define _IOC_OUTTOK 0x210 +#define SIZEOF_SMBIOC_OSHARE 0x120 +#define IOC_SHARE 0x0 +#define IOC_SHARE_INCR 0x1 +#define IOC_SH_PASSWD 0x81 +#define IOC_SH_PASSWD_INCR 0x1 +#define IOC_SH_OPT 0x104 +#define IOC_STYPE 0x108 +#define IOC_SH_OWNER 0x10c +#define IOC_SH_GROUP 0x110 +#define IOC_SH_MODE 0x114 +#define IOC_SH_RIGHTS 0x118 +#define SIZEOF_SMBIOC_RQ 0x30 +#define IOC_CMD 0x0 +#define IOC_TWC 0x1 +#define IOC_TBC 0x2 +#define IOC_RPBUFSZ 0x4 +#define IOC_RWC 0x9 +#define IOC_RBC 0xa +#define IOC_RQ_ERRCLASS 0xd +#define IOC_RQ_SERROR 0xe +#define IOC_RQ_ERROR 0x10 +#define _IOC_TWORDS 0x18 +#define _IOC_TBYTES 0x20 +#define _IOC_RPBUF 0x28 +#define SIZEOF_SMBIOC_T2RQ 0xc0 +#define IOC_SETUP 0x0 +#define IOC_SETUP_INCR 0x2 +#define IOC_SETUPCNT 0x8 +#define IOC_NAME 0xc +#define IOC_NAME_INCR 0x1 +#define IOC_TPARAMCNT 0x8c +#define IOC_TDATACNT 0x8e +#define IOC_RPARAMCNT 0x90 +#define IOC_RDATACNT 0x92 +#define IOC_T2_ERRCLASS 0x95 +#define IOC_T2_SERROR 0x96 +#define IOC_T2_ERROR 0x98 +#define IOC_RPFLAGS2 0x9c +#define _IOC_TPARAM 0xa0 +#define _IOC_TDATA 0xa8 +#define _IOC_RPARAM 0xb0 +#define _IOC_RDATA 0xb8 +#define SIZEOF_SMBIOC_FLAGS 0xc +#define IOC_LEVEL 0x0 +#define IOC_MASK 0x4 +#define IOC_FLAGS 0x8 +#define SIZEOF_SMBIOC_LOOKUP 0x340 +#define IOC_LOOK_LEVEL 0x0 +#define IOC_LOOK_FLAGS 0x4 +#define IOC_SH 0x8 +#define IOC_SSN 0x128 +#define SIZEOF_SMBIOC_RW 0x18 +#define IOC_FH 0x0 +#define IOC_CNT 0x4 +#define _IOC_OFFSET 0x8 +#define _IOC_BASE 0x10 +#define SIZEOF_SMBIOC_PK 0x304 +#define PK_DOM 0x4 +#define PK_DOM_INCR 0x1 +#define PK_USR 0x104 +#define PK_USR_INCR 0x1 +#define PK_PASS 0x204 +#define PK_PASS_INCR 0x1
--- a/usr/src/uts/sparc/os/minor_perm Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/uts/sparc/os/minor_perm Wed Feb 13 19:51:22 2008 -0800 @@ -180,3 +180,4 @@ vnic:* 0666 root sys physmem:* 0600 root sys sdp:sdp 0666 root sys +nsmb:* 0666 root sys
--- a/usr/src/uts/sparc/os/name_to_major Wed Feb 13 15:48:38 2008 -0800 +++ b/usr/src/uts/sparc/os/name_to_major Wed Feb 13 19:51:22 2008 -0800 @@ -221,3 +221,4 @@ vnic 273 vscan 274 softmac 275 +nsmb 276
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/sparc/smbfs/Makefile Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,93 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# uts/sparc/smbfs/Makefile +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the smbfs (Server +# message block file system) kernel module. +# +# sparc architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = smbfs +OBJECTS = $(SMBFS_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(SMBFS_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(USR_FS_DIR)/$(MODULE) +ROOTLINK = $(USR_SYS_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sparc/Makefile.sparc + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) + +# +# Overrides. +# +MODSTUBS_DIR = $(OBJS_DIR) +$(MODSTUBS_O) := AS_CPPFLAGS += -DSMBFS_MODULE +CLEANFILES += $(MODSTUBS_O) +C99MODE = $(C99_ENABLE) +INC_PATH += -I$(UTSBASE)/common/fs/smbclnt +LDFLAGS += -dy -Ndrv/nsmb + +.KEEP_STATE: + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +$(ROOTLINK): $(USR_SYS_DIR) $(ROOTMODULE) + -$(RM) $@; ln $(ROOTMODULE) $@ + +# +# Include common targets. +# +include $(UTSBASE)/sparc/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/sparc/smbfs/inc.flg Wed Feb 13 19:51:22 2008 -0800 @@ -0,0 +1,42 @@ +#!/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +# Find the CIFS sources. + +find_files "s.*.c" usr/src/uts/common/fs/smbclnt/smbfs + +# Find header files. + +find_files "s.*.h" \ + usr/src/uts/common/fs \ + usr/src/uts/common/netinet \ + usr/src/uts/common/rpc \ + usr/src/uts/common/sys \ + usr/src/uts/common/vm \ + usr/src/uts/sparc/sys \ + usr/src/uts/sun/sys