From 8329232e00f1048795bae53acb230316243aadb5 Mon Sep 17 00:00:00 2001 From: Gordon Ross Date: Sat, 12 Aug 2017 10:54:18 -0400 Subject: 9874 Add fksmbcl development tool Reviewed by: Evan Layton Reviewed by: Matt Barden Approved by: Joshua M. Clulow --- usr/src/lib/libsmbfs/smb/ctx.c | 49 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) (limited to 'usr/src/lib/libsmbfs/smb/ctx.c') diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c index 9455a92344..e28599e28f 100644 --- a/usr/src/lib/libsmbfs/smb/ctx.c +++ b/usr/src/lib/libsmbfs/smb/ctx.c @@ -34,7 +34,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ #include @@ -333,7 +333,12 @@ smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv, cf_opt_lock(); /* Careful: no return/goto before cf_opt_unlock! */ while (error == 0) { - opt = cf_getopt(argc, argv, STDPARAM_OPT); + /* + * Leading ':' tells this to skip unknown opts. + * Just get -A and -U here so we know the user + * for config file parsing. + */ + opt = cf_getopt(argc, argv, ":AU:"); if (opt == -1) break; arg = cf_optarg; @@ -398,7 +403,7 @@ smb_ctx_done(struct smb_ctx *ctx) rpc_cleanup_smbctx(ctx); if (ctx->ct_dev_fd != -1) { - close(ctx->ct_dev_fd); + nsmb_close(ctx->ct_dev_fd); ctx->ct_dev_fd = -1; } if (ctx->ct_door_fd != -1) { @@ -1147,6 +1152,10 @@ smb_ctx_resolve(struct smb_ctx *ctx) return (0); } +/* + * Note: The next three have NODIRECT binding so the + * "fksmbcl" development tool can provide its own. + */ int smb_open_driver() { @@ -1163,6 +1172,19 @@ smb_open_driver() return (fd); } +int +nsmb_close(int fd) +{ + return (close(fd)); +} + +int +nsmb_ioctl(int fd, int cmd, void *arg) +{ + return (ioctl(fd, cmd, arg)); +} + + int smb_ctx_gethandle(struct smb_ctx *ctx) { @@ -1171,7 +1193,7 @@ smb_ctx_gethandle(struct smb_ctx *ctx) if (ctx->ct_dev_fd != -1) { rpc_cleanup_smbctx(ctx); - close(ctx->ct_dev_fd); + nsmb_close(ctx->ct_dev_fd); ctx->ct_dev_fd = -1; ctx->ct_flags &= ~SMBCF_SSNACTIVE; } @@ -1187,12 +1209,12 @@ smb_ctx_gethandle(struct smb_ctx *ctx) /* * Check the driver version (paranoia) */ - if (ioctl(fd, SMBIOC_GETVERS, &version) < 0) + if (nsmb_ioctl(fd, SMBIOC_GETVERS, &version) < 0) version = 0; if (version != NSMB_VERSION) { smb_error(dgettext(TEXT_DOMAIN, "incorrect driver version"), 0); - close(fd); + nsmb_close(fd); return (ENODEV); } @@ -1220,6 +1242,15 @@ smb_ctx_get_ssn(struct smb_ctx *ctx) if (err == 0) { DPRINT("found an existing VC"); } else { + /* + * If we're authenticating (real user, not NULL session) + * and we don't yet have a password, return EAUTH and + * the caller will prompt for it and call again. + */ + if (ctx->ct_user[0] != '\0' && + ctx->ct_password[0] == '\0') + return (EAUTH); + /* * This calls the IOD to create a new session. */ @@ -1272,7 +1303,7 @@ smb_ctx_get_tree(struct smb_ctx *ctx) * * The driver does the actual TCON call. */ - if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) { + if (nsmb_ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) { err = errno; goto out; } @@ -1303,7 +1334,7 @@ smb_ctx_flags2(struct smb_ctx *ctx) { uint16_t flags2; - if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) { + if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) { smb_error(dgettext(TEXT_DOMAIN, "can't get flags2 for a session"), errno); return (-1); @@ -1321,7 +1352,7 @@ smb_fh_getssnkey(int dev_fd, uchar_t *key, size_t len) if (len < SMBIOC_HASH_SZ) return (EINVAL); - if (ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1) + if (nsmb_ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1) return (errno); return (0); -- cgit v1.2.3 From 40c0e2317898b8c774791bdc2b30bd50111ab1fa Mon Sep 17 00:00:00 2001 From: Gordon Ross Date: Sat, 20 Jan 2018 12:23:17 -0500 Subject: 9875 SMB client connection setup rework Reviewed by: Evan Layton Reviewed by: Matt Barden Approved by: Joshua M. Clulow --- usr/src/cmd/fs.d/smbclnt/smbutil/Makefile | 4 +- usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c | 143 ----- usr/src/cmd/fs.d/smbclnt/smbutil/view.c | 19 +- usr/src/lib/libsmbfs/Makefile.com | 8 +- usr/src/lib/libsmbfs/netsmb/smb_lib.h | 34 +- usr/src/lib/libsmbfs/smb/connect.c | 603 +++++++-------------- usr/src/lib/libsmbfs/smb/ctx.c | 52 +- usr/src/lib/libsmbfs/smb/file.c | 38 +- usr/src/lib/libsmbfs/smb/findvc.c | 3 +- usr/src/lib/libsmbfs/smb/getaddr.c | 17 +- usr/src/lib/libsmbfs/smb/iod_wk.c | 71 ++- usr/src/lib/libsmbfs/smb/krb5ssp.c | 61 +-- usr/src/lib/libsmbfs/smb/mapfile-vers | 12 +- usr/src/lib/libsmbfs/smb/nb_ssn.c | 336 ------------ usr/src/lib/libsmbfs/smb/negprot.c | 457 ---------------- usr/src/lib/libsmbfs/smb/ntlm.c | 47 +- usr/src/lib/libsmbfs/smb/ntlm.h | 20 +- usr/src/lib/libsmbfs/smb/ntlmssp.c | 113 ++-- usr/src/lib/libsmbfs/smb/private.h | 68 +-- usr/src/lib/libsmbfs/smb/rap.c | 446 --------------- usr/src/lib/libsmbfs/smb/rq.c | 470 ---------------- usr/src/lib/libsmbfs/smb/signing.c | 263 --------- usr/src/lib/libsmbfs/smb/ssnsetup.c | 459 ---------------- usr/src/uts/common/fs/smbclnt/netsmb/offsets.in | 75 +-- usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c | 9 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h | 107 ++-- usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c | 128 +---- usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c | 398 ++++++++++---- usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h | 7 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c | 60 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h | 12 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c | 27 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c | 466 +++++++++++++++- usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h | 9 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c | 109 ++-- usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h | 13 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c | 177 ++++-- usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h | 3 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c | 404 ++++++-------- usr/src/uts/common/netsmb/smb_dev.h | 156 ++---- usr/src/uts/common/sys/t_kuser.h | 1 + usr/src/uts/intel/nsmb/ioc_check.ref | 75 +-- usr/src/uts/sparc/nsmb/ioc_check.ref | 75 +-- 43 files changed, 1848 insertions(+), 4207 deletions(-) delete mode 100644 usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c delete mode 100644 usr/src/lib/libsmbfs/smb/nb_ssn.c delete mode 100644 usr/src/lib/libsmbfs/smb/negprot.c delete mode 100644 usr/src/lib/libsmbfs/smb/rap.c delete mode 100644 usr/src/lib/libsmbfs/smb/rq.c delete mode 100644 usr/src/lib/libsmbfs/smb/signing.c delete mode 100644 usr/src/lib/libsmbfs/smb/ssnsetup.c (limited to 'usr/src/lib/libsmbfs/smb/ctx.c') diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile b/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile index ae9dd15817..3a852c6978 100644 --- a/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile +++ b/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile @@ -23,7 +23,7 @@ # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# Copyright 2013 Nexenta Systems, Inc. All rights reserved. +# Copyright 2018 Nexenta Systems, Inc. All rights reserved. # Copyright (c) 2018, Joyent, Inc. # @@ -34,7 +34,7 @@ PROG= smbutil OBJS= smbutil.o discon.o info.o login.o lookup.o print.o status.o view.o \ - shares_rap.o shares_rpc.o srvsvc1_clnt.o srvsvc1_ndr.o + shares_rpc.o srvsvc1_clnt.o srvsvc1_ndr.o SRCS= $(OBJS:%.o=%.c) diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c b/usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c deleted file mode 100644 index f2235e2880..0000000000 --- a/usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2000-2002, 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. - * - * from: Id: view.c,v 1.9 2002/02/20 09:26:42 bp Exp - */ - -/* - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. - */ - -#include -#include -#include -#include - -#include /* letohs, etc. */ -#include -#include -#include - -#include "common.h" - -/* - * Enumerate shares using Remote Administration Protocol (RAP) - * Was in libsmbfs netshareenum.c - */ - -struct smb_share_info_1 { - char shi1_netname[13]; - char shi1_pad; - uint16_t shi1_type; - uint32_t shi1_remark; /* char * */ -}; - -static 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; - - 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); -} - -int -share_enum_rap(smb_ctx_t *ctx) -{ - struct smb_share_info_1 *shi; - void *rpbuf; - char *cp; - int error, bufsize, i, rcnt, total; - int lbound, rbound; - uint16_t type; - - bufsize = 0xffe0; /* samba notes win2k bug for 65535 */ - rpbuf = malloc(bufsize); - if (rpbuf == NULL) - return (errno); - - error = smb_rap_NetShareEnum(ctx, 1, rpbuf, &bufsize, &rcnt, &total); - if (error && - error != (ERROR_MORE_DATA | SMB_RAP_ERROR)) - goto out; - - /* - * Bounds for offsets to comments strings. - * After the array, and before the end. - */ - lbound = rcnt * (sizeof (struct smb_share_info_1)); - rbound = bufsize; - - /* Print the header line. */ - view_print_share(NULL, 0, NULL); - - for (shi = rpbuf, i = 0; i < rcnt; i++, shi++) { - type = letohs(shi->shi1_type); - - shi->shi1_pad = '\0'; /* ensure null termination */ - - /* - * Offsets to comment strings can be trash. - * Only print when the offset is valid. - */ - if (shi->shi1_remark >= lbound && - shi->shi1_remark < rbound) { - cp = (char *)rpbuf + shi->shi1_remark; - } else - cp = NULL; - - /* Convert from OEM to local codeset? */ - view_print_share(shi->shi1_netname, type, cp); - } - error = 0; - -out: - free(rpbuf); - return (error); -} diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/view.c b/usr/src/cmd/fs.d/smbclnt/smbutil/view.c index bf3397c166..18f0488ad3 100644 --- a/usr/src/cmd/fs.d/smbclnt/smbutil/view.c +++ b/usr/src/cmd/fs.d/smbclnt/smbutil/view.c @@ -34,7 +34,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -51,8 +51,6 @@ #include #include "common.h" -static int use_rap; - void view_usage(void) { @@ -86,15 +84,6 @@ cmd_view(int argc, char *argv[]) while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) { if (opt == '?') view_usage(); - /* - * This is an undocumented option, just for testing. - * Use the old LanMan Remote API Protocol (RAP) for - * enumerating shares. - */ - if (opt == 'B') { - use_rap++; - continue; - } error = smb_ctx_opt(ctx, opt, optarg); if (error) goto out; @@ -137,12 +126,8 @@ again: /* * Have IPC$ tcon, now list shares. - * Try RPC; if that fails, do RAP. */ - if (!use_rap) - error = share_enum_rpc(ctx, ctx->ct_fullserver); - if (error || use_rap) - error = share_enum_rap(ctx); + error = share_enum_rpc(ctx, ctx->ct_fullserver); out: smb_ctx_free(ctx); diff --git a/usr/src/lib/libsmbfs/Makefile.com b/usr/src/lib/libsmbfs/Makefile.com index 3a5c62c46c..e69b199ad0 100644 --- a/usr/src/lib/libsmbfs/Makefile.com +++ b/usr/src/lib/libsmbfs/Makefile.com @@ -24,7 +24,7 @@ # Use is subject to license terms. # Copyright 2015 Igor Kozhukhov # -# Copyright 2013 Nexenta Systems, Inc. All rights reserved. +# Copyright 2018 Nexenta Systems, Inc. All rights reserved. # # Copyright (c) 2018, Joyent, Inc. @@ -57,21 +57,15 @@ OBJ_LIB=\ nb.o \ nb_name.o \ nb_net.o \ - nb_ssn.o \ nbns_rq.o \ - negprot.o \ newvc.o \ nls.o \ ntlm.o \ ntlmssp.o \ print.o \ - rap.o \ rcfile.o \ - rq.o \ - signing.o \ spnego.o \ spnegoparse.o \ - ssnsetup.o \ ssp.o \ subr.o \ ui-sun.o \ diff --git a/usr/src/lib/libsmbfs/netsmb/smb_lib.h b/usr/src/lib/libsmbfs/netsmb/smb_lib.h index 1f6e062e74..c9aa810c91 100644 --- a/usr/src/lib/libsmbfs/netsmb/smb_lib.h +++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.h @@ -34,7 +34,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _NETSMB_SMB_LIB_H_ @@ -103,28 +103,21 @@ struct smb_ctx { struct addrinfo *ct_addrinfo; /* IP addresses of the server */ struct nb_ctx *ct_nb; /* NetBIOS info. */ char *ct_locname; /* local (machine) name */ - smb_iod_ssn_t ct_iod_ssn; - /* smbioc_oshare_t ct_sh; XXX */ int ct_minauth; int ct_shtype_req; /* share type wanted */ char *ct_origshare; char *ct_home; char *ct_rpath; /* remote file name */ - /* Connection setup SMB stuff. */ - /* Strings from the SMB negotiate response. */ - char *ct_srv_OS; - char *ct_srv_LM; - uint32_t ct_clnt_caps; + /* See ssp.c */ + void *ct_ssp_ctx; + smbioc_ssn_work_t ct_work; + smb_iod_ssn_t ct_iod_ssn; /* NTLM auth. stuff */ uchar_t ct_clnonce[NTLM_CHAL_SZ]; uchar_t ct_srv_chal[NTLM_CHAL_SZ]; char ct_password[SMBIOC_MAX_NAME]; - - /* See ssp.c */ - void *ct_ssp_ctx; - smbioc_ssn_work_t ct_work; }; @@ -142,16 +135,9 @@ struct smb_ctx { #define ct_nthash ct_iod_ssn.iod_nthash #define ct_lmhash ct_iod_ssn.iod_lmhash -#define ct_sopt ct_work.wk_sopt -#define ct_iods ct_work.wk_iods -#define ct_tran_fd ct_work.wk_iods.is_tran_fd -#define ct_hflags ct_work.wk_iods.is_hflags -#define ct_hflags2 ct_work.wk_iods.is_hflags2 -#define ct_vcflags ct_work.wk_iods.is_vcflags -#define ct_ssn_key ct_work.wk_iods.is_ssn_key -#define ct_mac_seqno ct_work.wk_iods.is_next_seq -#define ct_mackeylen ct_work.wk_iods.is_u_maclen -#define ct_mackey ct_work.wk_iods.is_u_mackey.lp_ptr +#define ct_vcflags ct_work.wk_vcflags +#define ct_ssnkey_len ct_work.wk_u_ssnkey_len +#define ct_ssnkey_buf ct_work.wk_u_ssnkey_buf.lp_ptr /* @@ -169,9 +155,7 @@ struct smb_ctx { #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 */ +#define SMBCF_KCDOMAIN 0x01000000 /* use domain in KC lookup */ /* diff --git a/usr/src/lib/libsmbfs/smb/connect.c b/usr/src/lib/libsmbfs/smb/connect.c index c2ccc3361d..a45fa90958 100644 --- a/usr/src/lib/libsmbfs/smb/connect.c +++ b/usr/src/lib/libsmbfs/smb/connect.c @@ -22,7 +22,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -53,322 +54,63 @@ #include #include +#include #include #include #include #include "charsets.h" #include "private.h" +#include "smb_crypt.h" -/* - * SMB messages are up to 64K. - * Let's leave room for two. - */ -static int smb_tcpsndbuf = 0x20000; -static int smb_tcprcvbuf = 0x20000; -static int smb_connect_timeout = 30; /* seconds */ -int smb_recv_timeout = 30; /* seconds */ - -int conn_tcp6(struct smb_ctx *, const struct sockaddr *, int); -int conn_tcp4(struct smb_ctx *, const struct sockaddr *, int); -int conn_nbt(struct smb_ctx *, const struct sockaddr *, char *); - -/* - * Internal set sockopt for int-sized options. - * Borrowed from: libnsl/rpc/ti_opts.c - */ static int -smb_setopt_int(int fd, int level, int name, int val) -{ - struct t_optmgmt oreq, ores; - struct { - struct t_opthdr oh; - int ival; - } opts; - - /* opt header */ - opts.oh.len = sizeof (opts); - opts.oh.level = level; - opts.oh.name = name; - opts.oh.status = 0; - opts.ival = val; - - oreq.flags = T_NEGOTIATE; - oreq.opt.buf = (void *)&opts; - oreq.opt.len = sizeof (opts); - - ores.flags = 0; - ores.opt.buf = NULL; - ores.opt.maxlen = 0; - - if (t_optmgmt(fd, &oreq, &ores) < 0) { - DPRINT("t_opgmgnt, t_errno = %d", t_errno); - if (t_errno == TSYSERR) - return (errno); - return (EPROTO); - } - if (ores.flags != T_SUCCESS) { - DPRINT("flags 0x%x, status 0x%x", - (int)ores.flags, (int)opts.oh.status); - return (EPROTO); - } - - return (0); -} - -static int -smb_setopts(int fd) -{ - int err; - - /* - * Set various socket/TCP options. - * Failures here are not fatal - - * just log a complaint. - * - * We don't need these two: - * SO_RCVTIMEO, SO_SNDTIMEO - */ - - err = smb_setopt_int(fd, SOL_SOCKET, SO_SNDBUF, smb_tcpsndbuf); - if (err) { - DPRINT("set SO_SNDBUF, err %d", err); - } - - err = smb_setopt_int(fd, SOL_SOCKET, SO_RCVBUF, smb_tcprcvbuf); - if (err) { - DPRINT("set SO_RCVBUF, err %d", err); - } - - err = smb_setopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, 1); - if (err) { - DPRINT("set SO_KEEPALIVE, err %d", err); - } - - err = smb_setopt_int(fd, IPPROTO_TCP, TCP_NODELAY, 1); - if (err) { - DPRINT("set TCP_NODELAY, err %d", err); - } - - /* Set the connect timeout (in milliseconds). */ - err = smb_setopt_int(fd, IPPROTO_TCP, - TCP_CONN_ABORT_THRESHOLD, - smb_connect_timeout * 1000); - if (err) { - DPRINT("set connect timeout, err %d", err); - } - return (0); -} - - -int -conn_tcp6(struct smb_ctx *ctx, const struct sockaddr *sa, int port) -{ - struct sockaddr_in6 sin6; - char *dev = "/dev/tcp6"; - char paddrbuf[INET6_ADDRSTRLEN]; - struct t_call sndcall; - int fd, err; - - if (sa->sa_family != AF_INET6) { - DPRINT("bad af %d", sa->sa_family); - return (EINVAL); - } - bcopy(sa, &sin6, sizeof (sin6)); - sin6.sin6_port = htons(port); - - DPRINT("tcp6: %s (%d)", - inet_ntop(AF_INET6, &sin6.sin6_addr, - paddrbuf, sizeof (paddrbuf)), port); - - fd = t_open(dev, O_RDWR, NULL); - if (fd < 0) { - /* Assume t_errno = TSYSERR */ - err = errno; - perror(dev); - return (err); - } - if ((err = smb_setopts(fd)) != 0) - goto errout; - if (t_bind(fd, NULL, NULL) < 0) { - DPRINT("t_bind t_errno %d", t_errno); - if (t_errno == TSYSERR) - err = errno; - else - err = EPROTO; - goto errout; - } - sndcall.addr.maxlen = sizeof (sin6); - sndcall.addr.len = sizeof (sin6); - sndcall.addr.buf = (void *) &sin6; - sndcall.opt.len = 0; - sndcall.udata.len = 0; - if (t_connect(fd, &sndcall, NULL) < 0) { - err = get_xti_err(fd); - DPRINT("connect, err %d", err); - goto errout; - } - - DPRINT("tcp6: connected, fd=%d", fd); - ctx->ct_tran_fd = fd; - return (0); +smb__ssnsetup(struct smb_ctx *ctx, + struct mbdata *mbc1, struct mbdata *mbc2); -errout: - close(fd); - return (err); -} +int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *); -/* - * This is used for both SMB over TCP (port 445) - * and NetBIOS - see conn_nbt(). - */ -int -conn_tcp4(struct smb_ctx *ctx, const struct sockaddr *sa, int port) +const char * +smb_iod_state_name(enum smbiod_state st) { - struct sockaddr_in sin; - char *dev = "/dev/tcp"; - char paddrbuf[INET_ADDRSTRLEN]; - struct t_call sndcall; - int fd, err; - - if (sa->sa_family != AF_INET) { - DPRINT("bad af %d", sa->sa_family); - return (EINVAL); - } - bcopy(sa, &sin, sizeof (sin)); - sin.sin_port = htons(port); + const char *n = "(?)"; - DPRINT("tcp4: %s (%d)", - inet_ntop(AF_INET, &sin.sin_addr, - paddrbuf, sizeof (paddrbuf)), port); - - fd = t_open(dev, O_RDWR, NULL); - if (fd < 0) { - /* Assume t_errno = TSYSERR */ - err = errno; - perror(dev); - return (err); - } - if ((err = smb_setopts(fd)) != 0) - goto errout; - if (t_bind(fd, NULL, NULL) < 0) { - DPRINT("t_bind t_errno %d", t_errno); - if (t_errno == TSYSERR) - err = errno; - else - err = EPROTO; - goto errout; - } - sndcall.addr.maxlen = sizeof (sin); - sndcall.addr.len = sizeof (sin); - sndcall.addr.buf = (void *) &sin; - sndcall.opt.len = 0; - sndcall.udata.len = 0; - if (t_connect(fd, &sndcall, NULL) < 0) { - err = get_xti_err(fd); - DPRINT("connect, err %d", err); - goto errout; - } - - DPRINT("tcp4: connected, fd=%d", fd); - ctx->ct_tran_fd = fd; - return (0); - -errout: - close(fd); - return (err); -} - -/* - * Open a NetBIOS connection (session, port 139) - * - * The optional name parameter, if passed, means - * we found the sockaddr via NetBIOS name lookup, - * and can just use that for our session request. - * Otherwise (if name is NULL), we're connecting - * by IP address, and need to come up with the - * NetBIOS name by other means. - */ -int -conn_nbt(struct smb_ctx *ctx, const struct sockaddr *saarg, char *name) -{ - struct sockaddr_in sin; - struct sockaddr *sa; - char server[NB_NAMELEN]; - char workgroup[NB_NAMELEN]; - int err, nberr, port; - - bcopy(saarg, &sin, sizeof (sin)); - sa = (struct sockaddr *)&sin; - - switch (sin.sin_family) { - case AF_NETBIOS: /* our fake AF */ - sin.sin_family = AF_INET; + switch (st) { + case SMBIOD_ST_UNINIT: + n = "UNINIT!"; break; - case AF_INET: + case SMBIOD_ST_IDLE: + n = "IDLE"; + break; + case SMBIOD_ST_RECONNECT: + n = "RECONNECT"; + break; + case SMBIOD_ST_RCFAILED: + n = "RCFAILED"; + break; + case SMBIOD_ST_CONNECTED: + n = "CONNECTED"; + break; + case SMBIOD_ST_NEGOTIATED: + n = "NEGOTIATED"; + break; + case SMBIOD_ST_AUTHCONT: + n = "AUTHCONT"; + break; + case SMBIOD_ST_AUTHFAIL: + n = "AUTHFAIL"; + break; + case SMBIOD_ST_AUTHOK: + n = "AUTHOK"; + break; + case SMBIOD_ST_VCACTIVE: + n = "VCACTIVE"; + break; + case SMBIOD_ST_DEAD: + n = "DEAD"; break; - default: - DPRINT("bad af %d", sin.sin_family); - return (EINVAL); - } - port = IPPORT_NETBIOS_SSN; - - /* - * If we have a NetBIOS name, just use it. - * This is the path taken when we've done a - * NetBIOS name lookup on this name to get - * the IP address in the passed sa. Otherwise, - * we're connecting by IP address, and need to - * figure out what NetBIOS name to use. - */ - if (name) { - strlcpy(server, name, sizeof (server)); - DPRINT("given name: %s", server); - } else { - /* - * - * Try a NetBIOS node status query, - * which searches for a type=[20] name. - * If that doesn't work, just use the - * (fake) "*SMBSERVER" name. - */ - DPRINT("try node status"); - server[0] = '\0'; - nberr = nbns_getnodestatus(ctx->ct_nb, - &sin.sin_addr, server, workgroup); - if (nberr == 0 && server[0] != '\0') { - /* Found the name. Save for reconnect. */ - DPRINT("found name: %s", server); - strlcpy(ctx->ct_srvname, server, - sizeof (ctx->ct_srvname)); - } else { - DPRINT("getnodestatus, nberr %d", nberr); - strlcpy(server, "*SMBSERVER", sizeof (server)); - } - } - - /* - * Establish the TCP connection. - * Careful to close it on errors. - */ - if ((err = conn_tcp4(ctx, sa, port)) != 0) { - DPRINT("TCP connect: err=%d", err); - goto out; } - /* Connected. Do NetBIOS session request. */ - err = nb_ssn_request(ctx, server); - if (err) - DPRINT("ssn_rq, err %d", err); - -out: - if (err) { - if (ctx->ct_tran_fd != -1) { - close(ctx->ct_tran_fd); - ctx->ct_tran_fd = -1; - } - } - return (err); + return (n); } /* @@ -377,9 +119,12 @@ out: int smb_iod_connect(smb_ctx_t *ctx) { - struct sockaddr *sa; - int err, err2; + smbioc_ossn_t *ossn = &ctx->ct_ssn; + smbioc_ssn_work_t *work = &ctx->ct_work; + int err; struct mbdata blob; + char *nego_buf = NULL; + uint32_t nego_len; memset(&blob, 0, sizeof (blob)); @@ -392,15 +137,6 @@ smb_iod_connect(smb_ctx_t *ctx) if (smb_debug) dump_ctx("smb_iod_connect", ctx); - /* - * This may be a reconnect, so - * cleanup if necessary. - */ - if (ctx->ct_tran_fd != -1) { - close(ctx->ct_tran_fd); - ctx->ct_tran_fd = -1; - } - /* * Get local machine name. * Full name - not a NetBIOS name. @@ -420,109 +156,190 @@ smb_iod_connect(smb_ctx_t *ctx) */ ctx->ct_flags |= SMBCF_RESOLVED; - sa = &ctx->ct_srvaddr.sa; - switch (sa->sa_family) { - - case AF_INET6: - err = conn_tcp6(ctx, sa, IPPORT_SMB); - break; - - case AF_INET: - err = conn_tcp4(ctx, sa, IPPORT_SMB); - /* - * If port 445 was not listening, try port 139. - * Note: Not doing NetBIOS name lookup here. - * We already have the IP address. - */ - switch (err) { - case ECONNRESET: - case ECONNREFUSED: - err2 = conn_nbt(ctx, sa, NULL); - if (err2 == 0) - err = 0; - } - break; - - case AF_NETBIOS: - /* Like AF_INET, but use NetBIOS ssn. */ - err = conn_nbt(ctx, sa, ctx->ct_srvname); - break; - - default: - DPRINT("skipped family %d", sa->sa_family); - err = EPROTONOSUPPORT; - break; - } - - - if (err) { - DPRINT("connect, err=%d", err); + /* + * Ask the drvier to connect. + */ + DPRINT("Try ioctl connect..."); + if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_CONNECT, work) < 0) { + err = errno; + smb_error(dgettext(TEXT_DOMAIN, + "%s: connect failed"), + err, ossn->ssn_srvname); return (err); } + DPRINT("Connect OK, new state=%s", + smb_iod_state_name(work->wk_out_state)); /* - * Do SMB Negotiate Protocol. + * Setup a buffer to recv the nego. hint. */ - err = smb_negprot(ctx, &blob); + nego_len = 4096; + err = mb_init_sz(&blob, nego_len); if (err) goto out; + nego_buf = blob.mb_top->m_data; + work->wk_u_auth_rbuf.lp_ptr = nego_buf; + work->wk_u_auth_rlen = nego_len; /* - * Empty user name means an explicit request for - * NULL session setup, which is a special case. - * If negotiate determined that we want to do - * SMB signing, we have to turn that off for a - * NULL session. [MS-SMB 3.3.5.3]. + * Ask the driver for SMB negotiate */ - if (ctx->ct_user[0] == '\0') { - /* Null user should have null domain too. */ - ctx->ct_domain[0] = '\0'; - ctx->ct_authflags = SMB_AT_ANON; - ctx->ct_clnt_caps &= ~SMB_CAP_EXT_SECURITY; - ctx->ct_vcflags &= ~SMBV_WILL_SIGN; + DPRINT("Try ioctl negotiate..."); + if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_NEGOTIATE, work) < 0) { + err = errno; + smb_error(dgettext(TEXT_DOMAIN, + "%s: negotiate failed"), + err, ossn->ssn_srvname); + goto out; + } + DPRINT("Negotiate OK, new state=%s", + smb_iod_state_name(work->wk_out_state)); + + nego_len = work->wk_u_auth_rlen; + blob.mb_top->m_len = nego_len; + + if (smb_debug) { + DPRINT("Sec. blob: %d", nego_len); + smb_hexdump(nego_buf, nego_len); } /* * Do SMB Session Setup (authenticate) - * - * If the server negotiated extended security, - * run the SPNEGO state machine, otherwise do - * one of the old-style variants. + * Always "extended security" now (SPNEGO) */ - if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) { - err = smb_ssnsetup_spnego(ctx, &blob); - } else { - /* - * Server did NOT negotiate extended security. - * Try NTLMv2, NTLMv1, or ANON (if enabled). - */ - if (ctx->ct_authflags & SMB_AT_NTLM2) { - err = smb_ssnsetup_ntlm2(ctx); - } else if (ctx->ct_authflags & SMB_AT_NTLM1) { - err = smb_ssnsetup_ntlm1(ctx); - } else if (ctx->ct_authflags & SMB_AT_ANON) { - err = smb_ssnsetup_null(ctx); - } else { - /* - * Don't return EAUTH, because a new - * password prompt will not help. - */ - DPRINT("No NTLM authflags"); - err = ENOTSUP; - } + DPRINT("Do session setup..."); + err = smb_ssnsetup_spnego(ctx, &blob); + if (err != 0) { + DPRINT("Session setup err=%d", err); + goto out; } + /* + * Success! We return zero now, and our caller (normally + * the smbiod program) will then call smb_iod_work in a + * new thread to service this VC as long as necessary. + */ + DPRINT("Session setup OK"); + out: mb_done(&blob); + return (err); +} + +int +smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb) +{ + struct mbdata send_mb, recv_mb; + smbioc_ssn_work_t *work = &ctx->ct_work; + int err; + + bzero(&send_mb, sizeof (send_mb)); + bzero(&recv_mb, sizeof (recv_mb)); + + err = ssp_ctx_create_client(ctx, hint_mb); + if (err) + goto out; + + /* NULL input indicates first call. */ + err = ssp_ctx_next_token(ctx, NULL, &send_mb); if (err) { - close(ctx->ct_tran_fd); - ctx->ct_tran_fd = -1; - } else { - /* Tell library code we have a session. */ - ctx->ct_flags |= SMBCF_SSNACTIVE; - DPRINT("tran_fd = %d", ctx->ct_tran_fd); + DPRINT("smb__ssnsetup, ssp next, err=%d", err); + goto out; + } + for (;;) { + err = smb__ssnsetup(ctx, &send_mb, &recv_mb); + if (err != 0 && err != EINPROGRESS) { + DPRINT("smb__ssnsetup, err=%d", err); + goto out; + } + DPRINT("smb__ssnsetup, new state=%s", + smb_iod_state_name(work->wk_out_state)); + if (work->wk_out_state == SMBIOD_ST_AUTHOK) { + err = 0; + break; + } + if (work->wk_out_state == SMBIOD_ST_AUTHFAIL) { + err = EAUTH; + goto out; + } + if (work->wk_out_state != SMBIOD_ST_AUTHCONT) { + err = EPROTO; + goto out; + } + /* state == SMBIOD_ST_AUTHCONT */ + + /* middle calls get both in, out */ + err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb); + if (err) { + DPRINT("smb__ssnsetup, ssp next, err=%d", err); + goto out; + } + } + + /* NULL output indicates last call. */ + (void) ssp_ctx_next_token(ctx, &recv_mb, NULL); + + /* + * The session key is in ctx->ct_ssnkey_buf + * (a.k.a. ct_work.wk_u_ssn_key_buf) + */ + +out: + /* Done with ctx->ct_ssp_ctx */ + ssp_ctx_destroy(ctx); + + return (err); +} + +int smb_max_authtok_sz = 0x10000; + +/* + * Session Setup function, calling the nsmb driver. + * + * Args + * send_mb: [in] outgoing blob data to send + * recv_mb: [out] received blob data buffer + */ +static int +smb__ssnsetup(struct smb_ctx *ctx, + struct mbdata *send_mb, struct mbdata *recv_mb) +{ + smbioc_ossn_t *ossn = &ctx->ct_ssn; + smbioc_ssn_work_t *work = &ctx->ct_work; + mbuf_t *m; + int err; + + /* Setup receive buffer for the auth data. */ + err = mb_init_sz(recv_mb, smb_max_authtok_sz); + if (err != 0) + return (err); + m = recv_mb->mb_top; + work->wk_u_auth_rbuf.lp_ptr = m->m_data; + work->wk_u_auth_rlen = m->m_maxlen; + + /* ... and the auth data to send. */ + m = send_mb->mb_top; + work->wk_u_auth_wbuf.lp_ptr = m->m_data; + work->wk_u_auth_wlen = m->m_len; + + DPRINT("Session setup ioctl..."); + if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_SSNSETUP, work) < 0) { + err = errno; + if (err != 0 && err != EINPROGRESS) { + smb_error(dgettext(TEXT_DOMAIN, + "%s: session setup "), + err, ossn->ssn_srvname); + } } + DPRINT("Session setup ret %d", err); + + /* Free the auth data we sent. */ + mb_done(send_mb); + + /* Setup length of received auth data */ + m = recv_mb->mb_top; + m->m_len = work->wk_u_auth_rlen; return (err); } diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c index e28599e28f..43ca516f81 100644 --- a/usr/src/lib/libsmbfs/smb/ctx.c +++ b/usr/src/lib/libsmbfs/smb/ctx.c @@ -34,7 +34,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -148,10 +148,6 @@ dump_ctx_flags(int flags) 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"); @@ -254,13 +250,12 @@ smb_ctx_init(struct smb_ctx *ctx) ctx->ct_dev_fd = -1; ctx->ct_door_fd = -1; - ctx->ct_tran_fd = -1; ctx->ct_parsedlevel = SMBL_NONE; ctx->ct_minlevel = SMBL_NONE; ctx->ct_maxlevel = SMBL_PATH; /* Fill in defaults */ - ctx->ct_vopt = SMBVOPT_EXT_SEC; + ctx->ct_vopt = SMBVOPT_SIGNING_ENABLED; ctx->ct_owner = SMBM_ANY_OWNER; ctx->ct_authflags = SMB_AT_DEFAULT; ctx->ct_minauth = SMB_AT_MINAUTH; @@ -410,10 +405,6 @@ smb_ctx_done(struct smb_ctx *ctx) close(ctx->ct_door_fd); ctx->ct_door_fd = -1; } - if (ctx->ct_tran_fd != -1) { - close(ctx->ct_tran_fd); - ctx->ct_tran_fd = -1; - } if (ctx->ct_srvaddr_s) { free(ctx->ct_srvaddr_s); ctx->ct_srvaddr_s = NULL; @@ -446,17 +437,9 @@ smb_ctx_done(struct smb_ctx *ctx) free(ctx->ct_rpath); ctx->ct_rpath = NULL; } - if (ctx->ct_srv_OS) { - free(ctx->ct_srv_OS); - ctx->ct_srv_OS = NULL; - } - if (ctx->ct_srv_LM) { - free(ctx->ct_srv_LM); - ctx->ct_srv_LM = NULL; - } - if (ctx->ct_mackey) { - free(ctx->ct_mackey); - ctx->ct_mackey = NULL; + if (ctx->ct_ssnkey_buf) { + free(ctx->ct_ssnkey_buf); + ctx->ct_ssnkey_buf = NULL; } } @@ -904,12 +887,11 @@ smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) } /* - * Suport a securty options arg, i.e. -S noext,lm,ntlm + * Suport a securty options arg, i.e. -S lm,ntlm * for testing various type of authenticators. */ static struct nv sectype_table[] = { - /* noext - handled below */ { "anon", SMB_AT_ANON }, { "lm", SMB_AT_LM1 }, { "ntlm", SMB_AT_NTLM1 }, @@ -935,13 +917,6 @@ smb_parse_secopts(struct smb_ctx *ctx, const char *arg) if (nlen == 0) break; - if (nlen == 5 && 0 == strncmp(p, "noext", nlen)) { - /* Don't offer extended security. */ - ctx->ct_vopt &= ~SMBVOPT_EXT_SEC; - p += nlen; - continue; - } - /* This is rarely called, so not optimized. */ for (nv = sectype_table; nv->name; nv++) { tlen = strlen(nv->name); @@ -1121,6 +1096,19 @@ smb_ctx_resolve(struct smb_ctx *ctx) } assert(ctx->ct_addrinfo != NULL); + /* + * Empty user name means an explicit request for + * NULL session setup, which is a special case. + * (No SMB signing, per [MS-SMB] 3.3.5.3) + */ + if (ctx->ct_user[0] == '\0') { + /* Null user should have null domain too. */ + ctx->ct_domain[0] = '\0'; + ctx->ct_authflags = SMB_AT_ANON; + ctx->ct_vopt |= SMBVOPT_ANONYMOUS; + ctx->ct_vopt &= ~SMBVOPT_SIGNING_REQUIRED; + } + /* * If we have a user name but no password, * check for a keychain entry. @@ -1139,6 +1127,7 @@ smb_ctx_resolve(struct smb_ctx *ctx) */ ctx->ct_authflags &= ctx->ct_minauth; } + if (ctx->ct_authflags == 0) { smb_error(dgettext(TEXT_DOMAIN, "no valid auth. types"), 0); @@ -1195,7 +1184,6 @@ smb_ctx_gethandle(struct smb_ctx *ctx) rpc_cleanup_smbctx(ctx); nsmb_close(ctx->ct_dev_fd); ctx->ct_dev_fd = -1; - ctx->ct_flags &= ~SMBCF_SSNACTIVE; } fd = smb_open_driver(); diff --git a/usr/src/lib/libsmbfs/smb/file.c b/usr/src/lib/libsmbfs/smb/file.c index b104502d9c..1c4e2dc236 100644 --- a/usr/src/lib/libsmbfs/smb/file.c +++ b/usr/src/lib/libsmbfs/smb/file.c @@ -33,9 +33,10 @@ */ /* - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -62,9 +63,15 @@ #include "private.h" +/* + * It's not actually necessary to call the CLOSEFH ioctl, but doing it + * makes debugging a little easier. If we were to skip the ioctl, + * nsmb_close would cleanup the handle, here or in process exit. + */ int smb_fh_close(int fd) { + (void) nsmb_ioctl(fd, SMBIOC_CLOSEFH, NULL); return (nsmb_close(fd)); } @@ -251,21 +258,24 @@ smb_fh_xactnp(int fd, int *rdlen, char *rdata, /* receive */ int *more) { - int err, rparamcnt; - uint16_t setup[2]; - - setup[0] = TRANS_TRANSACT_NAMED_PIPE; - setup[1] = 0xFFFF; /* driver replaces this */ - rparamcnt = 0; + smbioc_xnp_t ioc; - err = smb_t2_request(fd, 2, setup, "\\PIPE\\", - 0, NULL, /* TX paramcnt, params */ - tdlen, (void *)tdata, - &rparamcnt, NULL, /* no RX params */ - rdlen, rdata, more); + /* this gets copyin & copyout */ + bzero(&ioc, sizeof (ioc)); + ioc.ioc_fh = -1; /* tell driver to supply this */ + ioc.ioc_tdlen = tdlen; + ioc.ioc_rdlen = *rdlen; + ioc.ioc_more = 0; + ioc.ioc_tdata = (char *)tdata; + ioc.ioc_rdata = rdata; - if (err) + if (nsmb_ioctl(fd, SMBIOC_XACTNP, &ioc) == -1) { *rdlen = 0; + return (-1); + } + + *rdlen = ioc.ioc_rdlen; + *more = ioc.ioc_more; - return (err); + return (0); } diff --git a/usr/src/lib/libsmbfs/smb/findvc.c b/usr/src/lib/libsmbfs/smb/findvc.c index 9d9ccd678c..0e781f7099 100644 --- a/usr/src/lib/libsmbfs/smb/findvc.c +++ b/usr/src/lib/libsmbfs/smb/findvc.c @@ -23,7 +23,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -121,7 +121,6 @@ smb_ctx_findvc(struct smb_ctx *ctx) if (err == 0) { /* re-use an existing VC */ - ctx->ct_flags |= SMBCF_SSNACTIVE; return (0); } } diff --git a/usr/src/lib/libsmbfs/smb/getaddr.c b/usr/src/lib/libsmbfs/smb/getaddr.c index 67e61567a1..7c01b0d7c9 100644 --- a/usr/src/lib/libsmbfs/smb/getaddr.c +++ b/usr/src/lib/libsmbfs/smb/getaddr.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -57,6 +58,8 @@ #include "charsets.h" #include "private.h" +static char smb_port[16] = "445"; + void dump_addrinfo(struct addrinfo *ai) { @@ -118,7 +121,7 @@ smb_ctx_getaddr(struct smb_ctx *ctx) struct nb_ctx *nbc = ctx->ct_nb; struct addrinfo hints, *res; char *srvaddr_str; - int gaierr, gaierr2; + int gaierr; if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == '\0') return (EAI_NONAME); @@ -154,19 +157,26 @@ smb_ctx_getaddr(struct smb_ctx *ctx) hints.ai_flags = AI_CANONNAME; hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - gaierr = getaddrinfo(srvaddr_str, NULL, &hints, &res); + gaierr = getaddrinfo(srvaddr_str, smb_port, &hints, &res); if (gaierr == 0) { ctx->ct_addrinfo = res; return (0); } + /* + * If we really want to support NetBIOS, we should add + * an AF_NETBIOS entry to the address list here. + * For now, let's just skip NetBIOS. + * (Can we just kill NetBIOS? Please? :) + */ +#if 0 /* XXX Just kill NetBIOS? */ /* * If regular IP name lookup failed, try NetBIOS, * but only if given a valid NetBIOS name and if * NetBIOS name lookup is enabled. */ if (nbc->nb_flags & NBCF_NS_ENABLE) { - gaierr2 = nbns_getaddrinfo(ctx->ct_fullserver, nbc, &res); + int gaierr2 = nbns_getaddrinfo(ctx->ct_fullserver, nbc, &res); if (gaierr2 == 0) { if (res->ai_canonname) strlcpy(ctx->ct_srvname, @@ -176,6 +186,7 @@ smb_ctx_getaddr(struct smb_ctx *ctx) return (0); } } +#endif /* * Return the original error from getaddrinfo diff --git a/usr/src/lib/libsmbfs/smb/iod_wk.c b/usr/src/lib/libsmbfs/smb/iod_wk.c index 8b56fdaf18..b19f1f3f0f 100644 --- a/usr/src/lib/libsmbfs/smb/iod_wk.c +++ b/usr/src/lib/libsmbfs/smb/iod_wk.c @@ -20,9 +20,10 @@ */ /* - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -59,22 +60,21 @@ #include "private.h" /* - * Be the reader thread for this VC. + * The user agent (smbiod) calls smb_iod_connect for the first + * connection to some server, and if that succeeds, will start a + * thread running this function, passing the smb_ctx_t + * + * This thread now enters the driver and stays there, reading + * network responses as long as the connection is alive. */ int smb_iod_work(smb_ctx_t *ctx) { smbioc_ssn_work_t *work = &ctx->ct_work; - int vcst, err = 0; + int err = 0; DPRINT("server: %s", ctx->ct_srvname); - /* Caller should have opened these */ - if (ctx->ct_tran_fd == -1 || ctx->ct_dev_fd == -1) { - err = EINVAL; - goto out; - } - /* * This is the reader / reconnect loop. * @@ -84,20 +84,22 @@ smb_iod_work(smb_ctx_t *ctx) * * XXX: Add some syslog calls in here? */ - vcst = SMBIOD_ST_VCACTIVE; for (;;) { - switch (vcst) { + DPRINT("state: %s", + smb_iod_state_name(work->wk_out_state)); + + switch (work->wk_out_state) { case SMBIOD_ST_IDLE: /* * Wait for driver requests to arrive * for this VC, then return here. * Next state is normally RECONNECT. */ - DPRINT("state: idle"); + DPRINT("Call _ioc_idle..."); if (nsmb_ioctl(ctx->ct_dev_fd, - SMBIOC_IOD_IDLE, &vcst) == -1) { + SMBIOC_IOD_IDLE, work) == -1) { err = errno; DPRINT("ioc_idle: err %d", err); goto out; @@ -105,13 +107,11 @@ smb_iod_work(smb_ctx_t *ctx) continue; case SMBIOD_ST_RECONNECT: - DPRINT("state: reconnect"); + DPRINT("Call _iod_connect..."); err = smb_iod_connect(ctx); - if (err == 0) { - vcst = SMBIOD_ST_VCACTIVE; + if (err == 0) continue; - } - DPRINT("_iod_connect: err %d", err); + DPRINT("iod_connect: err %d", err); /* * If the error was EAUTH, retry is * not likely to succeed either, so @@ -121,60 +121,53 @@ smb_iod_work(smb_ctx_t *ctx) */ if (err == EAUTH) goto out; - vcst = SMBIOD_ST_RCFAILED; continue; case SMBIOD_ST_RCFAILED: - DPRINT("state: rcfailed"); /* * Reconnect failed. Kill off any * requests waiting in the driver, * then get ready to try again. * Next state is normally IDLE. */ + DPRINT("Call _iod_rcfail..."); if (nsmb_ioctl(ctx->ct_dev_fd, - SMBIOC_IOD_RCFAIL, &vcst) == -1) { + SMBIOC_IOD_RCFAIL, work) == -1) { err = errno; - DPRINT("ioc_rcfail: err %d", err); + DPRINT("iod_rcfail: err %d", err); goto out; } continue; - case SMBIOD_ST_VCACTIVE: - DPRINT("state: active"); + case SMBIOD_ST_AUTHOK: + /* + * This is where we enter the driver and + * stay there. While the connection is up + * the VC will have SMBIOD_ST_VCACTIVE + */ + DPRINT("Call _iod_work..."); if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_WORK, work) == -1) { err = errno; - DPRINT("ioc_work: err %d", err); + DPRINT("iod_work: err %d", err); goto out; } - vcst = work->wk_out_state; - /* - * Go ahead and close the transport now, - * rather than wait until reconnect to - * this server. - */ - close(ctx->ct_tran_fd); - ctx->ct_tran_fd = -1; continue; case SMBIOD_ST_DEAD: - DPRINT("state: dead"); err = 0; goto out; default: - DPRINT("state: BAD(%d)", vcst); + DPRINT("Unexpected state: %d (%s)", + work->wk_out_state, + smb_iod_state_name(work->wk_out_state)); err = EFAULT; goto out; } } out: - if (ctx->ct_tran_fd != -1) { - close(ctx->ct_tran_fd); - ctx->ct_tran_fd = -1; - } if (ctx->ct_dev_fd != -1) { nsmb_close(ctx->ct_dev_fd); ctx->ct_dev_fd = -1; diff --git a/usr/src/lib/libsmbfs/smb/krb5ssp.c b/usr/src/lib/libsmbfs/smb/krb5ssp.c index 208ec6d0a4..421a0bda37 100644 --- a/usr/src/lib/libsmbfs/smb/krb5ssp.c +++ b/usr/src/lib/libsmbfs/smb/krb5ssp.c @@ -32,6 +32,7 @@ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -90,7 +91,7 @@ extern MECH_OID g_stcMechOIDList []; typedef struct krb5ssp_state { /* Filled in by krb5ssp_init_client */ krb5_context ss_krb5ctx; /* krb5 context (ptr) */ - krb5_ccache ss_krb5cc; /* credentials cache (ptr) */ + krb5_ccache ss_krb5cc; /* credentials cache (ptr) */ krb5_principal ss_krb5clp; /* client principal (ptr) */ /* Filled in by krb5ssp_get_tkt */ krb5_auth_context ss_auth; /* auth ctx. w/ server (ptr) */ @@ -107,8 +108,8 @@ krb5ssp_tkt2gtok(uchar_t *tkt, ulong_t tktlen, ulong_t len; ulong_t bloblen = tktlen; uchar_t krbapreq[2] = { KRB_AP_REQ, 0 }; - uchar_t *blob = NULL; /* result */ - uchar_t *b; + uchar_t *blob = NULL; /* result */ + uchar_t *b; bloblen += sizeof (krbapreq); bloblen += g_stcMechOIDList[spnego_mech_oid_Kerberos_V5].iLen; @@ -168,7 +169,7 @@ krb5ssp_get_tkt(krb5ssp_state_t *ss, char *server, krb5_data outdata = {0}; krb5_error_code kerr = 0; const char *fn = NULL; - uchar_t *tkt; + uchar_t *tkt; /* Should have these from krb5ssp_init_client. */ if (kctx == NULL || kcc == NULL) { @@ -252,9 +253,9 @@ krb5ssp_put_request(struct ssp_ctx *sp, struct mbdata *out_mb) int err; struct smb_ctx *ctx = sp->smb_ctx; krb5ssp_state_t *ss = sp->sp_private; - uchar_t *tkt = NULL; + uchar_t *tkt = NULL; ulong_t tktlen; - uchar_t *gtok = NULL; /* gssapi token */ + uchar_t *gtok = NULL; /* gssapi token */ ulong_t gtoklen; /* gssapi token length */ char *prin = ctx->ct_srvname; @@ -268,9 +269,6 @@ krb5ssp_put_request(struct ssp_ctx *sp, struct mbdata *out_mb) if ((err = mb_put_mem(out_mb, gtok, gtoklen, MB_MSYSTEM)) != 0) goto out; - if (ctx->ct_vcflags & SMBV_WILL_SIGN) - ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; - out: if (gtok) free(gtok); @@ -383,7 +381,7 @@ krb5ssp_final(struct ssp_ctx *sp) struct smb_ctx *ctx = sp->smb_ctx; krb5ssp_state_t *ss = sp->sp_private; krb5_keyblock *ssn_key = NULL; - int err, len; + int err; /* * Save the session key, used for SMB signing @@ -398,35 +396,32 @@ krb5ssp_final(struct ssp_ctx *sp) err = EAUTH; goto out; } - memset(ctx->ct_ssn_key, 0, SMBIOC_HASH_SZ); - if ((len = ssn_key->length) > SMBIOC_HASH_SZ) - len = SMBIOC_HASH_SZ; - memcpy(ctx->ct_ssn_key, ssn_key->contents, len); + + /* Sanity check the length */ + if (ssn_key->length > 1024) { + DPRINT("session key too long"); + err = EAUTH; + goto out; + } /* - * Set the MAC key on the first successful auth. + * Update/save the session key. */ - if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) && - (ctx->ct_mackey == NULL)) { - ctx->ct_mackeylen = ssn_key->length; - ctx->ct_mackey = malloc(ctx->ct_mackeylen); - if (ctx->ct_mackey == NULL) { - ctx->ct_mackeylen = 0; - err = ENOMEM; - goto out; - } - memcpy(ctx->ct_mackey, ssn_key->contents, - ctx->ct_mackeylen); - /* - * Apparently, the server used seq. no. zero - * for our previous message, so next is two. - */ - ctx->ct_mac_seqno = 2; + if (ctx->ct_ssnkey_buf != NULL) { + free(ctx->ct_ssnkey_buf); + ctx->ct_ssnkey_buf = NULL; + } + ctx->ct_ssnkey_buf = malloc(ssn_key->length); + if (ctx->ct_ssnkey_buf == NULL) { + err = ENOMEM; + goto out; } + ctx->ct_ssnkey_len = ssn_key->length; + memcpy(ctx->ct_ssnkey_buf, ssn_key->contents, ctx->ct_ssnkey_len); err = 0; out: - if (ssn_key) + if (ssn_key != NULL) krb5_free_keyblock(ss->ss_krb5ctx, ssn_key); return (err); @@ -508,7 +503,7 @@ krb5ssp_init_client(struct ssp_ctx *sp) krb5ssp_state_t *ss; krb5_error_code kerr; krb5_context kctx = NULL; - krb5_ccache kcc = NULL; + krb5_ccache kcc = NULL; krb5_principal kprin = NULL; if ((sp->smb_ctx->ct_authflags & SMB_AT_KRB5) == 0) { diff --git a/usr/src/lib/libsmbfs/smb/mapfile-vers b/usr/src/lib/libsmbfs/smb/mapfile-vers index 8d658ab937..73ab2504f5 100644 --- a/usr/src/lib/libsmbfs/smb/mapfile-vers +++ b/usr/src/lib/libsmbfs/smb/mapfile-vers @@ -19,7 +19,7 @@ # # # Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. -# Copyright 2017 Nexenta Systems, Inc. All rights reserved. +# Copyright 2018 Nexenta Systems, Inc. All rights reserved. # # @@ -127,16 +127,6 @@ SYMBOL_VERSION SUNWprivate { smb_simplecrypt; smb_simpledecrypt; smb_strerror; -# -# Functions to support the Remote Access Protocol (RAP) - smb_rap_create; - smb_rap_done; - smb_rap_error; - smb_rap_getNparam; - smb_rap_request; - smb_rap_setNparam; - smb_rap_setPparam; -# smb_verbose { FLAGS = NODIRECT }; # data # # Functions to support Access Control Lists (ACLs) diff --git a/usr/src/lib/libsmbfs/smb/nb_ssn.c b/usr/src/lib/libsmbfs/smb/nb_ssn.c deleted file mode 100644 index 319e250296..0000000000 --- a/usr/src/lib/libsmbfs/smb/nb_ssn.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - */ - -/* - * NetBIOS session service functions - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include "private.h" -#include "charsets.h" - -static int nb_ssn_send(struct smb_ctx *, struct mbdata *, int, int); -static int nb_ssn_recv(struct smb_ctx *, struct mbdata *, int *, int *); -static int nb_ssn_pollin(struct smb_ctx *, int); - -/* - * Send a data message. - */ -int -smb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp) -{ - return (nb_ssn_send(ctx, mbp, 0, mbp->mb_count)); -} - -/* - * Send a NetBIOS message, after - * prepending the 4-byte header. - */ -static int -nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp, - int mtype, int mlen) -{ - mbuf_t *m; - uint32_t hdr, hdrbuf; - int err; - - m = mbp->mb_top; - if (m == NULL) - return (EINVAL); - - /* - * Prepend the NetBIOS header. - * Our mbufs leave space for this. - */ - hdr = (mtype << 24) | mlen; - hdrbuf = htonl(hdr); - m->m_data -= 4; - m->m_len += 4; - bcopy(&hdrbuf, m->m_data, 4); - - /* - * Get contiguous data (so TCP won't fragment) - * Note: replaces mb_top. - */ - err = m_lineup(mbp->mb_top, &mbp->mb_top); - if (err) - return (err); - m = mbp->mb_top; - - /* - * Send it. - */ - if (t_snd(ctx->ct_tran_fd, m->m_data, m->m_len, 0) < 0) { - if (t_errno == TSYSERR) - err = errno; - else - err = EPROTO; - DPRINT("t_snd: t_errno %d, err %d", t_errno, err); - return (err); - } - - return (0); -} - -/* - * Receive a data message. Discard anything else. - * Caller must deal with EAGAIN, EINTR. - */ -int -smb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mbp) -{ - int err, mtype, mlen; - err = nb_ssn_recv(ctx, mbp, &mtype, &mlen); - if (err) - return (err); - if (mtype != NB_SSN_MESSAGE) { - DPRINT("discard type 0x%x", mtype); - mb_done(mbp); - return (EAGAIN); - } - if (mlen == 0) { - DPRINT("zero length"); - mb_done(mbp); - return (EAGAIN); - } - - return (0); -} - -/* - * Receive a NetBIOS message, any type. - * Give caller type and length. - */ -static int -nb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mb, - int *mtype, int *mlen) -{ - char *buf; - uint32_t hdr, hdrbuf; - int cnt, len, err, moreflag; - int fd = ctx->ct_tran_fd; - int tmo = smb_recv_timeout * 1000; - - /* - * Start by getting the header - * (four bytes) - */ - if ((err = nb_ssn_pollin(ctx, tmo)) != 0) { - DPRINT("pollin err %d", err); - return (err); - } - moreflag = 0; - cnt = t_rcv(fd, &hdrbuf, sizeof (hdrbuf), &moreflag); - if (cnt < 0) { - err = get_xti_err(fd); - DPRINT("t_errno %d err %d", t_errno, err); - return (err); - } - - if (cnt != sizeof (hdrbuf)) { - DPRINT("hdr cnt %d", cnt); - return (EPROTO); - } - - /* - * Decode the header, get the length. - */ - hdr = ntohl(hdrbuf); - *mtype = (hdr >> 24) & 0xff; - *mlen = hdr & 0xffffff; - - if (mlen == 0) - return (0); - - /* - * Get a message buffer, read the payload - */ - if ((err = mb_init_sz(mb, *mlen)) != 0) - return (err); - buf = mb->mb_top->m_data; - len = *mlen; - while (len > 0) { - if (!moreflag) { - if ((err = nb_ssn_pollin(ctx, tmo)) != 0) { - DPRINT("pollin err %d", err); - return (err); - } - } - - moreflag = 0; - cnt = t_rcv(fd, buf, len, &moreflag); - if (cnt < 0) { - err = get_xti_err(fd); - DPRINT("t_errno %d err %d", t_errno, err); - return (err); - } - buf += cnt; - len -= cnt; - } - mb->mb_top->m_len = *mlen; - mb->mb_count = *mlen; - - return (0); -} - -int -get_xti_err(int fd) -{ - int look; - if (t_errno == TSYSERR) - return (errno); - - if (t_errno == TLOOK) { - look = t_look(fd); - switch (look) { - case T_DISCONNECT: - (void) t_rcvdis(fd, NULL); - (void) t_snddis(fd, NULL); - return (ECONNRESET); - case T_ORDREL: - /* Received orderly release indication */ - (void) t_rcvrel(fd); - /* Send orderly release indicator */ - (void) t_sndrel(fd); - return (ECONNRESET); - } - } - return (EPROTO); -} - -/* - * Wait for data we can receive. - * Timeout is mSec., as for poll(2) - */ -static int -nb_ssn_pollin(struct smb_ctx *ctx, int tmo) -{ - struct pollfd pfd[1]; - int cnt, err; - - pfd[0].fd = ctx->ct_tran_fd; - pfd[0].events = POLLIN | POLLPRI; - pfd[0].revents = 0; - cnt = poll(pfd, 1, tmo); - switch (cnt) { - case 0: - err = ETIME; - break; - case -1: - err = errno; - break; - default: - err = 0; - break; - } - return (err); -} - -/* - * Send a NetBIOS session request and - * wait for the response. - */ -int -nb_ssn_request(struct smb_ctx *ctx, char *srvname) -{ - struct mbdata req, res; - struct nb_name lcl, srv; - int err, mtype, mlen; - char *ucwks; - - bzero(&req, sizeof (req)); - bzero(&res, sizeof (res)); - - if ((err = mb_init(&req)) != 0) - goto errout; - - ucwks = utf8_str_toupper(ctx->ct_locname); - if (ucwks == NULL) { - err = ENOMEM; - goto errout; - } - - /* Local NB name. */ - snprintf(lcl.nn_name, NB_NAMELEN, "%-15.15s", ucwks); - lcl.nn_type = NBT_WKSTA; - lcl.nn_scope = ctx->ct_nb->nb_scope; - - /* Server NB name */ - snprintf(srv.nn_name, NB_NAMELEN, "%-15.15s", srvname); - srv.nn_type = NBT_SERVER; - srv.nn_scope = ctx->ct_nb->nb_scope; - - /* - * Build the request. Header is prepended later. - */ - if ((err = nb_name_encode(&req, &srv)) != 0) - goto errout; - if ((err = nb_name_encode(&req, &lcl)) != 0) - goto errout; - - /* - * Send it, wait for the reply. - */ - err = nb_ssn_send(ctx, &req, NB_SSN_REQUEST, req.mb_count); - if (err) { - DPRINT("send, err %d", err); - goto errout; - } - err = nb_ssn_recv(ctx, &res, &mtype, &mlen); - if (err) { - DPRINT("recv, err %d", err); - goto errout; - } - - if (mtype != NB_SSN_POSRESP) { - DPRINT("recv, mtype 0x%x", mtype); - err = ECONNREFUSED; - goto errout; - } - - return (0); - -errout: - mb_done(&res); - mb_done(&req); - return (err); -} diff --git a/usr/src/lib/libsmbfs/smb/negprot.c b/usr/src/lib/libsmbfs/smb/negprot.c deleted file mode 100644 index 770b742c44..0000000000 --- a/usr/src/lib/libsmbfs/smb/negprot.c +++ /dev/null @@ -1,457 +0,0 @@ -/* - * Copyright (c) 2000-2001 Boris Popov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Boris Popov. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. - */ - -/* - * SMB Negotiate Protocol, and related. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "charsets.h" -#include "smb_crypt.h" -#include "private.h" - -/* - * SMB dialects that we know about. - */ -struct smb_dialect { - int d_id; - const char *d_name; -}; -static struct smb_dialect smb_dialects[] = { - {SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"}, - {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"}, - {SMB_DIALECT_LANMAN2_0, "LM1.2X002"}, - {SMB_DIALECT_LANMAN2_1, "LANMAN2.1"}, - {SMB_DIALECT_NTLM0_12, "NT LM 0.12"}, - {-1, NULL} -}; - -#define SMB_DIALECT_MAX \ - (sizeof (smb_dialects) / sizeof (struct smb_dialect) - 2) - -static const uint32_t smb_clnt_caps_mask = - SMB_CAP_UNICODE | - SMB_CAP_LARGE_FILES | - SMB_CAP_NT_SMBS | - SMB_CAP_STATUS32 | - SMB_CAP_EXT_SECURITY; - -/* - * SMB Negotiate Protocol - * Based on code from the driver: smb_smb.c - * - * If using Extended Security, oblob (output) - * will hold the initial security "hint". - */ -int -smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob) -{ - struct smb_sopt *sv = &ctx->ct_sopt; - struct smb_iods *is = &ctx->ct_iods; - struct smb_rq *rqp; - struct mbdata *mbp; - struct smb_dialect *dp; - int err, len; - uint8_t wc, eklen; - uint16_t dindex, bc; - int will_sign = 0; - - /* - * Initialize: vc_hflags and vc_hflags2. - * Note: ctx->ct_hflags* are copied into the - * (per request) rqp->rq_hflags* by smb_rq_init. - * - * Like Windows, set FLAGS2_UNICODE in our first request, - * even though technically we don't yet know whether the - * server supports Unicode. Will clear this flag below - * if we find out it doesn't. Need to do this because - * some servers reject all non-Unicode requests. - */ - ctx->ct_hflags = - SMB_FLAGS_CASELESS | - SMB_FLAGS_CANONICAL_PATHNAMES; - ctx->ct_hflags2 = - SMB_FLAGS2_KNOWS_LONG_NAMES | - SMB_FLAGS2_KNOWS_EAS | - /* SMB_FLAGS2_IS_LONG_NAME |? */ - /* EXT_SEC (see below) */ - SMB_FLAGS2_ERR_STATUS | - SMB_FLAGS2_UNICODE; - - /* - * Sould we offer extended security? - * We'll turn this back off below if - * the server doesn't support it. - */ - if (ctx->ct_vopt & SMBVOPT_EXT_SEC) - ctx->ct_hflags2 |= SMB_FLAGS2_EXT_SEC; - - /* - * The initial UID needs to be zero, - * or Windows XP says "bad user". - * The initial TID is all ones, but - * we don't use it or store it here - * because the driver handles that. - */ - is->is_smbuid = 0; - - /* - * In case we're reconnecting, - * free previous stuff. - */ - ctx->ct_mac_seqno = 0; - if (ctx->ct_mackey != NULL) { - free(ctx->ct_mackey); - ctx->ct_mackey = NULL; - ctx->ct_mackeylen = 0; - } - - sv = &ctx->ct_sopt; - bzero(sv, sizeof (struct smb_sopt)); - - err = smb_rq_init(ctx, SMB_COM_NEGOTIATE, &rqp); - if (err) - return (err); - - /* - * Build the SMB request. - */ - mbp = &rqp->rq_rq; - mb_put_uint8(mbp, 0); /* word count */ - smb_rq_bstart(rqp); - for (dp = smb_dialects; dp->d_id != -1; dp++) { - mb_put_uint8(mbp, SMB_DT_DIALECT); - mb_put_astring(mbp, dp->d_name); - } - smb_rq_bend(rqp); - - /* - * This does the OTW call - */ - err = smb_rq_internal(ctx, rqp); - if (err) { - DPRINT("call failed, err %d", err); - goto errout; - } - if (rqp->rq_status != 0) { - DPRINT("nt status 0x%x", rqp->rq_status); - err = EBADRPC; - goto errout; - } - - /* - * Decode the response - * - * Comments to right show names as described in - * The Microsoft SMB Protocol spec. [MS-SMB] - * section 2.2.3 - */ - mbp = &rqp->rq_rp; - (void) md_get_uint8(mbp, &wc); - err = md_get_uint16le(mbp, &dindex); - if (err || dindex > SMB_DIALECT_MAX) { - DPRINT("err %d dindex %d", err, (int)dindex); - goto errout; - } - dp = smb_dialects + dindex; - sv->sv_proto = dp->d_id; - DPRINT("Dialect %s", dp->d_name); - if (dp->d_id < SMB_DIALECT_NTLM0_12) { - /* XXX: User-visible warning too? */ - DPRINT("old dialect %s", dp->d_name); - goto errout; - } - if (wc != 17) { - DPRINT("bad wc %d", (int)wc); - goto errout; - } - md_get_uint8(mbp, &sv->sv_sm); /* SecurityMode */ - md_get_uint16le(mbp, &sv->sv_maxmux); /* MaxMpxCount */ - md_get_uint16le(mbp, &sv->sv_maxvcs); /* MaxCountVCs */ - md_get_uint32le(mbp, &sv->sv_maxtx); /* MaxBufferSize */ - md_get_uint32le(mbp, &sv->sv_maxraw); /* MaxRawSize */ - md_get_uint32le(mbp, &sv->sv_skey); /* SessionKey */ - md_get_uint32le(mbp, &sv->sv_caps); /* Capabilities */ - md_get_mem(mbp, NULL, 8, MB_MSYSTEM); /* SystemTime(s) */ - md_get_uint16le(mbp, (uint16_t *)&sv->sv_tz); - md_get_uint8(mbp, &eklen); /* EncryptionKeyLength */ - err = md_get_uint16le(mbp, &bc); /* ByteCount */ - if (err) - goto errout; - - /* BEGIN CSTYLED */ - /* - * Will we do SMB signing? Or block the connection? - * The table below describes this logic. References: - * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3] - * http://msdn.microsoft.com/en-us/library/cc212511.aspx - * http://msdn.microsoft.com/en-us/library/cc212929.aspx - * - * Srv/Cli | Required | Enabled | If Required | Disabled - * ------------+----------+------------+-------------+----------- - * Required | Signed | Signed | Signed | Blocked [1] - * ------------+----------+------------+-------------+----------- - * Enabled | Signed | Signed | Not Signed | Not Signed - * ------------+----------+------------+-------------+----------- - * If Required | Signed | Not Signed | Not Signed | Not Signed - * ------------+----------+------------+-------------+----------- - * Disabled | Blocked | Not Signed | Not Signed | Not Signed - * - * [1] Like Windows 2003 and later, we don't really implement - * the "Disabled" setting. Instead we implement "If Required", - * so we always sign if the server requires signing. - */ - /* END CSTYLED */ - - if (sv->sv_sm & SMB_SM_SIGS_REQUIRE) { - /* - * Server requires signing. We will sign, - * even if local setting is "disabled". - */ - will_sign = 1; - } else if (sv->sv_sm & SMB_SM_SIGS) { - /* - * Server enables signing (client's option). - * If enabled locally, do signing. - */ - if (ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED) - will_sign = 1; - /* else not signing. */ - } else { - /* - * Server does not support signing. - * If we "require" it, bail now. - */ - if (ctx->ct_vopt & SMBVOPT_SIGNING_REQUIRED) { - DPRINT("Client requires signing " - "but server has it disabled."); - err = EBADRPC; - goto errout; - } - } - - if (will_sign) { - ctx->ct_vcflags |= SMBV_WILL_SIGN; - } - DPRINT("Security signatures: %d", will_sign); - - /* See comment above re. FLAGS2_UNICODE */ - if (sv->sv_caps & SMB_CAP_UNICODE) - ctx->ct_vcflags |= SMBV_UNICODE; - else - ctx->ct_hflags2 &= ~SMB_FLAGS2_UNICODE; - - if ((sv->sv_caps & SMB_CAP_STATUS32) == 0) { - /* - * They don't do NT error codes. - * - * If we send requests with - * SMB_FLAGS2_ERR_STATUS set in - * Flags2, Windows 98, at least, - * appears to send replies with that - * bit set even though it sends back - * DOS error codes. (They probably - * just use the request header as - * a template for the reply header, - * and don't bother clearing that bit.) - * - * Therefore, we clear that bit in - * our vc_hflags2 field. - */ - ctx->ct_hflags2 &= ~SMB_FLAGS2_ERR_STATUS; - } - if (dp->d_id == SMB_DIALECT_NTLM0_12 && - sv->sv_maxtx < 4096 && - (sv->sv_caps & SMB_CAP_NT_SMBS) == 0) { - ctx->ct_vcflags |= SMBV_WIN95; - DPRINT("Win95 detected"); - } - - /* - * The rest of the message varies depending on - * whether we've negotiated "extended security". - * - * With extended security, we have: - * Server_GUID (length 16) - * Security_BLOB - * Otherwise we have: - * EncryptionKey (length is eklen) - * PrimaryDomain - */ - if (sv->sv_caps & SMB_CAP_EXT_SECURITY) { - struct mbuf *m; - DPRINT("Ext.Security: yes"); - - /* - * Skip the server GUID. - */ - err = md_get_mem(mbp, NULL, SMB_GUIDLEN, MB_MSYSTEM); - if (err) - goto errout; - /* - * Remainder is the security blob. - * Note: eklen "must be ignored" [MS-SMB] - */ - len = (int)bc - SMB_GUIDLEN; - if (len < 0) - goto errout; - - /* - * Get the (optional) SPNEGO "hint". - */ - err = md_get_mbuf(mbp, len, &m); - if (err) - goto errout; - mb_initm(oblob, m); - oblob->mb_count = len; - } else { - DPRINT("Ext.Security: no"); - ctx->ct_hflags2 &= ~SMB_FLAGS2_EXT_SEC; - - /* - * Save the "Encryption Key" (the challenge). - * - * Sanity check: make sure the sec. blob length - * isn't bigger than the byte count. - */ - if (bc < eklen || eklen < NTLM_CHAL_SZ) { - err = EBADRPC; - goto errout; - } - err = md_get_mem(mbp, ctx->ct_srv_chal, - NTLM_CHAL_SZ, MB_MSYSTEM); - /* - * Server domain follows (ignored) - * Note: NOT aligned(2) - unusual! - */ - } - - smb_rq_done(rqp); - - /* - * A few sanity checks on what we received, - * becuse we will send these in ssnsetup. - * - * Maximum outstanding requests (we care), - * and Max. VCs (we only use one). Also, - * MaxBufferSize lower limit per spec. - */ - if (sv->sv_maxmux < 1) - sv->sv_maxmux = 1; - if (sv->sv_maxvcs < 1) - sv->sv_maxvcs = 1; - if (sv->sv_maxtx < 1024) - sv->sv_maxtx = 1024; - - /* - * Maximum transfer size. - * Sanity checks: - * - * Let's be conservative about an upper limit here. - * Win2k uses 16644 (and others) so 32k should be a - * reasonable sanity limit for this value. - * - * Note that this limit does NOT affect READX/WRITEX - * with CAP_LARGE_..., which we nearly always use. - */ - is->is_txmax = sv->sv_maxtx; - if (is->is_txmax > 0x8000) - is->is_txmax = 0x8000; - - /* - * Max read/write sizes, WITHOUT overhead. - * This is just the payload size, so we must - * leave room for the SMB headers, etc. - * This is just the ct_txmax value, but - * reduced and rounded down. Tricky bit: - * - * Servers typically give us a value that's - * some nice "round" number, i.e 0x4000 plus - * some overhead, i.e. Win2k: 16644==0x4104 - * Subtract for the SMB header (32) and the - * SMB command word and byte vectors (34?), - * then round down to a 512 byte multiple. - */ - len = is->is_txmax - 68; - len &= 0xFE00; - /* XXX: Not sure yet which of these to keep. */ - is->is_rwmax = len; - is->is_rxmax = len; - is->is_wxmax = len; - - /* - * Most of the "capability" bits we offer in session setup - * are just copied from those offered by the server. - */ - ctx->ct_clnt_caps = sv->sv_caps & smb_clnt_caps_mask; - - /* Get the client nonce. */ - (void) smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ); - - return (0); - -errout: - smb_rq_done(rqp); - if (err == 0) - err = EBADRPC; - return (err); -} diff --git a/usr/src/lib/libsmbfs/smb/ntlm.c b/usr/src/lib/libsmbfs/smb/ntlm.c index 9f08a2eaca..44b26f54e6 100644 --- a/usr/src/lib/libsmbfs/smb/ntlm.c +++ b/usr/src/lib/libsmbfs/smb/ntlm.c @@ -34,7 +34,7 @@ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -184,7 +184,8 @@ ntlm_v1_session_key(uchar_t *ssn_key, const uchar_t *nt_hash) */ int ntlm_put_v1_responses(struct smb_ctx *ctx, - struct mbdata *lm_mbp, struct mbdata *nt_mbp) + struct mbdata *lm_mbp, struct mbdata *nt_mbp, + uchar_t *ssn_key) { uchar_t *lmresp, *ntresp; int err; @@ -229,7 +230,7 @@ ntlm_put_v1_responses(struct smb_ctx *ctx, /* * Compute the session key */ - ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash); + ntlm_v1_session_key(ssn_key, ctx->ct_nthash); return (err); } @@ -245,7 +246,8 @@ ntlm_put_v1_responses(struct smb_ctx *ctx, */ int ntlm_put_v1x_responses(struct smb_ctx *ctx, - struct mbdata *lm_mbp, struct mbdata *nt_mbp) + struct mbdata *lm_mbp, struct mbdata *nt_mbp, + uchar_t *ssn_key) { MD5_CTX context; uchar_t challenges[2 * NTLM_CHAL_SZ]; @@ -299,7 +301,7 @@ ntlm_put_v1x_responses(struct smb_ctx *ctx, /* * Compute the session key */ - ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash); + ntlm_v1_session_key(ssn_key, ctx->ct_nthash); return (err); } @@ -477,7 +479,8 @@ ntlm_v2_session_key(uchar_t *ssn_key, */ int ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp, - struct mbdata *lm_mbp, struct mbdata *nt_mbp) + struct mbdata *lm_mbp, struct mbdata *nt_mbp, + uchar_t *ssn_key) { uchar_t *lmresp, *ntresp; int err; @@ -547,7 +550,7 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp, /* * Compute the session key */ - ntlm_v2_session_key(ctx->ct_ssn_key, v2hash, ntresp); + ntlm_v2_session_key(ssn_key, v2hash, ntresp); out: if (err) { @@ -649,38 +652,14 @@ out: return (err); } -/* - * Build the MAC key (for SMB signing) - */ -int -ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp) -{ - struct mbuf *m; - size_t len; - char *p; - - /* - * MAC_key = concat(session_key, nt_response) - */ - m = ntresp_mbp->mb_top; - len = NTLM_HASH_SZ + m->m_len; - if ((p = malloc(len)) == NULL) - return (ENOMEM); - ctx->ct_mackeylen = len; - ctx->ct_mackey = p; - memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ); - memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len); - - return (0); -} - /* * Helper for ntlmssp_put_type3 - Build the "key exchange key" * used when we have both NTLM(v1) and NTLMSSP_NEGOTIATE_NTLM2. * HMAC_MD5(SessionBaseKey, concat(ServerChallenge, LmResponse[0..7])) */ void -ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey) +ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, + uchar_t *ssn_key, uchar_t *kxkey) { uchar_t data[NTLM_HASH_SZ]; uchar_t *p = mtod(lm_mbp->mb_top, uchar_t *); @@ -690,6 +669,6 @@ ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey) memcpy(data + NTLM_CHAL_SZ, p, NTLM_CHAL_SZ); /* HMAC_MD5(SessionBaseKey, concat(...)) */ - HMACT64(kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ, + HMACT64(kxkey, ssn_key, NTLM_HASH_SZ, data, NTLM_HASH_SZ); } diff --git a/usr/src/lib/libsmbfs/smb/ntlm.h b/usr/src/lib/libsmbfs/smb/ntlm.h index 447033b516..d0c093689a 100644 --- a/usr/src/lib/libsmbfs/smb/ntlm.h +++ b/usr/src/lib/libsmbfs/smb/ntlm.h @@ -22,7 +22,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _NTLM_H @@ -38,7 +39,7 @@ * NTLM_HASH_SZ: 16 bytes (see smb_lib.h) * NTLM_CHAL_SZ: 8 bytes (see smb_lib.h) */ -#define NTLM_V1_RESP_SZ 24 /* response size */ +#define NTLM_V1_RESP_SZ 24 /* response size */ #define NAMETYPE_EOL 0x0000 /* end of list of names */ #define NAMETYPE_MACHINE_NB 0x0001 /* NetBIOS machine name */ @@ -57,20 +58,21 @@ ntlm_build_target_info(struct smb_ctx *, struct mbuf *, struct mbdata *); int ntlm_put_v1_responses(struct smb_ctx *ctx, - struct mbdata *lm_mbp, struct mbdata *nt_mbp); + struct mbdata *lm_mbp, struct mbdata *nt_mbp, + uchar_t *ssnkey); int ntlm_put_v1x_responses(struct smb_ctx *ctx, - struct mbdata *lm_mbp, struct mbdata *nt_mbp); + struct mbdata *lm_mbp, struct mbdata *nt_mbp, + uchar_t *ssnkey); int ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp, - struct mbdata *lm_mbp, struct mbdata *nt_mbp); - -int -ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp); + struct mbdata *lm_mbp, struct mbdata *nt_mbp, + uchar_t *ssnkey); void -ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey); +ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, + uchar_t *ssn_key, uchar_t *kxkey); #endif /* _NTLM_H */ diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.c b/usr/src/lib/libsmbfs/smb/ntlmssp.c index f39fa594ec..5ae583114d 100644 --- a/usr/src/lib/libsmbfs/smb/ntlmssp.c +++ b/usr/src/lib/libsmbfs/smb/ntlmssp.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -67,13 +67,14 @@ #include "ntlmssp.h" /* A shorter alias for a crazy long name from [MS-NLMP] */ -#define NTLMSSP_NEGOTIATE_NTLM2 \ +#define NTLMSSP_NEGOTIATE_ESS \ NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY typedef struct ntlmssp_state { uint32_t ss_flags; char *ss_target_name; /* Primary domain or server name */ struct mbuf *ss_target_info; + uchar_t ss_ssnkey[NTLM_HASH_SZ]; uchar_t ss_kxkey[NTLM_HASH_SZ]; } ntlmssp_state_t; @@ -90,8 +91,7 @@ struct sec_buf { static const char ntlmssp_id[ID_SZ] = "NTLMSSP"; static int -ntlm_rand_ssn_key(struct smb_ctx *ctx, - ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp); +ntlm_rand_ssn_key(ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp); /* * Get a "security buffer" (header part) @@ -249,16 +249,14 @@ ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb) NTLMSSP_NEGOTIATE_SEAL | /* NTLMSSP_NEGOTIATE_LM_KEY (never) */ NTLMSSP_NEGOTIATE_NTLM | - /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN (set below) */ - NTLMSSP_NEGOTIATE_NTLM2 | + NTLMSSP_NEGOTIATE_ALWAYS_SIGN | + NTLMSSP_NEGOTIATE_ESS | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_KEY_EXCH | NTLMSSP_NEGOTIATE_56; - if (ctx->ct_vcflags & SMBV_WILL_SIGN) { - ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; - ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; - } + if ((ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED) == 0) + ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN; bcopy(ntlmssp_id, &hdr.h_id, ID_SZ); hdr.h_type = NTLMSSP_MSGTYPE_NEGOTIATE; @@ -447,15 +445,20 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb) /* * We're setting up a NULL session, meaning * the lm_mbc, nt_mbc parts remain empty. - * Let's add the "anon" flag (hint). - * As there is no session key, disable the - * fancy session key stuff. + * Let's add the "anon" flag (hint), and + * as we have no OWF hashes, we can't use + * "extended session security" (_ESS). + * The SessionBaseKey is all zeros, so + * the KeyExchangeKey is too. Otherwise + * this is like NTLMv2/LMv2 */ - hdr.h_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION; - ssp_st->ss_flags &= ~( - NTLMSSP_NEGOTIATE_NTLM2 | - NTLMSSP_NEGOTIATE_KEY_EXCH); + ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION; + ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ESS; + hdr.h_flags = ssp_st->ss_flags; err = 0; + /* KeyExchangeKey = SessionBaseKey = (zeros) */ + memset(ssp_st->ss_ssnkey, 0, NTLM_HASH_SZ); + memset(ssp_st->ss_kxkey, 0, NTLM_HASH_SZ); } else if (ctx->ct_authflags & SMB_AT_NTLM2) { /* * Doing NTLMv2/LMv2 @@ -465,47 +468,49 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb) if (err) goto out; err = ntlm_put_v2_responses(ctx, &ti_mbc, - &lm_mbc, &nt_mbc); + &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey); if (err) goto out; - /* The "key exg. key" is the session base key */ - memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ); - - } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_NTLM2) { + /* KeyExchangeKey = SessionBaseKey (v2) */ + memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ); + } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_ESS) { /* * Doing NTLM ("v1x") which is NTLM with * "Extended Session Security" */ err = ntlm_put_v1x_responses(ctx, - &lm_mbc, &nt_mbc); + &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey); if (err) goto out; - /* Compute the "Key exchange key". */ - ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_kxkey); + /* + * "v1x computes the KeyExchangeKey from both the + * server and client nonce and (v1) SessionBaseKey. + */ + ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_ssnkey, + ssp_st->ss_kxkey); } else { /* * Doing plain old NTLM (and LM if enabled) */ err = ntlm_put_v1_responses(ctx, - &lm_mbc, &nt_mbc); + &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey); if (err) goto out; - /* The "key exg. key" is the session base key */ - memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ); + /* KeyExchangeKey = SessionBaseKey (v1) */ + memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ); } /* - * Compute the "Exported Session Key" and (possibly) - * the "Encrypted Random Sesion Key". - * [MS-NLMP 3.1.5.1.2] + * Compute the "ExportedSessionKey" and (possibly) the + * "EncryptedRandomSesionKey". [MS-NLMP 3.1.5.1.2] */ if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { - err = ntlm_rand_ssn_key(ctx, ssp_st, &ek_mbc); + err = ntlm_rand_ssn_key(ssp_st, &ek_mbc); if (err) goto out; } else { /* ExportedSessionKey is the KeyExchangeKey */ - memcpy(ctx->ct_ssn_key, ssp_st->ss_kxkey, NTLM_HASH_SZ); + memcpy(ssp_st->ss_ssnkey, ssp_st->ss_kxkey, NTLM_HASH_SZ); /* EncryptedRandomSessionKey remains NULL */ } @@ -590,7 +595,6 @@ out: */ static int ntlm_rand_ssn_key( - struct smb_ctx *ctx, ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp) { @@ -603,12 +607,12 @@ ntlm_rand_ssn_key( encr_ssn_key = mb_reserve(ek_mbp, NTLM_HASH_SZ); /* Set "ExportedSessionKey to NONCE(16) */ - (void) smb_get_urandom(ctx->ct_ssn_key, NTLM_HASH_SZ); + (void) smb_get_urandom(ssp_st->ss_ssnkey, NTLM_HASH_SZ); /* Set "EncryptedRandomSessionKey" to RC4(...) */ err = smb_encrypt_RC4(encr_ssn_key, NTLM_HASH_SZ, ssp_st->ss_kxkey, NTLM_HASH_SZ, - ctx->ct_ssn_key, NTLM_HASH_SZ); + ssp_st->ss_ssnkey, NTLM_HASH_SZ); return (err); } @@ -617,34 +621,29 @@ ntlm_rand_ssn_key( * ntlmssp_final * * Called after successful authentication. - * Setup the MAC key for signing. + * Save the session key. */ int ntlmssp_final(struct ssp_ctx *sp) { struct smb_ctx *ctx = sp->smb_ctx; + ntlmssp_state_t *ssp_st = sp->sp_private; int err = 0; /* - * MAC_key is just the session key, but - * Only on the first successful auth. + * Update/save the session key. */ - if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) && - (ctx->ct_mackey == NULL)) { - ctx->ct_mackeylen = NTLM_HASH_SZ; - ctx->ct_mackey = malloc(ctx->ct_mackeylen); - if (ctx->ct_mackey == NULL) { - ctx->ct_mackeylen = 0; - err = ENOMEM; - goto out; - } - memcpy(ctx->ct_mackey, ctx->ct_ssn_key, NTLM_HASH_SZ); - /* - * Apparently, the server used seq. no. zero - * for our previous message, so next is two. - */ - ctx->ct_mac_seqno = 2; + if (ctx->ct_ssnkey_buf != NULL) { + free(ctx->ct_ssnkey_buf); + ctx->ct_ssnkey_buf = NULL; } + ctx->ct_ssnkey_buf = malloc(NTLM_HASH_SZ); + if (ctx->ct_ssnkey_buf == NULL) { + err = ENOMEM; + goto out; + } + ctx->ct_ssnkey_len = NTLM_HASH_SZ; + memcpy(ctx->ct_ssnkey_buf, ssp_st->ss_ssnkey, NTLM_HASH_SZ); out: return (err); @@ -728,13 +727,17 @@ int ntlmssp_init_client(struct ssp_ctx *sp) { ntlmssp_state_t *ssp_st; + smb_ctx_t *ctx = sp->smb_ctx; - if ((sp->smb_ctx->ct_authflags & + if ((ctx->ct_authflags & (SMB_AT_NTLM2 | SMB_AT_NTLM1 | SMB_AT_ANON)) == 0) { DPRINT("No NTLM authflags"); return (EINVAL); } + /* Get the client nonce. */ + (void) smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ); + ssp_st = calloc(1, sizeof (*ssp_st)); if (ssp_st == NULL) return (ENOMEM); diff --git a/usr/src/lib/libsmbfs/smb/private.h b/usr/src/lib/libsmbfs/smb/private.h index febca40126..d877cafa1d 100644 --- a/usr/src/lib/libsmbfs/smb/private.h +++ b/usr/src/lib/libsmbfs/smb/private.h @@ -31,9 +31,10 @@ */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _PRIVATE_H @@ -60,60 +61,6 @@ extern void dprint(const char *, const char *, ...) #define DPRINT(...) ((void)0) #endif -/* - * Flags bits in ct_vcflags (copied from smb_conn.h) - * Pass these to the driver? - */ -#define SMBV_RECONNECTING 0x0002 /* conn in process of reconnection */ -#define SMBV_LONGNAMES 0x0004 /* conn configured to use long names */ -#define SMBV_ENCRYPT 0x0008 /* server demands encrypted password */ -#define SMBV_WIN95 0x0010 /* used to apply bugfixes for this OS */ -#define SMBV_NT4 0x0020 /* used when NT4 issues invalid resp */ -#define SMBV_UNICODE 0x0040 /* conn configured to use Unicode */ -#define SMBV_EXT_SEC 0x0080 /* conn to use extended security */ -#define SMBV_WILL_SIGN 0x0100 /* negotiated signing */ - -/* - * request handling structures - */ -struct smb_rq { - struct smb_ctx *rq_ctx; - struct mbdata rq_rq; - struct mbdata rq_rp; - int rq_rpbufsz; - uint8_t rq_cmd; - uint8_t rq_hflags; - uint16_t rq_hflags2; - uint32_t rq_status; - uint16_t rq_uid; - uint16_t rq_tid; - uint16_t rq_mid; - uint32_t rq_seqno; - /* See rq_[bw]{start,end} functions */ - char *rq_wcntp; - int rq_wcbase; - char *rq_bcntp; - int rq_bcbase; -}; -typedef struct smb_rq smb_rq_t; - -#define smb_rq_getrequest(rqp) (&(rqp)->rq_rq) -#define smb_rq_getreply(rqp) (&(rqp)->rq_rp) - -int smb_rq_init(struct smb_ctx *, uchar_t, struct smb_rq **); -void smb_rq_done(struct smb_rq *); -void smb_rq_bstart(struct smb_rq *); -void smb_rq_bend(struct smb_rq *); -void smb_rq_wstart(struct smb_rq *); -void smb_rq_wend(struct smb_rq *); -int smb_rq_simple(struct smb_rq *); -int smb_rq_dmem(struct mbdata *, const char *, size_t); -int smb_rq_internal(struct smb_ctx *, struct smb_rq *); -void smb_rq_sign(struct smb_rq *); -int smb_rq_verify(struct smb_rq *); -int smb_t2_request(int, int, uint16_t *, const char *, - int, void *, int, void *, int *, void *, int *, void *, int *); - /* * This library extends the mchain.h function set a little. */ @@ -174,16 +121,7 @@ int smb_ctx_getaddr(struct smb_ctx *ctx); int smb_ctx_gethandle(struct smb_ctx *ctx); int smb_iod_start(struct smb_ctx *); - -int smb_ssn_send(struct smb_ctx *, struct mbdata *); -int smb_ssn_recv(struct smb_ctx *, struct mbdata *); - -int smb_negprot(struct smb_ctx *, struct mbdata *); - -int smb_ssnsetup_null(struct smb_ctx *); -int smb_ssnsetup_ntlm1(struct smb_ctx *); -int smb_ssnsetup_ntlm2(struct smb_ctx *); -int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *); +const char *smb_iod_state_name(enum smbiod_state st); void smb_time_local2server(struct timeval *, int, long *); void smb_time_server2local(ulong_t, int, struct timeval *); diff --git a/usr/src/lib/libsmbfs/smb/rap.c b/usr/src/lib/libsmbfs/smb/rap.c deleted file mode 100644 index 546ee46f05..0000000000 --- a/usr/src/lib/libsmbfs/smb/rap.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. - * 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. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "private.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) -{ - int len = 0; - uint_t uv = (uint_t)value; - uint32_t *lp; - uint16_t *sp; - char *p; - - switch (ptype) { - case 'L': - case 'W': - /* LINTED */ - sp = (uint16_t *)rap->r_npbuf; - *sp = htoles(uv); - len = sizeof (*sp); - break; - case 'D': - /* LINTED */ - lp = (uint32_t *)rap->r_npbuf; - *lp = htolel(uv); - len = sizeof (*lp); - break; - case 'b': - p = rap->r_npbuf; - memset(p, uv, plen); - len = plen; - break; - 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; - - 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); - if (rap->r_pbuf == NULL) - return (ENOMEM); - (void) smb_rap_rqparam(rap, 'W', 1, fn); - (void) smb_rap_rqparam_z(rap, rap->r_sparam); - (void) 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); -} - -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; - char *dp, *p = rap->r_nparam; - char ptype; - int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow; - - rdatacnt = rap->r_rcvbuflen; - rparamcnt = rap->r_plen; - error = smb_t2_request(ctx->ct_dev_fd, - 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); -} diff --git a/usr/src/lib/libsmbfs/smb/rq.c b/usr/src/lib/libsmbfs/smb/rq.c deleted file mode 100644 index f6004dfa06..0000000000 --- a/usr/src/lib/libsmbfs/smb/rq.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * 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 $ - */ - -/* - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "private.h" - -#define MIN_REPLY_SIZE 4096 - -static uint32_t smb_map_doserr(uint8_t, uint16_t); - -/* - * Create and initialize a request structure, for either an - * "internal" request (one that does not use the driver) or - * a regular "driver" request, that uses driver ioctls. - * - * The two kinds are built a little differently: - * Driver requests are composed starting with the - * first word of the "variable word vector" section. - * The driver prepends the SMB header and word count. - * The driver also needs an output buffer to receive - * the response, filled in via copyout in the ioctl. - * - * Internal requests are composed entirely in this library. - * Space for the SMB header is reserved here, and later - * filled in by smb_rq_internal before the send/receive. - */ -int -smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, struct smb_rq **rqpp) -{ - struct smb_rq *rqp; - - rqp = malloc(sizeof (*rqp)); - if (rqp == NULL) - goto errout; - bzero(rqp, sizeof (*rqp)); - rqp->rq_cmd = cmd; - rqp->rq_ctx = ctx; - - /* - * Setup the request buffer. - * Do the reply buffer later. - */ - if (mb_init(&rqp->rq_rq)) - goto errout; - - /* Space for the SMB header. (filled in later) */ - mb_put_mem(&rqp->rq_rq, NULL, SMB_HDRLEN, MB_MSYSTEM); - - /* - * Copy the ctx flags here, so the caller can - * update the req flags before the OTW call. - */ - rqp->rq_hflags = ctx->ct_hflags; - rqp->rq_hflags2 = ctx->ct_hflags2; - - *rqpp = rqp; - return (0); - -errout: - if (rqp) { - smb_rq_done(rqp); - free(rqp); - } - return (ENOMEM); -} - -void -smb_rq_done(struct smb_rq *rqp) -{ - mb_done(&rqp->rq_rp); - mb_done(&rqp->rq_rq); - free(rqp); -} - -/* - * Reserve space for the word count, which is filled in later by - * smb_rq_wend(). Also initialize the counter that it uses - * to figure out what value to fill in. - * - * Note that the word count happens to be 8-bits, - * which can lead to confusion. - */ -void -smb_rq_wstart(struct smb_rq *rqp) -{ - struct mbdata *mbp = &rqp->rq_rq; - - (void) mb_fit(mbp, 1, &rqp->rq_wcntp); - rqp->rq_wcbase = mbp->mb_count; -} - -/* - * Fill in the word count, in the space reserved by - * smb_rq_wstart(). - */ -void -smb_rq_wend(struct smb_rq *rqp) -{ - struct mbdata *mbp = &rqp->rq_rq; - int wcnt; - - if (rqp->rq_wcntp == NULL) { - DPRINT("no wcount ptr\n"); - return; - } - wcnt = mbp->mb_count - rqp->rq_wcbase; - if (wcnt > 0x1ff) - DPRINT("word count too large (%d)\n", wcnt); - if (wcnt & 1) - DPRINT("odd word count\n"); - wcnt >>= 1; - - /* - * Fill in the word count (8-bits). - * Also store it in the rq, in case - * we're using the ioctl path. - */ - *rqp->rq_wcntp = (char)wcnt; -} - -/* - * Reserve space for the byte count, which is filled in later by - * smb_rq_bend(). Also initialize the counter that it uses - * to figure out what value to fill in. - * - * Note that the byte count happens to be 16-bits, - * which can lead to confusion. - */ -void -smb_rq_bstart(struct smb_rq *rqp) -{ - struct mbdata *mbp = &rqp->rq_rq; - - (void) mb_fit(mbp, 2, &rqp->rq_bcntp); - rqp->rq_bcbase = mbp->mb_count; -} - -/* - * Fill in the byte count, in the space reserved by - * smb_rq_bstart(). - */ -void -smb_rq_bend(struct smb_rq *rqp) -{ - struct mbdata *mbp = &rqp->rq_rq; - int bcnt; - - if (rqp->rq_bcntp == NULL) { - DPRINT("no bcount ptr\n"); - return; - } - bcnt = mbp->mb_count - rqp->rq_bcbase; - if (bcnt > 0xffff) - DPRINT("byte count too large (%d)\n", bcnt); - /* - * Fill in the byte count (16-bits). - * Also store it in the rq, in case - * we're using the ioctl path. - * - * The pointer is char * type due to - * typical off-by-one alignment. - */ - rqp->rq_bcntp[0] = bcnt & 0xFF; - rqp->rq_bcntp[1] = (bcnt >> 8); -} - -int -smb_rq_simple(struct smb_rq *rqp) -{ - struct smbioc_rq krq; - struct mbdata *mbp; - mbuf_t *m; - char *data; - uint32_t len; - size_t rpbufsz; - int error; - - bzero(&krq, sizeof (krq)); - krq.ioc_cmd = rqp->rq_cmd; - - /* - * Make the SMB request body contiguous, - * and fill in the ioctl request. - */ - mbp = smb_rq_getrequest(rqp); - error = m_lineup(mbp->mb_top, &mbp->mb_top); - if (error) - return (error); - - data = mtod(mbp->mb_top, char *); - len = m_totlen(mbp->mb_top); - - /* - * _rq_init left space for the SMB header, - * which makes mb_count the offset from - * the beginning of the header (useful). - * However, in this code path the driver - * prepends the header, so we skip it. - */ - krq.ioc_tbufsz = len - SMB_HDRLEN; - krq.ioc_tbuf = data + SMB_HDRLEN; - - /* - * Setup a buffer to hold the reply, - * at least MIN_REPLY_SIZE, or larger - * if the caller increased rq_rpbufsz. - */ - mbp = smb_rq_getreply(rqp); - rpbufsz = rqp->rq_rpbufsz; - if (rpbufsz < MIN_REPLY_SIZE) - rpbufsz = MIN_REPLY_SIZE; - if ((error = m_get(rpbufsz, &m)) != 0) - return (error); - mb_initm(mbp, m); - krq.ioc_rbufsz = rpbufsz; - krq.ioc_rbuf = mtod(m, char *); - - /* - * Call the driver - */ - if (nsmb_ioctl(rqp->rq_ctx->ct_dev_fd, SMBIOC_REQUEST, &krq) == -1) - return (errno); - - /* - * Initialize returned mbdata. - * SMB header already parsed. - */ - m->m_len = krq.ioc_rbufsz; - - return (0); -} - - -int -smb_t2_request(int dev_fd, 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; - - krq = (smbioc_t2rq_t *)malloc(sizeof (smbioc_t2rq_t)); - bzero(krq, sizeof (*krq)); - - if (setupcount < 0 || setupcount >= SMBIOC_T2RQ_MAXSETUP) { - /* 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; - - if (nsmb_ioctl(dev_fd, SMBIOC_T2RQ, krq) == -1) { - 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); - free(krq); - - return (0); -} - - -/* - * Do an over-the-wire call without using the nsmb driver. - * This is all "internal" to this library, and used only - * for connection setup (negotiate protocol, etc.) - */ -int -smb_rq_internal(struct smb_ctx *ctx, struct smb_rq *rqp) -{ - static const uint8_t ffsmb[4] = SMB_SIGNATURE; - struct smb_iods *is = &ctx->ct_iods; - uint32_t sigbuf[2]; - struct mbdata mbtmp, *mbp; - int err, save_mlen; - uint8_t ctmp; - - rqp->rq_uid = is->is_smbuid; - rqp->rq_tid = SMB_TID_UNKNOWN; - rqp->rq_mid = is->is_next_mid++; - - /* - * Fill in the NBT and SMB headers - * Using mbtmp so we can rewind without - * affecting the passed request mbdata. - */ - bcopy(&rqp->rq_rq, &mbtmp, sizeof (mbtmp)); - mbp = &mbtmp; - mbp->mb_cur = mbp->mb_top; - mbp->mb_pos = mbp->mb_cur->m_data; - mbp->mb_count = 0; - /* Have to save and restore m_len */ - save_mlen = mbp->mb_cur->m_len; - mbp->mb_cur->m_len = 0; - - /* - * rewind done; fill it in - */ - mb_put_mem(mbp, ffsmb, SMB_SIGLEN, MB_MSYSTEM); - mb_put_uint8(mbp, rqp->rq_cmd); - mb_put_uint32le(mbp, 0); /* status */ - mb_put_uint8(mbp, rqp->rq_hflags); - mb_put_uint16le(mbp, rqp->rq_hflags2); - /* pid_hi(2), signature(8), reserved(2) */ - mb_put_mem(mbp, NULL, 12, MB_MZERO); - mb_put_uint16le(mbp, rqp->rq_tid); - mb_put_uint16le(mbp, 0); /* pid_lo */ - mb_put_uint16le(mbp, rqp->rq_uid); - mb_put_uint16le(mbp, rqp->rq_mid); - - /* Restore original m_len */ - mbp->mb_cur->m_len = save_mlen; - - /* - * Sign the message, if flags2 indicates. - */ - if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) { - smb_rq_sign(rqp); - } - - /* - * Send it, wait for the reply. - */ - if ((err = smb_ssn_send(ctx, &rqp->rq_rq)) != 0) - return (err); - - if ((err = smb_ssn_recv(ctx, &rqp->rq_rp)) != 0) - return (err); - - /* - * Should have an SMB header, at least. - */ - mbp = &rqp->rq_rp; - if (mbp->mb_cur->m_len < SMB_HDRLEN) { - DPRINT("len < 32"); - return (EBADRPC); - } - - /* - * If the request was signed, validate the - * signature on the response. - */ - if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) { - err = smb_rq_verify(rqp); - if (err) { - DPRINT("bad signature"); - return (err); - } - } - - /* - * Decode the SMB header. - */ - md_get_mem(mbp, (char *)sigbuf, 4, MB_MSYSTEM); - if (0 != bcmp(sigbuf, ffsmb, 4)) { - DPRINT("not SMB"); - return (EBADRPC); - } - md_get_uint8(mbp, &ctmp); /* SMB cmd */ - md_get_uint32le(mbp, &rqp->rq_status); - md_get_uint8(mbp, &rqp->rq_hflags); - md_get_uint16le(mbp, &rqp->rq_hflags2); - /* pid_hi(2), signature(8), reserved(2) */ - md_get_mem(mbp, NULL, 12, MB_MSYSTEM); - md_get_uint16le(mbp, &rqp->rq_tid); - md_get_uint16le(mbp, NULL); /* pid_lo */ - md_get_uint16le(mbp, &rqp->rq_uid); - md_get_uint16le(mbp, &rqp->rq_mid); - - /* - * Figure out the status return. - * Caller looks at rq_status. - */ - if ((rqp->rq_hflags2 & SMB_FLAGS2_ERR_STATUS) == 0) { - uint16_t serr; - uint8_t class; - - class = rqp->rq_status & 0xff; - serr = rqp->rq_status >> 16; - rqp->rq_status = smb_map_doserr(class, serr); - } - - return (0); -} - -/* - * Map old DOS errors (etc.) to NT status codes. - * We probably don't need this anymore, since - * the oldest server we talk to is NT. But if - * later find we do need this, add support here - * for the DOS errors we care about. - */ -static uint32_t -smb_map_doserr(uint8_t class, uint16_t serr) -{ - if (class == 0 && serr == 0) - return (0); - - DPRINT("class 0x%x serr 0x%x", (int)class, (int)serr); - return (NT_STATUS_UNSUCCESSFUL); -} diff --git a/usr/src/lib/libsmbfs/smb/signing.c b/usr/src/lib/libsmbfs/smb/signing.c deleted file mode 100644 index 0e9c826bbd..0000000000 --- a/usr/src/lib/libsmbfs/smb/signing.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Signing support, using libmd - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include "private.h" - -#define SMBSIGOFF 14 /* SMB signature offset */ -#define SMBSIGLEN 8 /* SMB signature length */ - -/* - * Set this to a small number to debug sequence numbers - * that seem to get out of step. - */ -#ifdef DEBUG -int nsmb_signing_fudge = 4; -#endif - -/* - * Compute MD5 digest of packet data, using the stored MAC key. - * - * See similar code in the driver: - * uts/common/fs/smbclnt/netsmb/smb_signing.c - * and on the server side: - * uts/common/fs/smbsrv/smb_signing.c - */ -static int -smb_compute_MAC(struct smb_ctx *ctx, mbuf_t *m, - uint32_t seqno, uchar_t *signature) -{ - MD5_CTX md5; - uchar_t digest[MD5_DIGEST_LENGTH]; - - /* - * This union is a little bit of trickery to: - * (1) get the sequence number int aligned, and - * (2) reduce the number of digest calls, at the - * cost of a copying 32 bytes instead of 8. - * Both sides of this union are 2+32 bytes. - */ - union { - struct { - uint8_t skip[2]; /* not used - just alignment */ - uint8_t raw[SMB_HDRLEN]; /* header length (32) */ - } r; - struct { - uint8_t skip[2]; /* not used - just alignment */ - uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */ - uint32_t sig[2]; /* MAC signature, aligned! */ - uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */ - } s; - } smbhdr; - - if (m->m_len < SMB_HDRLEN) - return (EIO); - if (ctx->ct_mackey == NULL) - return (EINVAL); - - /* - * Make an aligned copy of the SMB header - * and fill in the sequence number. - */ - bcopy(m->m_data, smbhdr.r.raw, SMB_HDRLEN); - smbhdr.s.sig[0] = htolel(seqno); - smbhdr.s.sig[1] = 0; - - /* - * Compute the MAC: MD5(concat(Key, message)) - */ - MD5Init(&md5); - - /* Digest the MAC Key */ - MD5Update(&md5, ctx->ct_mackey, ctx->ct_mackeylen); - - /* Digest the (copied) SMB header */ - MD5Update(&md5, smbhdr.r.raw, SMB_HDRLEN); - - /* Digest the rest of the first mbuf */ - if (m->m_len > SMB_HDRLEN) { - MD5Update(&md5, m->m_data + SMB_HDRLEN, - m->m_len - SMB_HDRLEN); - } - m = m->m_next; - - /* Digest rest of the SMB message. */ - while (m) { - MD5Update(&md5, m->m_data, m->m_len); - m = m->m_next; - } - - /* Final */ - MD5Final(digest, &md5); - - /* - * Finally, store the signature. - * (first 8 bytes of the digest) - */ - if (signature) - bcopy(digest, signature, SMBSIGLEN); - - return (0); -} - -/* - * Sign a request with HMAC-MD5. - */ -void -smb_rq_sign(struct smb_rq *rqp) -{ - struct smb_ctx *ctx = rqp->rq_ctx; - mbuf_t *m = rqp->rq_rq.mb_top; - uint8_t *sigloc; - int err; - - /* - * Our mblk allocation ensures this, - * but just in case... - */ - if (m->m_len < SMB_HDRLEN) - return; - sigloc = (uchar_t *)m->m_data + SMBSIGOFF; - - if (ctx->ct_mackey == NULL) { - /* - * Signing is required, but we have no key yet - * fill in with the magic fake signing value. - * This happens with SPNEGO, NTLMSSP, ... - */ - bcopy("BSRSPLY", sigloc, 8); - return; - } - - /* - * This will compute the MAC and store it - * directly into the message at sigloc. - */ - rqp->rq_seqno = ctx->ct_mac_seqno; - ctx->ct_mac_seqno += 2; - err = smb_compute_MAC(ctx, m, rqp->rq_seqno, sigloc); - if (err) { - DPRINT("compute MAC, err %d", err); - bzero(sigloc, SMBSIGLEN); - } -} - -/* - * Verify reply signature. - */ -int -smb_rq_verify(struct smb_rq *rqp) -{ - struct smb_ctx *ctx = rqp->rq_ctx; - mbuf_t *m = rqp->rq_rp.mb_top; - uint8_t sigbuf[SMBSIGLEN]; - uint8_t *sigloc; - uint32_t rseqno; - int err, fudge; - - /* - * Note ct_mackey and ct_mackeylen gets initialized by - * smb_smb_ssnsetup. It's normal to have a null MAC key - * during extended security session setup. - */ - if (ctx->ct_mackey == NULL) - return (0); - - /* - * Let caller deal with empty reply or short messages by - * returning zero. Caller will fail later, in parsing. - */ - if (m == NULL) { - DPRINT("empty reply"); - return (0); - } - if (m->m_len < SMB_HDRLEN) { - DPRINT("short reply"); - return (0); - } - - sigloc = (uchar_t *)m->m_data + SMBSIGOFF; - rseqno = rqp->rq_seqno + 1; - - DPRINT("rq_rseqno = 0x%x", rseqno); - - err = smb_compute_MAC(ctx, m, rseqno, sigbuf); - if (err) { - DPRINT("compute MAC, err %d", err); - /* - * If we can't compute a MAC, then there's - * no point trying other seqno values. - */ - return (EBADRPC); - } - - /* - * Compare the computed signature with the - * one found in the message (at sigloc) - */ - if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) - return (0); - - DPRINT("BAD signature, MID=0x%x", rqp->rq_mid); - -#ifdef DEBUG - /* - * For diag purposes, we check whether the client/server idea - * of the sequence # has gotten a bit out of sync. - */ - for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) { - (void) smb_compute_MAC(ctx, m, rseqno + fudge, sigbuf); - if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) - break; - (void) smb_compute_MAC(ctx, m, rseqno - fudge, sigbuf); - if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) { - fudge = -fudge; - break; - } - } - if (fudge <= nsmb_signing_fudge) { - DPRINT("rseqno=%d, but %d would have worked", - rseqno, rseqno + fudge); - } -#endif - return (EBADRPC); -} diff --git a/usr/src/lib/libsmbfs/smb/ssnsetup.c b/usr/src/lib/libsmbfs/smb/ssnsetup.c deleted file mode 100644 index da7640241c..0000000000 --- a/usr/src/lib/libsmbfs/smb/ssnsetup.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (c) 2000-2001 Boris Popov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Boris Popov. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. - */ - -/* - * SMB Session Setup, and related. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "private.h" -#include "charsets.h" -#include "ntlm.h" -#include "smb_crypt.h" - - -static int -smb__ssnsetup(struct smb_ctx *ctx, - struct mbdata *mbc1, struct mbdata *mbc2, - uint32_t *statusp, uint16_t *actionp); - -/* - * Session Setup: NULL session (anonymous) - */ -int -smb_ssnsetup_null(struct smb_ctx *ctx) -{ - int err; - uint32_t ntstatus; - uint16_t action = 0; - - if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) { - /* Should not get here with... */ - err = EINVAL; - goto out; - } - - err = smb__ssnsetup(ctx, NULL, NULL, &ntstatus, &action); - if (err) - goto out; - - DPRINT("status 0x%x action 0x%x", ntstatus, (int)action); - if (ntstatus != 0) - err = EAUTH; - -out: - return (err); -} - - -/* - * SMB Session Setup, using NTLMv1 (and maybe LMv1) - */ -int -smb_ssnsetup_ntlm1(struct smb_ctx *ctx) -{ - struct mbdata lm_mbc, nt_mbc; - int err; - uint32_t ntstatus; - uint16_t action = 0; - - if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) { - /* Should not get here with... */ - err = EINVAL; - goto out; - } - - /* Make mb_done calls at out safe. */ - bzero(&lm_mbc, sizeof (lm_mbc)); - bzero(&nt_mbc, sizeof (nt_mbc)); - - /* Put the LM,NTLM responses (as mbdata). */ - err = ntlm_put_v1_responses(ctx, &lm_mbc, &nt_mbc); - if (err) - goto out; - - if ((ctx->ct_vcflags & SMBV_WILL_SIGN) != 0 && - (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) { - err = ntlm_build_mac_key(ctx, &nt_mbc); - if (err) - goto out; - /* OK, start signing! */ - ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; - } - - err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action); - if (err) - goto out; - - DPRINT("status 0x%x action 0x%x", ntstatus, (int)action); - if (ntstatus != 0) - err = EAUTH; - -out: - mb_done(&lm_mbc); - mb_done(&nt_mbc); - - return (err); -} - -/* - * SMB Session Setup, using NTLMv2 (and LMv2) - */ -int -smb_ssnsetup_ntlm2(struct smb_ctx *ctx) -{ - struct mbdata lm_mbc, nt_mbc, ti_mbc; - int err; - uint32_t ntstatus; - uint16_t action = 0; - - if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) { - /* Should not get here with... */ - err = EINVAL; - goto out; - } - - /* Make mb_done calls at out safe. */ - bzero(&lm_mbc, sizeof (lm_mbc)); - bzero(&nt_mbc, sizeof (nt_mbc)); - bzero(&ti_mbc, sizeof (ti_mbc)); - - /* Build the NTLMv2 "target info" blob (as mbdata) */ - err = ntlm_build_target_info(ctx, NULL, &ti_mbc); - if (err) - goto out; - - /* Put the LMv2, NTLMv2 responses (as mbdata). */ - err = ntlm_put_v2_responses(ctx, &ti_mbc, &lm_mbc, &nt_mbc); - if (err) - goto out; - - if ((ctx->ct_vcflags & SMBV_WILL_SIGN) != 0 && - (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) { - err = ntlm_build_mac_key(ctx, &nt_mbc); - if (err) - goto out; - /* OK, start signing! */ - ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; - } - - err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action); - if (err) - goto out; - - DPRINT("status 0x%x action 0x%x", ntstatus, (int)action); - if (ntstatus != 0) - err = EAUTH; - -out: - mb_done(&ti_mbc); - mb_done(&lm_mbc); - mb_done(&nt_mbc); - - return (err); -} - -int -smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb) -{ - struct mbdata send_mb, recv_mb; - int err; - uint32_t ntstatus; - uint16_t action = 0; - - err = ssp_ctx_create_client(ctx, hint_mb); - if (err) - goto out; - - bzero(&send_mb, sizeof (send_mb)); - bzero(&recv_mb, sizeof (recv_mb)); - - /* NULL input indicates first call. */ - err = ssp_ctx_next_token(ctx, NULL, &send_mb); - if (err) - goto out; - - for (;;) { - err = smb__ssnsetup(ctx, &send_mb, &recv_mb, - &ntstatus, &action); - if (err) - goto out; - if (ntstatus == 0) - break; /* normal loop termination */ - if (ntstatus != NT_STATUS_MORE_PROCESSING_REQUIRED) { - err = EAUTH; - goto out; - } - - /* middle calls get both in, out */ - err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb); - if (err) - goto out; - } - DPRINT("status 0x%x action 0x%x", ntstatus, (int)action); - - /* NULL output indicates last call. */ - (void) ssp_ctx_next_token(ctx, &recv_mb, NULL); - -out: - ssp_ctx_destroy(ctx); - - return (err); -} - -/* - * Session Setup function used for all the forms we support. - * To allow this sharing, the crypto stuff is computed by - * callers and passed in as mbdata chains. Also, the args - * have different meanings for extended security vs. old. - * Some may be used as either IN or OUT parameters. - * - * For NTLM (v1, v2), all parameters are inputs - * mbc1: [in] LM password hash - * mbc2: [in] NT password hash - * For Extended security (spnego) - * mbc1: [in] outgoing blob data - * mbc2: [out] received blob data - * For both forms, these are optional: - * statusp: [out] NT status - * actionp: [out] Logon Action (i.e. SMB_ACT_GUEST) - */ -static int -smb__ssnsetup(struct smb_ctx *ctx, - struct mbdata *mbc1, struct mbdata *mbc2, - uint32_t *statusp, uint16_t *actionp) -{ - static const char NativeOS[] = "Solaris"; - static const char LanMan[] = "NETSMB"; - struct smb_sopt *sv = &ctx->ct_sopt; - struct smb_iods *is = &ctx->ct_iods; - struct smb_rq *rqp = NULL; - struct mbdata *mbp; - struct mbuf *m; - int err, uc; - uint32_t caps; - uint16_t bc, len1, len2, sblen; - uint8_t wc; - - caps = ctx->ct_clnt_caps; - uc = ctx->ct_hflags2 & SMB_FLAGS2_UNICODE; - - err = smb_rq_init(ctx, SMB_COM_SESSION_SETUP_ANDX, &rqp); - if (err) - goto out; - - /* - * Build the SMB request. - */ - mbp = &rqp->rq_rq; - smb_rq_wstart(rqp); - mb_put_uint16le(mbp, 0xff); /* 0: AndXCommand */ - mb_put_uint16le(mbp, 0); /* 1: AndXOffset */ - mb_put_uint16le(mbp, sv->sv_maxtx); /* 2: MaxBufferSize */ - mb_put_uint16le(mbp, sv->sv_maxmux); /* 3: MaxMpxCount */ - mb_put_uint16le(mbp, 1); /* 4: VcNumber */ - mb_put_uint32le(mbp, sv->sv_skey); /* 5,6: Session Key */ - - if (caps & SMB_CAP_EXT_SECURITY) { - len1 = mbc1 ? mbc1->mb_count : 0; - mb_put_uint16le(mbp, len1); /* 7: Sec. Blob Len */ - mb_put_uint32le(mbp, 0); /* 8,9: reserved */ - mb_put_uint32le(mbp, caps); /* 10,11: Capabilities */ - smb_rq_wend(rqp); /* 12: Byte Count */ - smb_rq_bstart(rqp); - if (mbc1 && mbc1->mb_top) { - mb_put_mbuf(mbp, mbc1->mb_top); /* sec. blob */ - mbc1->mb_top = NULL; /* consumed */ - } - /* mbc2 is required below */ - if (mbc2 == NULL) { - err = EINVAL; - goto out; - } - } else { - len1 = mbc1 ? mbc1->mb_count : 0; - len2 = mbc2 ? mbc2->mb_count : 0; - mb_put_uint16le(mbp, len1); /* 7: LM pass. len */ - mb_put_uint16le(mbp, len2); /* 8: NT pass. len */ - mb_put_uint32le(mbp, 0); /* 9,10: reserved */ - mb_put_uint32le(mbp, caps); /* 11,12: Capabilities */ - smb_rq_wend(rqp); /* 13: Byte Count */ - smb_rq_bstart(rqp); - if (mbc1 && mbc1->mb_top) { - mb_put_mbuf(mbp, mbc1->mb_top); /* LM password */ - mbc1->mb_top = NULL; /* consumed */ - } - if (mbc2 && mbc2->mb_top) { - mb_put_mbuf(mbp, mbc2->mb_top); /* NT password */ - mbc2->mb_top = NULL; /* consumed */ - } - mb_put_string(mbp, ctx->ct_user, uc); - mb_put_string(mbp, ctx->ct_domain, uc); - } - mb_put_string(mbp, NativeOS, uc); - mb_put_string(mbp, LanMan, uc); - smb_rq_bend(rqp); - - err = smb_rq_internal(ctx, rqp); - if (err) - goto out; - - if (statusp) - *statusp = rqp->rq_status; - - /* - * If we have a real error, the response probably has - * no more data, so don't try to parse any more. - * Note: err=0, means rq_status is valid. - */ - if (rqp->rq_status != 0 && - rqp->rq_status != NT_STATUS_MORE_PROCESSING_REQUIRED) { - goto out; - } - - /* - * Parse the reply - */ - uc = rqp->rq_hflags2 & SMB_FLAGS2_UNICODE; - is->is_smbuid = rqp->rq_uid; - mbp = &rqp->rq_rp; - - err = md_get_uint8(mbp, &wc); - if (err) - goto out; - - err = EBADRPC; /* for any problems in this section */ - if (caps & SMB_CAP_EXT_SECURITY) { - if (wc != 4) - goto out; - md_get_uint16le(mbp, NULL); /* secondary cmd */ - md_get_uint16le(mbp, NULL); /* andxoffset */ - md_get_uint16le(mbp, actionp); /* action */ - md_get_uint16le(mbp, &sblen); /* sec. blob len */ - md_get_uint16le(mbp, &bc); /* byte count */ - /* - * Get the security blob, after - * sanity-checking the length. - */ - if (sblen == 0 || bc < sblen) - goto out; - err = md_get_mbuf(mbp, sblen, &m); - if (err) - goto out; - mb_initm(mbc2, m); - mbc2->mb_count = sblen; - } else { - if (wc != 3) - goto out; - md_get_uint16le(mbp, NULL); /* secondary cmd */ - md_get_uint16le(mbp, NULL); /* andxoffset */ - md_get_uint16le(mbp, actionp); /* action */ - err = md_get_uint16le(mbp, &bc); /* byte count */ - if (err) - goto out; - } - - /* - * Native OS, LANMGR, & Domain follow here. - * Parse these strings and store for later. - * If unicode, they should be aligned. - * - * Note that with Extended security, we may use - * multiple calls to this function. Only parse - * these strings on the last one (status == 0). - * Ditto for the CAP_LARGE work-around. - */ - if (rqp->rq_status != 0) - goto out; - - /* Ignore any parsing errors for these strings. */ - err = md_get_string(mbp, &ctx->ct_srv_OS, uc); - DPRINT("server OS: %s", err ? "?" : ctx->ct_srv_OS); - err = md_get_string(mbp, &ctx->ct_srv_LM, uc); - DPRINT("server LM: %s", err ? "?" : ctx->ct_srv_LM); - /* - * There's sometimes a server domain folloing - * at this point, but we don't need it. - */ - - /* Success! (See Ignore any ... above) */ - err = 0; - - /* - * MS-SMB 2.2.4.5 clarifies that when SMB signing is enabled, - * the client should NOT use "large read/write" even though - * the server might offer those capabilities. - */ - if (ctx->ct_vcflags & SMBV_WILL_SIGN) { - DPRINT("signing, so disable CAP_LARGE_(r/w)"); - ctx->ct_sopt.sv_caps &= - ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX); - } - -out: - if (rqp) - smb_rq_done(rqp); - - return (err); -} diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in index 993bdd61a8..1d3bc3e6f5 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in +++ b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in @@ -20,7 +20,7 @@ \ \ -\ Copyright 2011 Nexenta Systems, Inc. All rights reserved. +\ Copyright 2018 Nexenta Systems, Inc. All rights reserved. \ Copyright 2009 Sun Microsystems, Inc. All rights reserved. \ Use is subject to license terms. \ @@ -68,71 +68,24 @@ smbioc_tcon tc_opt tc_sh -smb_sopt - sv_proto - sv_sm - sv_tz - sv_maxmux - sv_maxvcs - sv_rawmode - sv_maxtx - sv_maxraw - sv_skey - sv_caps - -smb_iods - is_tran_fd - is_vcflags - is_hflags - is_hflags2 - is_smbuid - is_next_mid - is_txmax - is_rwmax - is_rxmax - is_wxmax - is_ssn_key - is_next_seq - is_u_maclen - is_u_mackey - smbioc_ssn_work - wk_iods - wk_sopt wk_out_state - -smbioc_rq SIZEOF_SMBIOC_RQ - ioc_cmd - ioc_errclass IOC_RQ_ERRCLASS - ioc_serror IOC_RQ_SERROR - ioc_error IOC_RQ_ERROR - ioc_tbufsz - ioc_rbufsz - _ioc_tbuf - _ioc_rbuf - -smbioc_t2rq SIZEOF_SMBIOC_T2RQ - ioc_setup - ioc_setupcnt - ioc_name IOC_T2_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 + wk_u_ssnkey_len + wk_u_ssnkey_buf + wk_u_auth_rlen + wk_u_auth_wlen + wk_u_auth_rbuf + wk_u_auth_wbuf + wk_ssn_key + +smbioc_xnp SIZEOF_SMBIOC_XNP + ioc_fh + ioc_tdlen + ioc_rdlen + ioc_more _ioc_tdata - _ioc_rparam _ioc_rdata -smbioc_flags SIZEOF_SMBIOC_FLAGS - ioc_level - ioc_mask - ioc_flags - smbioc_rw SIZEOF_SMBIOC_RW ioc_fh ioc_cnt diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c index d1e7efd60a..41405c314d 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c @@ -34,6 +34,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -105,7 +107,7 @@ void smb_sm_done(void) { /* - * XXX Q4BP why are we not iterating on smb_vclist here? + * 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. */ @@ -365,6 +367,8 @@ smb_vc_free(struct smb_connobj *cp) if (vcp->vc_mackey != NULL) kmem_free(vcp->vc_mackey, vcp->vc_mackeylen); + if (vcp->vc_ssnkey != NULL) + kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen); cv_destroy(&vcp->iod_idle); rw_destroy(&vcp->iod_rqlock); @@ -399,7 +403,8 @@ smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp) /* Expanded TAILQ_HEAD_INITIALIZER */ vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first; - vcp->vc_state = SMBIOD_ST_IDLE; + /* A brand new VC should connect. */ + vcp->vc_state = SMBIOD_ST_RECONNECT; /* * These identify the connection. diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h index 42dfd687f9..7b2b6a4690 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h @@ -33,9 +33,10 @@ */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _SMB_CONN_H @@ -61,14 +62,11 @@ typedef struct smb_cred { /* * 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. + * Note: SMBO_GONE is also in vc_flags */ - -#define SMBV_WIN95 0x0010 /* used to apply bugfixes for this OS */ -#define SMBV_NT4 0x0020 /* used when NT4 issues invalid resp */ #define SMBV_UNICODE 0x0040 /* conn configured to use Unicode */ +#define SMBV_EXT_SEC 0x0080 /* conn to use extended security */ +#define SMBV_WILL_SIGN 0x0100 /* negotiated signing */ /* * Note: the common "obj" level uses this GONE flag by @@ -145,6 +143,41 @@ typedef struct smb_connobj smb_connobj_t; #define SMBL_VC 1 #define SMBL_SHARE 2 +/* + * SMB1 Negotiated protocol parameters + */ +struct smb_sopt { + int16_t sv_proto; /* protocol dialect */ + uchar_t sv_sm; /* security mode */ + int16_t sv_tz; /* offset in min relative to UTC */ + uint16_t sv_maxmux; /* max number of outstanding rq's */ + uint16_t sv_maxvcs; /* max number of VCs */ + uint16_t sv_rawmode; + uint32_t sv_maxtx; /* maximum transmit buf size */ + uint32_t sv_maxraw; /* maximum raw-buffer size */ + uint32_t sv_skey; /* session key */ + uint32_t sv_caps; /* capabilites SMB_CAP_ */ +}; +typedef struct smb_sopt smb_sopt_t; + +/* + * SMB1 I/O Deamon state + */ +struct smb_iods { + uint8_t is_hflags; /* SMB header flags */ + uint16_t is_hflags2; /* SMB header flags2 */ + uint16_t is_smbuid; /* SMB header UID */ + uint16_t is_next_mid; /* SMB header MID */ + uint32_t is_txmax; /* max tx/rx packet size */ + uint32_t is_rwmax; /* max read/write data size */ + uint32_t is_rxmax; /* max readx data size */ + uint32_t is_wxmax; /* max writex data size */ + /* Signing state */ + uint32_t is_next_seq; /* my next sequence number */ + +}; +typedef struct smb_iods smb_iods_t; + /* * Virtual Circuit to a server (really connection + session). * Yes, calling this a "Virtual Circuit" is confusining, @@ -160,21 +193,26 @@ typedef struct smb_vc { uid_t vc_owner; /* Unix owner */ int vc_genid; /* "generation" ID */ - int vc_mackeylen; /* length of MAC key */ - uint8_t *vc_mackey; /* MAC key */ + int vc_mackeylen; /* MAC key length */ + int vc_ssnkeylen; /* session key length */ + uint8_t *vc_mackey; /* MAC key buffer */ + uint8_t *vc_ssnkey; /* session key buffer */ ksema_t vc_sendlock; struct smb_tran_desc *vc_tdesc; /* transport ops. vector */ void *vc_tdata; /* transport control block */ - kcondvar_t iod_idle; /* IOD thread idle CV */ + kcondvar_t iod_idle; /* IOD thread idle CV */ krwlock_t iod_rqlock; /* iod_rqlist */ struct smb_rqhead iod_rqlist; /* list of outstanding reqs */ - struct _kthread *iod_thr; /* the IOD (reader) thread */ + struct _kthread *iod_thr; /* the IOD (reader) thread */ int iod_flags; /* see SMBIOD_* below */ int iod_newrq; /* send needed (iod_rqlock) */ int iod_muxfull; /* maxmux limit reached */ + smb_iods_t vc_iods; + smb_sopt_t vc_sopt; + /* This is copied in/out when IOD enters/returns */ smbioc_ssn_work_t vc_work; @@ -191,24 +229,23 @@ typedef struct smb_vc { #define vc_srvaddr vc_ssn.ssn_id.id_srvaddr #define vc_domain vc_ssn.ssn_id.id_domain #define vc_username vc_ssn.ssn_id.id_user -#define vc_vopt vc_ssn.ssn_vopt +#define vc_vopt vc_ssn.ssn_vopt /* defines for members in vc_work */ -#define vc_sopt vc_work.wk_sopt -#define vc_maxmux vc_work.wk_sopt.sv_maxmux -#define vc_tran_fd vc_work.wk_iods.is_tran_fd -#define vc_hflags vc_work.wk_iods.is_hflags -#define vc_hflags2 vc_work.wk_iods.is_hflags2 -#define vc_smbuid vc_work.wk_iods.is_smbuid -#define vc_next_mid vc_work.wk_iods.is_next_mid -#define vc_txmax vc_work.wk_iods.is_txmax -#define vc_rwmax vc_work.wk_iods.is_rwmax -#define vc_rxmax vc_work.wk_iods.is_rxmax -#define vc_wxmax vc_work.wk_iods.is_wxmax -#define vc_ssn_key vc_work.wk_iods.is_ssn_key -#define vc_next_seq vc_work.wk_iods.is_next_seq -#define vc_u_mackey vc_work.wk_iods.is_u_mackey -#define vc_u_maclen vc_work.wk_iods.is_u_maclen + +/* defines for members in vc_sopt ? */ +#define vc_maxmux vc_sopt.sv_maxmux + +/* defines for members in vc_iods */ +#define vc_hflags vc_iods.is_hflags +#define vc_hflags2 vc_iods.is_hflags2 +#define vc_smbuid vc_iods.is_smbuid +#define vc_next_mid vc_iods.is_next_mid +#define vc_txmax vc_iods.is_txmax +#define vc_rwmax vc_iods.is_rwmax +#define vc_rxmax vc_iods.is_rxmax +#define vc_wxmax vc_iods.is_wxmax +#define vc_next_seq vc_iods.is_next_seq #define SMB_VC_LOCK(vcp) mutex_enter(&(vcp)->vc_lock) #define SMB_VC_UNLOCK(vcp) mutex_exit(&(vcp)->vc_lock) @@ -300,6 +337,8 @@ int smb_dev2share(int fd, struct smb_share **sspp); /* * smb_usr.c */ +int smb_usr_ioctl(smb_dev_t *, int, intptr_t, int, cred_t *); + int smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags); int smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags); int smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags); @@ -319,7 +358,10 @@ int smb_usr_get_tree(smb_dev_t *, int, intptr_t, int, cred_t *); int smb_usr_drop_tree(smb_dev_t *sdp, int cmd); int smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr); -int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags); +int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, + cred_t *cr); + +int smb_pkey_ioctl(int, intptr_t, int, cred_t *); /* @@ -327,18 +369,21 @@ int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags); */ int smb_iod_create(smb_vc_t *vcp); int smb_iod_destroy(smb_vc_t *vcp); -int smb_iod_connect(smb_vc_t *vcp); void smb_iod_disconnect(smb_vc_t *vcp); int smb_iod_addrq(struct smb_rq *rqp); int smb_iod_multirq(struct smb_rq *rqp); int smb_iod_waitrq(struct smb_rq *rqp); void smb_iod_removerq(struct smb_rq *rqp); +int smb_iod_sendrecv(struct smb_rq *, int); void smb_iod_shutdown_share(smb_share_t *ssp); void smb_iod_sendall(smb_vc_t *); -int smb_iod_recvall(smb_vc_t *); +int smb_iod_recvall(smb_vc_t *, boolean_t); -int smb_iod_vc_work(smb_vc_t *, cred_t *); +int nsmb_iod_connect(smb_vc_t *vcp); +int nsmb_iod_negotiate(smb_vc_t *vcp, cred_t *cr); +int nsmb_iod_ssnsetup(smb_vc_t *vcp, cred_t *cr); +int smb_iod_vc_work(smb_vc_t *, int, cred_t *); int smb_iod_vc_idle(smb_vc_t *); int smb_iod_vc_rcfail(smb_vc_t *); int smb_iod_reconnect(smb_vc_t *); diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c index 9f718a7bfc..b2788bb194 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c @@ -34,7 +34,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -62,7 +62,7 @@ #include #include #include -#include +#include #include #include @@ -88,6 +88,10 @@ /* for version checks */ const uint32_t nsmb_version = NSMB_VERSION; +/* for smb_nbst_create() */ +dev_t nsmb_dev_tcp = NODEV; +dev_t nsmb_dev_tcp6 = NODEV; + static void *statep; static major_t nsmb_major; static minor_t last_minor = NSMB_MIN_MINOR; @@ -221,6 +225,9 @@ _init(void) streams_msg_init(); /* No attach, so need to set major. */ nsmb_major = 1; + /* And these, for smb_nbst_create() */ + nsmb_dev_tcp = AF_INET; + nsmb_dev_tcp6 = AF_INET6; #endif /* _KERNEL */ return (0); @@ -296,6 +303,7 @@ nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) static int nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { + major_t tmaj; if (cmd != DDI_ATTACH) return (DDI_FAILURE); @@ -320,6 +328,20 @@ nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) */ nsmb_major = ddi_name_to_major(NSMB_NAME); + /* + * We also need major numbers for t_kopen + */ + tmaj = ddi_name_to_major("tcp"); + if (tmaj == DDI_MAJOR_T_NONE) + cmn_err(CE_NOTE, "no tcp major?"); + else + nsmb_dev_tcp = makedevice(tmaj, 0); + tmaj = ddi_name_to_major("tcp6"); + if (tmaj == DDI_MAJOR_T_NONE) + cmn_err(CE_NOTE, "no tcp6 major?"); + else + nsmb_dev_tcp6 = makedevice(tmaj, 0); + nsmb_dip = dip; ddi_report_dev(dip); return (DDI_SUCCESS); @@ -431,107 +453,7 @@ nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */ * check the zone status here on every ioctl call. */ - /* - * Serialize ioctl calls. The smb_usr_... functions - * don't expect concurrent calls on a given sdp. - */ - mutex_enter(&sdp->sd_lock); - if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) { - mutex_exit(&sdp->sd_lock); - return (EBUSY); - } - sdp->sd_flags |= NSMBFL_IOCTL; - mutex_exit(&sdp->sd_lock); - - err = 0; - switch (cmd) { - case SMBIOC_GETVERS: - (void) ddi_copyout(&nsmb_version, (void *)arg, - sizeof (nsmb_version), flags); - break; - - case SMBIOC_FLAGS2: - err = smb_usr_get_flags2(sdp, arg, flags); - break; - - case SMBIOC_GETSSNKEY: - err = smb_usr_get_ssnkey(sdp, arg, flags); - break; - - case SMBIOC_DUP_DEV: - err = smb_usr_dup_dev(sdp, arg, flags); - break; - - case SMBIOC_REQUEST: - err = smb_usr_simplerq(sdp, arg, flags, cr); - break; - - case SMBIOC_T2RQ: - err = smb_usr_t2request(sdp, arg, flags, cr); - break; - - case SMBIOC_READ: - case SMBIOC_WRITE: - err = smb_usr_rw(sdp, cmd, arg, flags, cr); - break; - - case SMBIOC_NTCREATE: - err = smb_usr_ntcreate(sdp, arg, flags, cr); - break; - - case SMBIOC_PRINTJOB: - err = smb_usr_printjob(sdp, arg, flags, cr); - break; - - case SMBIOC_CLOSEFH: - err = smb_usr_closefh(sdp, cr); - break; - - case SMBIOC_SSN_CREATE: - case SMBIOC_SSN_FIND: - err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr); - break; - - case SMBIOC_SSN_KILL: - case SMBIOC_SSN_RELE: - err = smb_usr_drop_ssn(sdp, cmd); - break; - - case SMBIOC_TREE_CONNECT: - case SMBIOC_TREE_FIND: - err = smb_usr_get_tree(sdp, cmd, arg, flags, cr); - break; - - case SMBIOC_TREE_KILL: - case SMBIOC_TREE_RELE: - err = smb_usr_drop_tree(sdp, cmd); - break; - - case SMBIOC_IOD_WORK: - err = smb_usr_iod_work(sdp, arg, flags, cr); - break; - - case SMBIOC_IOD_IDLE: - case SMBIOC_IOD_RCFAIL: - err = smb_usr_iod_ioctl(sdp, cmd, arg, flags); - break; - - case SMBIOC_PK_ADD: - case SMBIOC_PK_DEL: - case SMBIOC_PK_CHK: - case SMBIOC_PK_DEL_OWNER: - case SMBIOC_PK_DEL_EVERYONE: - err = smb_pkey_ioctl(cmd, arg, flags, cr); - break; - - default: - err = ENOTTY; - break; - } - - mutex_enter(&sdp->sd_lock); - sdp->sd_flags &= ~NSMBFL_IOCTL; - mutex_exit(&sdp->sd_lock); + err = smb_usr_ioctl(sdp, cmd, arg, flags, cr); return (err); } diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c index 1e83a87806..4c547df25b 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c @@ -36,7 +36,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifdef DEBUG @@ -75,6 +75,14 @@ #include #include +/* + * SMB messages are up to 64K. + * Let's leave room for two. + */ +static int smb_tcpsndbuf = 0x20000; +static int smb_tcprcvbuf = 0x20000; +static int smb_connect_timeout = 10; /* seconds */ + int smb_iod_send_echo(smb_vc_t *); #ifdef _FAKE_KERNEL @@ -203,14 +211,15 @@ smb_iod_sendrq(struct smb_rq *rqp) ASSERT(RW_READ_HELD(&vcp->iod_rqlock)); /* - * Note: Anything special for SMBR_INTERNAL here? + * Internal requests are allowed in any state; + * otherwise should be active. */ - if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { + if ((rqp->sr_flags & SMBR_INTERNAL) == 0 && + vcp->vc_state != SMBIOD_ST_VCACTIVE) { SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state); return (ENOTCONN); } - /* * On the first send, set the MID and (maybe) * the signing sequence numbers. The increments @@ -220,12 +229,16 @@ smb_iod_sendrq(struct smb_rq *rqp) rqp->sr_mid = vcp->vc_next_mid++; - if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) { + if (vcp->vc_mackey != NULL && (rqp->sr_rqflags2 & + SMB_FLAGS2_SECURITY_SIGNATURE) != 0) { /* * We're signing requests and verifying * signatures on responses. Set the * sequence numbers of the request and * response here, used in smb_rq_verify. + * Note we have the signing flag during + * session setup but no key yet, and + * don't want sequence numbers there. */ rqp->sr_seqno = vcp->vc_next_seq++; rqp->sr_rseqno = vcp->vc_next_seq++; @@ -258,12 +271,8 @@ smb_iod_sendrq(struct smb_rq *rqp) */ 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); if (m != NULL) { @@ -295,12 +304,6 @@ smb_iod_sendrq(struct smb_rq *rqp) 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); } @@ -341,15 +344,14 @@ top: /* * 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. + * This is the "reader" loop, run by the IOD thread. Normally we're in + * state SMBIOD_ST_VCACTIVE here, but during reconnect we're called in + * other states with poll==TRUE * - * Any non-zero error means the IOD should terminate. + * A non-zero error return here causes the IOD work loop to terminate. */ int -smb_iod_recvall(struct smb_vc *vcp) +smb_iod_recvall(struct smb_vc *vcp, boolean_t poll) { struct smb_rq *rqp; mblk_t *m; @@ -364,12 +366,6 @@ smb_iod_recvall(struct smb_vc *vcp) * or is asking the IOD to terminate. */ - if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { - SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state); - error = 0; - break; - } - if (vcp->iod_flags & SMBIOD_SHUTDOWN) { SMBIODEBUG("SHUTDOWN set\n"); /* This IOD thread will terminate. */ @@ -384,6 +380,13 @@ smb_iod_recvall(struct smb_vc *vcp) m = NULL; error = smb_iod_recv1(vcp, &m); + /* + * Internal requests (reconnecting) call this in a loop + * (with poll==TRUE) until the request completes. + */ + if (error == ETIME && poll) + break; + if (error == ETIME && vcp->iod_rqlist.tqh_first != NULL) { /* @@ -417,16 +420,17 @@ smb_iod_recvall(struct smb_vc *vcp) continue; } /* ETIME && requests in queue */ - if (error == ETIME) { + if (error == ETIME) { /* and req list empty */ /* * If the IOD thread holds the last reference - * to this VC, let the IOD thread terminate. + * to this VC, let it become IDLE, and then + * let it be destroyed if not used. */ if (vcp->vc_co.co_usecount > 1) continue; SMB_VC_LOCK(vcp); if (vcp->vc_co.co_usecount == 1) { - smb_iod_newstate(vcp, SMBIOD_ST_DEAD); + smb_iod_newstate(vcp, SMBIOD_ST_IDLE); SMB_VC_UNLOCK(vcp); error = 0; break; @@ -442,17 +446,16 @@ smb_iod_recvall(struct smb_vc *vcp) * It's dangerous to continue here. * (possible infinite loop!) * - * If we have requests enqueued, next - * state is reconnecting, else idle. + * If this VC has shares, try reconnect; + * otherwise let this VC die now. */ - int state; SMB_VC_LOCK(vcp); - state = (vcp->iod_rqlist.tqh_first != NULL) ? - SMBIOD_ST_RECONNECT : SMBIOD_ST_IDLE; - smb_iod_newstate(vcp, state); + if (vcp->vc_co.co_usecount > 1) + smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT); + else + smb_iod_newstate(vcp, SMBIOD_ST_DEAD); cv_broadcast(&vcp->vc_statechg); SMB_VC_UNLOCK(vcp); - error = 0; break; } @@ -514,11 +517,18 @@ smb_iod_recvall(struct smb_vc *vcp) 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); + /* + * Reconnect calls this in a loop with poll=TRUE + * We've received a response, so break now. + */ + if (poll) { + error = 0; + break; + } } return (error); @@ -564,22 +574,12 @@ smb_iod_addrq(struct smb_rq *rqp) ASSERT(rqp->sr_cred); - /* - * State should be correct after the check in - * smb_rq_enqueue(), but we dropped locks... - */ - if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { - SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state); - return (ENOTCONN); - } - /* * Requests from the IOD itself are marked _INTERNAL, * and get some special treatment to avoid blocking * the reader thread (so we don't deadlock). * The request is not yet on the queue, so we can * modify it's state here without locks. - * Only thing using this now is ECHO. */ rqp->sr_owner = curthread; if (rqp->sr_owner == vcp->iod_thr) { @@ -619,6 +619,15 @@ smb_iod_addrq(struct smb_rq *rqp) smb_iod_removerq(rqp); return (error); + } else { + /* + * 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); @@ -722,9 +731,24 @@ smb_iod_waitrq(struct smb_rq *rqp) int error, rc; if (rqp->sr_flags & SMBR_INTERNAL) { + int timeleft = rqp->sr_timo; + ASSERT((rqp->sr_flags & SMBR_MULTIPACKET) == 0); + again: + smb_iod_sendall(vcp); + error = smb_iod_recvall(vcp, B_TRUE); + if (error == ETIME) { + /* We waited SMB_NBTIMO sec. */ + timeleft -= SMB_NBTIMO; + if (timeleft > 0) + goto again; + } + smb_iod_removerq(rqp); - return (EAGAIN); + if (rqp->sr_state != SMBRQ_NOTIFIED) + error = ETIME; + + return (error); } /* @@ -797,17 +821,8 @@ smb_iod_waitrq(struct smb_rq *rqp) goto out; } if (tr < 0) { -#ifdef DTRACE_PROBE1 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 } } @@ -826,17 +841,8 @@ smb_iod_waitrq(struct smb_rq *rqp) 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; } @@ -930,11 +936,6 @@ smb_iod_sendall(smb_vc_t *vcp) error = muxcnt = 0; TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) { - if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { - error = ENOTCONN; /* stop everything! */ - break; - } - if (rqp->sr_state == SMBRQ_NOTSENT) { error = smb_iod_sendrq(rqp); if (error) @@ -960,10 +961,180 @@ smb_iod_sendall(smb_vc_t *vcp) rw_exit(&vcp->iod_rqlock); } +/* + * Ioctl functions called by the user-level I/O Deamon (IOD) + * to bring up and service a connection to some SMB server. + */ + +int +nsmb_iod_connect(struct smb_vc *vcp) +{ + int err, val; + + ASSERT(vcp->iod_thr == curthread); + + if (vcp->vc_state != SMBIOD_ST_RECONNECT) { + cmn_err(CE_NOTE, "iod_connect: bad state %d", vcp->vc_state); + return (EINVAL); + } + + /* + * Set various options on this endpoint. + * Keep going in spite of errors. + */ + val = smb_tcpsndbuf; + err = SMB_TRAN_SETPARAM(vcp, SMBTP_SNDBUF, &val); + if (err != 0) { + cmn_err(CE_NOTE, "iod_connect: setopt SNDBUF, err=%d", err); + } + val = smb_tcprcvbuf; + err = SMB_TRAN_SETPARAM(vcp, SMBTP_RCVBUF, &val); + if (err != 0) { + cmn_err(CE_NOTE, "iod_connect: setopt RCVBUF, err=%d", err); + } + val = 1; + err = SMB_TRAN_SETPARAM(vcp, SMBTP_KEEPALIVE, &val); + if (err != 0) { + cmn_err(CE_NOTE, "iod_connect: setopt KEEPALIVE, err=%d", err); + } + val = 1; + err = SMB_TRAN_SETPARAM(vcp, SMBTP_TCP_NODELAY, &val); + if (err != 0) { + cmn_err(CE_NOTE, "iod_connect: setopt TCP_NODELAY, err=%d", err); + } + val = smb_connect_timeout * 1000; + err = SMB_TRAN_SETPARAM(vcp, SMBTP_TCP_CON_TMO, &val); + if (err != 0) { + cmn_err(CE_NOTE, "iod_connect: setopt TCP con tmo, err=%d", err); + } + + /* + * Bind and connect + */ + err = SMB_TRAN_BIND(vcp, NULL); + if (err != 0) { + cmn_err(CE_NOTE, "iod_connect: t_kbind: err=%d", err); + /* Continue on and try connect. */ + } + err = SMB_TRAN_CONNECT(vcp, &vcp->vc_srvaddr.sa); + /* + * No cmn_err here, as connect failures are normal, i.e. + * when a server has multiple addresses and only some are + * routed for us. (libsmbfs tries them all) + */ + if (err == 0) { + SMB_VC_LOCK(vcp); + smb_iod_newstate(vcp, SMBIOD_ST_CONNECTED); + SMB_VC_UNLOCK(vcp); + } /* else stay in state reconnect */ + + return (err); +} + +/* + * Do the whole SMB1/SMB2 negotiate + */ +int +nsmb_iod_negotiate(struct smb_vc *vcp, cred_t *cr) +{ + struct smb_sopt *sv = &vcp->vc_sopt; + smb_cred_t scred; + int err = 0; + + ASSERT(vcp->iod_thr == curthread); + + if (vcp->vc_state != SMBIOD_ST_CONNECTED) { + cmn_err(CE_NOTE, "iod_negotiate: bad state %d", vcp->vc_state); + return (EINVAL); + } + + /* + * (Re)init negotiated values + */ + bzero(sv, sizeof (*sv)); + vcp->vc_next_seq = 0; + + /* + * If this was reconnect, get rid of the old MAC key + * and session key. + */ + SMB_VC_LOCK(vcp); + if (vcp->vc_mackey != NULL) { + kmem_free(vcp->vc_mackey, vcp->vc_mackeylen); + vcp->vc_mackey = NULL; + vcp->vc_mackeylen = 0; + } + if (vcp->vc_ssnkey != NULL) { + kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen); + vcp->vc_ssnkey = NULL; + vcp->vc_ssnkeylen = 0; + } + SMB_VC_UNLOCK(vcp); + + smb_credinit(&scred, cr); + err = smb_smb_negotiate(vcp, &scred); + smb_credrele(&scred); + + if (err == 0) { + SMB_VC_LOCK(vcp); + smb_iod_newstate(vcp, SMBIOD_ST_NEGOTIATED); + SMB_VC_UNLOCK(vcp); + } + /* + * (else) leave state as it was. + * User-level will report this error + * and close this device handle. + */ + + return (err); +} + +/* + * Do either SMB1 or SMB2 session setup. + */ +int +nsmb_iod_ssnsetup(struct smb_vc *vcp, cred_t *cr) +{ + smb_cred_t scred; + int err; + + ASSERT(vcp->iod_thr == curthread); + + switch (vcp->vc_state) { + case SMBIOD_ST_NEGOTIATED: + case SMBIOD_ST_AUTHCONT: + break; + default: + return (EINVAL); + } + + smb_credinit(&scred, cr); + // XXX if SMB1 else ... + err = smb_smb_ssnsetup(vcp, &scred); + smb_credrele(&scred); + + SMB_VC_LOCK(vcp); + switch (err) { + case 0: + smb_iod_newstate(vcp, SMBIOD_ST_AUTHOK); + break; + case EINPROGRESS: /* MORE_PROCESSING_REQUIRED */ + smb_iod_newstate(vcp, SMBIOD_ST_AUTHCONT); + break; + default: + smb_iod_newstate(vcp, SMBIOD_ST_AUTHFAIL); + break; + } + SMB_VC_UNLOCK(vcp); + + return (err); +} + +/* ARGSUSED */ int -smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr) +smb_iod_vc_work(struct smb_vc *vcp, int flags, cred_t *cr) { - struct file *fp = NULL; + smbioc_ssn_work_t *wk = &vcp->vc_work; int err = 0; /* @@ -973,19 +1144,54 @@ smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr) ASSERT(vcp->iod_thr == curthread); /* - * Get the network transport file pointer, - * and "loan" it to our transport module. + * Should be in state... + */ + if (vcp->vc_state != SMBIOD_ST_AUTHOK) { + cmn_err(CE_NOTE, "iod_vc_work: bad state %d", vcp->vc_state); + return (EINVAL); + } + + /* + * Update the session key and initialize SMB signing. + * + * This implementation does not use multiple SMB sessions per + * TCP connection (where only the first session key is used) + * so we always have a new session key here. Sanity check the + * length from user space. Normally 16 or 32. */ - if ((fp = getf(vcp->vc_tran_fd)) == NULL) { - err = EBADF; - goto out; + if (wk->wk_u_ssnkey_len > 1024) { + cmn_err(CE_NOTE, "iod_vc_work: ssn key too long"); + return (EINVAL); } - if ((err = SMB_TRAN_LOAN_FP(vcp, fp, cr)) != 0) - goto out; + + ASSERT(vcp->vc_ssnkey == NULL); + SMB_VC_LOCK(vcp); + if (wk->wk_u_ssnkey_len != 0 && + wk->wk_u_ssnkey_buf.lp_ptr != NULL) { + vcp->vc_ssnkeylen = wk->wk_u_ssnkey_len; + vcp->vc_ssnkey = kmem_alloc(vcp->vc_ssnkeylen, KM_SLEEP); + if (ddi_copyin(wk->wk_u_ssnkey_buf.lp_ptr, + vcp->vc_ssnkey, vcp->vc_ssnkeylen, flags) != 0) { + err = EFAULT; + } + } + SMB_VC_UNLOCK(vcp); + if (err) + return (err); /* - * In case of reconnect, tell any enqueued requests - * then can GO! + * If we have a session key, derive the MAC key for SMB signing. + * If this was a NULL session, we might have no session key. + */ + ASSERT(vcp->vc_mackey == NULL); + if (vcp->vc_ssnkey != NULL) { + err = smb_sign_init(vcp); + if (err != 0) + return (err); + } + + /* + * Tell any enqueued requests they can start. */ SMB_VC_LOCK(vcp); vcp->vc_genid++; /* possibly new connection */ @@ -1006,7 +1212,7 @@ smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr) /* * Run the "reader" loop. */ - err = smb_iod_recvall(vcp); + err = smb_iod_recvall(vcp, B_FALSE); /* * The reader loop returned, so we must have a @@ -1027,13 +1233,6 @@ smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr) */ smb_iod_invrq(vcp); -out: - /* Recall the file descriptor loan. */ - (void) SMB_TRAN_LOAN_FP(vcp, NULL, cr); - if (fp != NULL) { - releasef(vcp->vc_tran_fd); - } - return (err); } @@ -1092,10 +1291,6 @@ smb_iod_vc_rcfail(struct smb_vc *vcp) * IOD thread for this VC. */ ASSERT(vcp->iod_thr == curthread); - - if (vcp->vc_state != SMBIOD_ST_RECONNECT) - return (EINVAL); - SMB_VC_LOCK(vcp); smb_iod_newstate(vcp, SMBIOD_ST_RCFAILED); @@ -1111,7 +1306,13 @@ smb_iod_vc_rcfail(struct smb_vc *vcp) if (tr == 0) err = EINTR; - smb_iod_newstate(vcp, SMBIOD_ST_IDLE); + /* + * While we were waiting on the CV, the state might have + * changed to reconnect. If so, leave that; otherwise + * go to state idle until the next request. + */ + if (vcp->vc_state == SMBIOD_ST_RCFAILED) + smb_iod_newstate(vcp, SMBIOD_ST_IDLE); cv_broadcast(&vcp->vc_statechg); SMB_VC_UNLOCK(vcp); @@ -1138,6 +1339,10 @@ again: /* FALLTHROUGH */ case SMBIOD_ST_RECONNECT: + case SMBIOD_ST_CONNECTED: + case SMBIOD_ST_NEGOTIATED: + case SMBIOD_ST_AUTHCONT: + case SMBIOD_ST_AUTHOK: rv = cv_wait_sig(&vcp->vc_statechg, &vcp->vc_lock); if (rv == 0) { err = EINTR; @@ -1149,6 +1354,7 @@ again: err = 0; /* success! */ break; + case SMBIOD_ST_AUTHFAIL: case SMBIOD_ST_RCFAILED: case SMBIOD_ST_DEAD: default: diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h index f4ebf9a573..4a44e36e89 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h @@ -22,6 +22,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _SMB_PASS_H @@ -44,14 +46,13 @@ typedef struct smb_passid { zoneid_t zoneid; /* Future Use */ char *srvdom; /* Windows Domain (or server) */ char *username; /* Windows User name */ - uchar_t lmhash[SMBIOC_HASH_SZ]; - uchar_t nthash[SMBIOC_HASH_SZ]; + uchar_t lmhash[SMBIOC_HASH_SZ]; + uchar_t nthash[SMBIOC_HASH_SZ]; } smb_passid_t; /* Called from smb_dev.c */ void smb_pkey_init(void); void smb_pkey_fini(void); int smb_pkey_idle(void); -int smb_pkey_ioctl(int, intptr_t, int, cred_t *); #endif /* _SMB_PASS_H */ diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c index 997b7318dd..2301965762 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c @@ -34,6 +34,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -330,6 +331,34 @@ ok_out: return (error); } +/* + * Used by the IOD thread during connection setup. + */ +int +smb_rq_internal(struct smb_rq *rqp, int timeout) +{ + struct smb_vc *vcp = rqp->sr_vc; + int err; + + rqp->sr_flags &= ~SMBR_RESTART; + rqp->sr_timo = timeout; /* in seconds */ + rqp->sr_state = SMBRQ_NOTSENT; + + /* + * Skip smb_rq_enqueue(rqp) here, as we don't want it + * trying to reconnect etc. We're doing that. + */ + rqp->sr_rquid = vcp->vc_smbuid; + rqp->sr_rqtid = SMB_TID_UNKNOWN; + err = smb_iod_addrq(rqp); + if (err != 0) + return (err); + + err = smb_rq_reply(rqp); + + return (err); +} + /* * Mark location of the word count, which is filled in later by * smb_rw_wend(). Also initialize the counter that it uses @@ -495,7 +524,20 @@ smb_rq_reply(struct smb_rq *rqp) 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) { + + if (rqp->sr_error != 0) { + if (rqp->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) { + rperror = smb_maperr32(rqp->sr_error); + } else { + uint8_t errClass = rqp->sr_error & 0xff; + uint16_t errCode = rqp->sr_error >> 16; + /* Convert to NT status */ + rqp->sr_error = smb_doserr2status(errClass, errCode); + rperror = smb_maperror(errClass, errCode); + } + } + + if (rperror) { /* * Do a special check for STATUS_BUFFER_OVERFLOW; * it's not an error. @@ -506,23 +548,13 @@ smb_rq_reply(struct smb_rq *rqp) * 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? */ + rqp->sr_flags |= SMBR_MOREDATA; 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_uint32le(mdp, NULL); error = md_get_uint32le(mdp, NULL); diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h index 0184022a65..4d6dbb1fe0 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h @@ -34,6 +34,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _NETSMB_SMB_RQ_H_ @@ -54,7 +55,7 @@ #define SMBR_NOINTR_RECV 0x0200 /* no interrupt in recv wait */ #define SMBR_SENDWAIT 0x0400 /* waiting for send to complete */ #define SMBR_NORECONNECT 0x0800 /* do not reconnect for this */ -/* SMBR_VCREF 0x4000 * took vc reference (obsolete) */ +/* SMBR_VCREF 0x4000 * took vc reference (obsolete) */ #define SMBR_MOREDATA 0x8000 /* our buffer was too small */ #define SMBT2_ALLSENT 0x0001 /* all data and params are sent */ @@ -64,7 +65,7 @@ #define SMBT2_NORESTART 0x0010 #define SMBT2_MOREDATA 0x8000 /* our buffer was too small */ -#define SMBRQ_LOCK(rqp) mutex_enter(&(rqp)->sr_lock) +#define SMBRQ_LOCK(rqp) mutex_enter(&(rqp)->sr_lock) #define SMBRQ_UNLOCK(rqp) mutex_exit(&(rqp)->sr_lock) enum smbrq_state { @@ -83,7 +84,7 @@ struct smb_rq { enum smbrq_state sr_state; struct smb_vc *sr_vc; struct smb_share *sr_share; - struct _kthread *sr_owner; + struct _kthread *sr_owner; uint32_t sr_seqno; /* Seq. no. of request */ uint32_t sr_rseqno; /* Seq. no. of reply */ struct mbchain sr_rq; @@ -105,7 +106,7 @@ struct smb_rq { int sr_timo; int sr_rexmit; /* how many more retries. dflt 0 */ int sr_sendcnt; - struct timespec sr_timesent; + struct timespec sr_timesent; int sr_lerror; uint8_t sr_errclass; uint16_t sr_serror; @@ -124,7 +125,7 @@ struct smb_t2rq { kcondvar_t t2_cond; uint16_t t2_setupcount; uint16_t *t2_setupdata; - uint16_t t2_setup[SMBIOC_T2RQ_MAXSETUP]; + uint16_t t2_setup[4]; 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 */ @@ -193,6 +194,7 @@ 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_rq_internal(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); diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c index d0f3e493ef..0d3b21a888 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -69,6 +69,31 @@ smb_crypto_mech_init(void) cmn_err(CE_NOTE, "nsmb can't get md5 mech"); } +/* + * This is called just after session setup completes, + * at the top of smb_iod_vc_work(). Initialize signing. + */ +int +smb_sign_init(smb_vc_t *vcp) +{ + + ASSERT(vcp->vc_ssnkey != NULL); + ASSERT(vcp->vc_mackey == NULL); + + /* + * Convert the session key to the MAC key. + * SMB1 uses the whole session key. + */ + vcp->vc_mackeylen = vcp->vc_ssnkeylen; + vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP); + bcopy(vcp->vc_ssnkey, vcp->vc_mackey, vcp->vc_mackeylen); + + /* The initial sequence number is two. */ + vcp->vc_next_seq = 2; + + return (0); +} + #define SMBSIGLEN 8 /* SMB signature length */ #define SMBSIGOFF 14 /* SMB signature offset */ diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c index efb7e9a03d..47f9a201cc 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c @@ -33,8 +33,9 @@ */ /* + * Portions Copyright (C) 2001 - 2014 Apple Inc. All rights reserved. * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -71,12 +72,38 @@ */ #define SMB_MAX_LARGE_RW_SIZE (60*1024) +struct smb_dialect { + int d_id; + const char *d_name; +}; + +static struct smb_dialect smb_dialects[] = { + {SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"}, + {SMB_DIALECT_COREPLUS, "MICROSOFT NETWORKS 1.03"}, + {SMB_DIALECT_LANMAN1_0, "MICROSOFT NETWORKS 3.0"}, + {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"}, + {SMB_DIALECT_LANMAN2_0, "LM1.2X002"}, + {SMB_DIALECT_LANMAN2_1, "LANMAN2.1"}, + {SMB_DIALECT_NTLM0_12, "NT LANMAN 1.0"}, + {SMB_DIALECT_NTLM0_12, "NT LM 0.12"}, +}; +static uint_t smb_ndialect = + sizeof (smb_dialects) / sizeof (smb_dialects[0]); + +static const uint32_t smb_clnt_caps_mask = + SMB_CAP_UNICODE | + SMB_CAP_LARGE_FILES | + SMB_CAP_NT_SMBS | + SMB_CAP_STATUS32 | + SMB_CAP_EXT_SECURITY; + /* * 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_logon = 45; int smb_timo_open = 45; int smb_timo_read = 45; int smb_timo_write = 60; /* was SMBWRTTIMO */ @@ -92,6 +119,443 @@ static int smb_smb_readx(struct smb_share *ssp, uint16_t fid, static int smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); +int +smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) +{ + smb_sopt_t *sv = &vcp->vc_sopt; + smbioc_ssn_work_t *wk = &vcp->vc_work; + struct smb_rq *rqp = NULL; + struct mbchain *mbp = NULL; + struct mdchain *mdp = NULL; + struct smb_dialect *dp; + int err, sblen, tlen; + uint8_t wc, eklen; + uint16_t dindex, bc; + boolean_t will_sign = B_FALSE; + + /* + * Initialize: vc_hflags and vc_hflags2. + * Note: vcp->vc_hflags* are copied into the + * (per request) rqp->rq_hflags* by smb_rq_init. + * + * Like Windows, set FLAGS2_UNICODE in our first request, + * even though technically we don't yet know whether the + * server supports Unicode. Will clear this flag below + * if we find out it doesn't. Need to do this because + * some servers reject all non-Unicode requests. + */ + vcp->vc_hflags = + SMB_FLAGS_CASELESS | + SMB_FLAGS_CANONICAL_PATHNAMES; + vcp->vc_hflags2 = + SMB_FLAGS2_KNOWS_LONG_NAMES | + SMB_FLAGS2_KNOWS_EAS | + SMB_FLAGS2_IS_LONG_NAME | + SMB_FLAGS2_EXT_SEC | + SMB_FLAGS2_ERR_STATUS | + SMB_FLAGS2_UNICODE; + + /* + * The initial UID needs to be zero, + */ + vcp->vc_smbuid = 0; + + /* + * (Re)init negotiated values + */ + bzero(sv, sizeof (*sv)); + sv->sv_maxmux = 1; + sv->sv_maxvcs = 1; + sv->sv_maxtx = 1024; + + err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp); + if (err) + return (err); + + /* + * Build the SMB request. + */ + smb_rq_getrequest(rqp, &mbp); + smb_rq_wstart(rqp); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + for (dindex = 0; dindex < smb_ndialect; dindex++) { + dp = &smb_dialects[dindex]; + mb_put_uint8(mbp, SMB_DT_DIALECT); + tlen = strlen(dp->d_name) + 1; + mb_put_mem(mbp, dp->d_name, tlen, MB_MSYSTEM); + } + smb_rq_bend(rqp); + + /* + * Do the OTW call. + */ + err = smb_rq_internal(rqp, smb_timo_default); + if (err) { + SMBSDEBUG("smb_rq_internal, err %d", err); + goto errout; + } + + /* + * Decode the response + * + * Comments to right show names as described in + * The Microsoft SMB Protocol spec. [MS-SMB] + * section 2.2.3 + */ + smb_rq_getreply(rqp, &mdp); + (void) md_get_uint8(mdp, &wc); + err = md_get_uint16le(mdp, &dindex); + if (err != 0) + goto errout; + if (dindex >= smb_ndialect) { + SMBERROR("Invalid dialect index from server: %s\n", + vcp->vc_srvname); + err = EBADRPC; + goto errout; + } + dp = smb_dialects + dindex; + sv->sv_proto = dp->d_id; + SMBSDEBUG("Dialect %s", dp->d_name); + if (dp->d_id < SMB_DIALECT_NTLM0_12) { + SMBSDEBUG("old dialect %s", dp->d_name); + goto errout; + } + if (wc != 17) { + SMBSDEBUG("bad wc %d", (int)wc); + goto errout; + } + md_get_uint8(mdp, &sv->sv_sm); /* SecurityMode */ + md_get_uint16le(mdp, &sv->sv_maxmux); /* MaxMpxCount */ + md_get_uint16le(mdp, &sv->sv_maxvcs); /* MaxCountVCs */ + md_get_uint32le(mdp, &sv->sv_maxtx); /* MaxBufferSize */ + md_get_uint32le(mdp, &sv->sv_maxraw); /* MaxRawSize */ + md_get_uint32le(mdp, &sv->sv_skey); /* SessionKey */ + md_get_uint32le(mdp, &sv->sv_caps); /* Capabilities */ + md_get_mem(mdp, NULL, 8, MB_MSYSTEM); /* SystemTime(s) */ + md_get_uint16le(mdp, (uint16_t *)&sv->sv_tz); + md_get_uint8(mdp, &eklen); /* EncryptionKeyLength */ + err = md_get_uint16le(mdp, &bc); /* ByteCount */ + if (err) + goto errout; + + /* BEGIN CSTYLED */ + /* + * Will we do SMB signing? Or block the connection? + * The table below describes this logic. References: + * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3] + * http://msdn.microsoft.com/en-us/library/cc212511.aspx + * http://msdn.microsoft.com/en-us/library/cc212929.aspx + * + * Srv/Cli | Required | Enabled | If Required | Disabled + * ------------+----------+------------+-------------+----------- + * Required | Signed | Signed | Signed | Blocked [1] + * ------------+----------+------------+-------------+----------- + * Enabled | Signed | Signed | Not Signed | Not Signed + * ------------+----------+------------+-------------+----------- + * If Required | Signed | Not Signed | Not Signed | Not Signed + * ------------+----------+------------+-------------+----------- + * Disabled | Blocked | Not Signed | Not Signed | Not Signed + * + * [1] Like Windows 2003 and later, we don't really implement + * the "Disabled" setting. Instead we implement "If Required", + * so we always sign if the server requires signing. + */ + /* END CSTYLED */ + + if (sv->sv_sm & SMB_SM_SIGS_REQUIRE) { + /* + * Server requires signing. We will sign, + * even if local setting is "disabled". + */ + will_sign = B_TRUE; + } else if (sv->sv_sm & SMB_SM_SIGS) { + /* + * Server enables signing (client's option). + * If enabled locally, do signing. + */ + if (vcp->vc_vopt & SMBVOPT_SIGNING_ENABLED) + will_sign = B_TRUE; + /* else not signing. */ + } else { + /* + * Server does not support signing. + * If we "require" it, bail now. + */ + if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) { + SMBERROR("Client requires signing " + "but server has it disabled."); + err = EBADRPC; + goto errout; + } + } + + /* + * Anonymous sessions can't sign. + */ + if (vcp->vc_vopt & SMBVOPT_ANONYMOUS) { + will_sign = B_FALSE; + } + + SMBSDEBUG("Security signatures: %d", (int)will_sign); + if (will_sign) { + vcp->vc_flags |= SMBV_WILL_SIGN; + vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; + + /* + * MS-SMB 2.2.4.5 says that when SMB signing is enabled, + * we should NOT use "large read/write" even though the + * server might offer those capabilities. + */ + sv->sv_caps &= ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX); + } + + /* See comment above re. FLAGS2_UNICODE */ + if ((sv->sv_caps & SMB_CAP_UNICODE) != 0) + vcp->vc_flags |= SMBV_UNICODE; + else + vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE; + + if ((sv->sv_caps & SMB_CAP_STATUS32) == 0) { + /* They don't do NT error codes. */ + vcp->vc_hflags2 &= ~SMB_FLAGS2_ERR_STATUS; + } + + /* + * The rest of the message varies depending on + * whether we've negotiated "extended security". + * + * With extended security, we have: + * Server_GUID (length 16) + * Security_BLOB + * Otherwise we have: + * EncryptionKey (length is eklen) + * PrimaryDomain + */ + if (sv->sv_caps & SMB_CAP_EXT_SECURITY) { + SMBSDEBUG("Ext.Security: yes"); + + /* + * Skip the server GUID. + */ + err = md_get_mem(mdp, NULL, SMB_GUIDLEN, MB_MSYSTEM); + if (err) + goto errout; + /* + * Remainder is the security blob. + * Note: eklen "must be ignored" [MS-SMB] + */ + sblen = (int)bc - SMB_GUIDLEN; + if (sblen < 0) + goto errout; + /* Security blob (hint) is next */ + } else { + SMBSDEBUG("Ext.Security: no"); + err = ENOTSUP; + goto errout; + } + + /* + * Copy the security blob out to user space. + * Buffer addr,size in vc_auth_rbuf,rlen + */ + if (wk->wk_u_auth_rlen < sblen) { + SMBSDEBUG("vc_auth_rbuf too small"); + /* Give caller required size. */ + wk->wk_u_auth_rlen = sblen; + err = EMSGSIZE; + goto errout; + } + wk->wk_u_auth_rlen = sblen; + err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr, sblen, MB_MUSER); + if (err) + goto errout; + + /* + * A few sanity checks on what we received, + * becuse we will send these in ssnsetup. + * + * Maximum outstanding requests (we care), + * and Max. VCs (we only use one). Also, + * MaxBufferSize lower limit per spec. + */ + if (sv->sv_maxmux < 1) + sv->sv_maxmux = 1; + if (sv->sv_maxvcs < 1) + sv->sv_maxvcs = 1; + if (sv->sv_maxtx < 1024) + sv->sv_maxtx = 1024; + + /* + * Maximum transfer size. + * Sanity checks: + * + * Let's be conservative about an upper limit here. + * Win2k uses 16644 (and others) so 32k should be a + * reasonable sanity limit for this value. + * + * Note that this limit does NOT affect READX/WRITEX + * with CAP_LARGE_..., which we nearly always use. + */ + vcp->vc_txmax = sv->sv_maxtx; + if (vcp->vc_txmax > 0x8000) + vcp->vc_txmax = 0x8000; + + /* + * Max read/write sizes, WITHOUT overhead. + * This is just the payload size, so we must + * leave room for the SMB headers, etc. + * This is just the ct_txmax value, but + * reduced and rounded down. Tricky bit: + * + * Servers typically give us a value that's + * some nice "round" number, i.e 0x4000 plus + * some overhead, i.e. Win2k: 16644==0x4104 + * Subtract for the SMB header (32) and the + * SMB command word and byte vectors (34?), + * then round down to a 512 byte multiple. + */ + tlen = vcp->vc_txmax - 68; + tlen &= 0xFE00; + + vcp->vc_rwmax = tlen; + vcp->vc_rxmax = tlen; + vcp->vc_wxmax = tlen; + + /* + * Most of the "capability" bits we offer in session setup + * are just copied from those offered by the server. + */ + sv->sv_caps &= smb_clnt_caps_mask; + + smb_rq_done(rqp); + return (0); + +errout: + smb_rq_done(rqp); + if (err == 0) + err = EBADRPC; + return (err); +} + +static const char NativeOS[] = "illumos"; +static const char LanMan[] = "NETSMB"; + +int +smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred) +{ + smb_sopt_t *sv = &vcp->vc_sopt; + smbioc_ssn_work_t *wk = &vcp->vc_work; + struct smb_rq *rqp = NULL; + struct mbchain *mbp = NULL; + struct mdchain *mdp = NULL; + char *sb; + int err, ret; + uint32_t caps; + uint16_t action, bc, sblen; + uint8_t wc; + + caps = sv->sv_caps; + sb = wk->wk_u_auth_wbuf.lp_ptr; + sblen = (uint16_t)wk->wk_u_auth_wlen; + + err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, + scred, &rqp); + if (err != 0) { + ret = err; + goto out; + } + + /* + * Build the SMB Session Setup request. + * Always extended security form. + */ + mbp = &rqp->sr_rq; + smb_rq_wstart(rqp); + mb_put_uint16le(mbp, 0xff); /* 0: AndXCommand */ + mb_put_uint16le(mbp, 0); /* 1: AndXOffset */ + mb_put_uint16le(mbp, sv->sv_maxtx); /* 2: MaxBufferSize */ + mb_put_uint16le(mbp, sv->sv_maxmux); /* 3: MaxMpxCount */ + mb_put_uint16le(mbp, 1); /* 4: VcNumber */ + mb_put_uint32le(mbp, sv->sv_skey); /* 5,6: Session Key */ + mb_put_uint16le(mbp, sblen); /* 7: Sec. Blob Len */ + mb_put_uint32le(mbp, 0); /* 8,9: reserved */ + mb_put_uint32le(mbp, caps); /* 10,11: Capabilities */ + smb_rq_wend(rqp); /* 12: Byte Count */ + smb_rq_bstart(rqp); + err = mb_put_mem(mbp, sb, sblen, MB_MUSER); + if (err != 0) { + ret = err; + goto out; + } + (void) smb_put_dstring(mbp, vcp, NativeOS, SMB_CS_NONE); + (void) smb_put_dstring(mbp, vcp, LanMan, SMB_CS_NONE); + smb_rq_bend(rqp); + + /* + * Run the request. The return value here should be the + * return from this function, unless we fail decoding. + * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK. + */ + ret = smb_rq_internal(rqp, smb_timo_logon); + if (ret != 0 && rqp->sr_error != + NT_STATUS_MORE_PROCESSING_REQUIRED) { + /* UID no longer valid. */ + vcp->vc_smbuid = 0; + goto out; + } + + if (vcp->vc_smbuid == 0) + vcp->vc_smbuid = rqp->sr_rpuid; + + /* + * Parse the reply + */ + smb_rq_getreply(rqp, &mdp); + + err = md_get_uint8(mdp, &wc); + if (err != 0) + wc = 0; + if (wc != 4) { + ret = EBADRPC; + goto out; + } + md_get_uint16le(mdp, NULL); /* secondary cmd */ + md_get_uint16le(mdp, NULL); /* andxoffset */ + md_get_uint16le(mdp, &action); /* action XXX */ + md_get_uint16le(mdp, &sblen); /* sec. blob len */ + md_get_uint16le(mdp, &bc); /* byte count */ + /* + * Get the security blob, after + * sanity-checking the length. + */ + if (sblen == 0 || sblen > bc) { + ret = EBADRPC; + goto out; + } + if (sblen > wk->wk_u_auth_rlen) { + ret = EBADRPC; + goto out; + } + sb = wk->wk_u_auth_rbuf.lp_ptr; + err = md_get_mem(mdp, sb, sblen, MB_MUSER); + if (err) { + ret = EBADRPC; + goto out; + } + + /* + * Native OS, LANMGR, & Domain follow here. + * We don't need them and don't parse them. + */ + +out: + if (rqp) + smb_rq_done(rqp); + + return (ret); +} + /* * Get the string representation of a share "use" type, * as needed for the "service" in tree connect. diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h index df0f28ec05..48815ff709 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h @@ -33,8 +33,8 @@ */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _NETSMB_SMB_SUBR_H_ @@ -117,6 +117,8 @@ extern int smb_timo_open; extern int smb_timo_read; extern int smb_timo_write; extern int smb_timo_append; +extern dev_t nsmb_dev_tcp; +extern dev_t nsmb_dev_tcp6; #define EMOREDATA (0x7fff) @@ -133,6 +135,7 @@ int smb_ntlmv2response(const uchar_t *hash, const uchar_t *C8, const uchar_t *blob, size_t bloblen, uchar_t **RN, size_t *RNlen); int smb_maperror(int eclass, int eno); int smb_maperr32(uint32_t eno); +uint_t smb_doserr2status(int, int); 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, @@ -144,8 +147,8 @@ 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); +int smb_sign_init(struct smb_vc *); void smb_rq_sign(struct smb_rq *); int smb_rq_verify(struct smb_rq *); int smb_calcv2mackey(struct smb_vc *, const uchar_t *, @@ -158,6 +161,8 @@ void smb_crypto_mech_init(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_echo(smb_vc_t *vcp, smb_cred_t *scred, int timo); int smb_smb_treeconnect(smb_share_t *ssp, smb_cred_t *scred); int smb_smb_treedisconnect(smb_share_t *ssp, smb_cred_t *scred); diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c index a581aa3533..dc0e824e5e 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c @@ -34,7 +34,8 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -58,40 +59,6 @@ #include #include -/* - * 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, cred_t *cr) { @@ -223,7 +190,9 @@ static const nt2errno_t nt2errno[] = { {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_BAD_NETWORK_PATH, ENOENT}, + {NT_STATUS_BUFFER_TOO_SMALL, E2BIG}, + {NT_STATUS_CANCELLED, ECANCELED}, {NT_STATUS_CANNOT_DELETE, EACCES}, {NT_STATUS_CONFLICTING_ADDRESSES, EADDRINUSE}, {NT_STATUS_CONNECTION_ABORTED, ECONNABORTED}, @@ -237,59 +206,87 @@ static const nt2errno_t nt2errno[] = { {NT_STATUS_DISK_FULL, ENOSPC}, {NT_STATUS_DLL_NOT_FOUND, ELIBACC}, {NT_STATUS_DUPLICATE_NAME, EINVAL}, + {NT_STATUS_EAS_NOT_SUPPORTED, ENOTSUP}, + {NT_STATUS_EA_TOO_LARGE, E2BIG}, {NT_STATUS_END_OF_FILE, ENODATA}, + {NT_STATUS_FILE_CLOSED, EBADF}, + {NT_STATUS_FILE_DELETED, ENOENT}, + {NT_STATUS_FILE_INVALID, EIO}, {NT_STATUS_FILE_IS_A_DIRECTORY, EISDIR}, {NT_STATUS_FILE_LOCK_CONFLICT, EAGAIN}, + {NT_STATUS_FILE_RENAMED, ENOENT}, {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_ILL_FORMED_PASSWORD, EAUTH}, + {NT_STATUS_INFO_LENGTH_MISMATCH, EINVAL}, + {NT_STATUS_INSUFFICIENT_RESOURCES, EAGAIN}, + {NT_STATUS_INSUFF_SERVER_RESOURCES, EAGAIN}, {NT_STATUS_INTEGER_OVERFLOW, ERANGE}, - {NT_STATUS_INVALID_ACCOUNT_NAME, EACCES}, + {NT_STATUS_INVALID_ACCOUNT_NAME, EAUTH}, + {NT_STATUS_INVALID_BUFFER_SIZE, EIO}, + {NT_STATUS_INVALID_DEVICE_REQUEST, EINVAL}, {NT_STATUS_INVALID_HANDLE, EBADF}, + {NT_STATUS_INVALID_INFO_CLASS, EINVAL}, {NT_STATUS_INVALID_LEVEL, ENOTSUP}, - {NT_STATUS_INVALID_LOGON_HOURS, EACCES}, + {NT_STATUS_INVALID_LOCK_SEQUENCE, EINVAL}, + {NT_STATUS_INVALID_LOGON_HOURS, EAUTH}, {NT_STATUS_INVALID_OWNER, EINVAL}, {NT_STATUS_INVALID_PARAMETER, EINVAL}, {NT_STATUS_INVALID_PIPE_STATE, EPIPE}, {NT_STATUS_INVALID_PRIMARY_GROUP, EINVAL}, {NT_STATUS_INVALID_WORKSTATION, EACCES}, {NT_STATUS_IN_PAGE_ERROR, EFAULT}, + {NT_STATUS_IO_DEVICE_ERROR, EIO}, {NT_STATUS_IO_TIMEOUT, ETIMEDOUT}, - {NT_STATUS_IP_ADDRESS_CONFLICT1, ENOTUNIQ}, - {NT_STATUS_IP_ADDRESS_CONFLICT2, ENOTUNIQ}, + {NT_STATUS_IP_ADDRESS_CONFLICT1, EADDRINUSE}, + {NT_STATUS_IP_ADDRESS_CONFLICT2, EADDRINUSE}, {NT_STATUS_LICENSE_QUOTA_EXCEEDED, EDQUOT}, {NT_STATUS_LOCK_NOT_GRANTED, EAGAIN}, - {NT_STATUS_LOGIN_TIME_RESTRICTION, EACCES}, - {NT_STATUS_LOGON_FAILURE, EACCES}, + {NT_STATUS_LOGIN_TIME_RESTRICTION, EAUTH}, + {NT_STATUS_LOGON_FAILURE, EAUTH}, + {NT_STATUS_LOGON_TYPE_NOT_GRANTED, EAUTH}, {NT_STATUS_MEDIA_WRITE_PROTECTED, EROFS}, {NT_STATUS_MEMORY_NOT_ALLOCATED, EFAULT}, + {NT_STATUS_MORE_PROCESSING_REQUIRED, EINPROGRESS}, {NT_STATUS_NAME_TOO_LONG, ENAMETOOLONG}, {NT_STATUS_NETWORK_ACCESS_DENIED, EACCES}, {NT_STATUS_NETWORK_BUSY, EBUSY}, + {NT_STATUS_NETWORK_NAME_DELETED, ENOENT}, {NT_STATUS_NETWORK_UNREACHABLE, ENETUNREACH}, {NT_STATUS_NET_WRITE_FAULT, ECOMM}, + {NT_STATUS_NONEXISTENT_EA_ENTRY, ENOENT}, {NT_STATUS_NONEXISTENT_SECTOR, ESPIPE}, {NT_STATUS_NONE_MAPPED, EINVAL}, {NT_STATUS_NOT_A_DIRECTORY, ENOTDIR}, + {NT_STATUS_NOT_FOUND, ENOENT}, {NT_STATUS_NOT_IMPLEMENTED, ENOTSUP}, + {NT_STATUS_NOT_LOCKED, ENOLCK}, {NT_STATUS_NOT_MAPPED_VIEW, EINVAL}, {NT_STATUS_NOT_SUPPORTED, ENOTSUP}, + {NT_STATUS_NO_EAS_ON_FILE, ENOENT}, + {NT_STATUS_NO_LOGON_SERVERS, EAUTH}, {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_NO_SUCH_LOGON_SESSION, EAUTH}, + {NT_STATUS_NO_SUCH_USER, EAUTH}, + {NT_STATUS_NO_TRUST_LSA_SECRET, EAUTH}, + {NT_STATUS_NO_TRUST_SAM_ACCOUNT, EAUTH}, {NT_STATUS_OBJECT_NAME_COLLISION, EEXIST}, {NT_STATUS_OBJECT_NAME_INVALID, EINVAL}, {NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT}, {NT_STATUS_OBJECT_PATH_INVALID, ENOTDIR}, {NT_STATUS_OBJECT_PATH_NOT_FOUND, ENOENT}, + {NT_STATUS_OBJECT_PATH_SYNTAX_BAD, EINVAL}, + {NT_STATUS_OBJECT_TYPE_MISMATCH, EBADF}, {NT_STATUS_PAGEFILE_QUOTA, EDQUOT}, - {NT_STATUS_PASSWORD_EXPIRED, EACCES}, - {NT_STATUS_PASSWORD_MUST_CHANGE, EACCES}, - {NT_STATUS_PASSWORD_RESTRICTION, EACCES}, + {NT_STATUS_PASSWORD_EXPIRED, EAUTH}, + {NT_STATUS_PASSWORD_MUST_CHANGE, EAUTH}, + {NT_STATUS_PASSWORD_RESTRICTION, EAUTH}, {NT_STATUS_PATH_NOT_COVERED, ENOENT}, {NT_STATUS_PIPE_BROKEN, EPIPE}, {NT_STATUS_PIPE_BUSY, EPIPE}, @@ -297,11 +294,12 @@ static const nt2errno_t nt2errno[] = { {NT_STATUS_PIPE_DISCONNECTED, EPIPE}, {NT_STATUS_PIPE_NOT_AVAILABLE, EBUSY}, {NT_STATUS_PORT_CONNECTION_REFUSED, ECONNREFUSED}, + {NT_STATUS_PORT_DISCONNECTED, EBADF}, {NT_STATUS_PORT_MESSAGE_TOO_LONG, EMSGSIZE}, {NT_STATUS_PORT_UNREACHABLE, EHOSTUNREACH}, {NT_STATUS_PROTOCOL_UNREACHABLE, ENOPROTOOPT}, {NT_STATUS_QUOTA_EXCEEDED, EDQUOT}, - {NT_STATUS_RANGE_NOT_LOCKED, EIO}, + {NT_STATUS_RANGE_NOT_LOCKED, EAGAIN}, /* like F_SETLK */ {NT_STATUS_REGISTRY_QUOTA_LIMIT, EDQUOT}, {NT_STATUS_REMOTE_DISCONNECT, ESHUTDOWN}, {NT_STATUS_REMOTE_NOT_LISTENING, ECONNREFUSED}, @@ -311,9 +309,11 @@ static const nt2errno_t nt2errno[] = { {NT_STATUS_TIMER_NOT_CANCELED, ETIME}, {NT_STATUS_TOO_MANY_LINKS, EMLINK}, {NT_STATUS_TOO_MANY_OPENED_FILES, EMFILE}, + {NT_STATUS_TRUSTED_DOMAIN_FAILURE, EAUTH}, + {NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE, EAUTH}, {NT_STATUS_UNABLE_TO_FREE_VM, EADDRINUSE}, {NT_STATUS_UNSUCCESSFUL, EINVAL}, - {NT_STATUS_WRONG_PASSWORD, EACCES}, + {NT_STATUS_WRONG_PASSWORD, EAUTH}, {0, 0} }; @@ -872,6 +872,19 @@ smb_maperr32(uint32_t nterr) return (EIO); } +uint_t +smb_doserr2status(int dclass, int derr) +{ + const nt2doserr_t *nt2d; + + if (dclass == 0 && derr == 0) + return (0); + + for (nt2d = nt2doserr; nt2d->nterr; nt2d++) + if (nt2d->dclass == dclass && nt2d->derr == derr) + return (nt2d->nterr); + return (NT_STATUS_UNSUCCESSFUL); +} int smb_maperror(int eclass, int eno) diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h index fd8f91eb1c..dc44fcc755 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h @@ -36,7 +36,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _NETSMB_SMB_TRAN_H_ @@ -54,11 +54,14 @@ struct file; #define SMBT_NBTCP 1 /* - * Transport parameters + * Transport parameters, for tr_getparam/tr_setparam */ -#define SMBTP_SNDSZ 1 /* R - int */ -#define SMBTP_RCVSZ 2 /* R - int */ -#define SMBTP_TIMEOUT 3 /* RW - struct timespec */ +#define SMBTP_TCP_NODELAY 0x01 /* RW - int */ +#define SMBTP_TCP_CON_TMO 0x13 /* RW - int */ +#define SMBTP_KEEPALIVE SO_KEEPALIVE /* RW - int */ +#define SMBTP_SNDBUF SO_SNDBUF /* RW - int */ +#define SMBTP_RCVBUF SO_RCVBUF /* RW - int */ +#define SMBTP_RCVTIMEO SO_RCVTIMEO /* RW - int? */ struct smb_tran_ops; diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c index 0b44cf879f..733ff9d078 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c @@ -35,7 +35,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -74,13 +74,6 @@ #include #include -/* - * SMB messages are up to 64K. - * Let's leave room for two. - */ -static int smb_tcpsndbuf = 0x20000; -static int smb_tcprcvbuf = 0x20000; - static int nb_disconnect(struct nbpcb *nbp); @@ -486,22 +479,45 @@ out: * This is called only by the thread creating this endpoint, * so we're single-threaded here. */ -/*ARGSUSED*/ static int smb_nbst_create(struct smb_vc *vcp, cred_t *cr) { - struct nbpcb *nbp; + TIUSER *tiptr = NULL; + struct nbpcb *nbp = NULL; + dev_t dev; + int rc; + ushort_t fmode; + + switch (vcp->vc_srvaddr.sa.sa_family) { + case AF_INET: + dev = nsmb_dev_tcp; + break; + case AF_INET6: + dev = nsmb_dev_tcp6; + break; + default: + return (EAFNOSUPPORT); + } + + fmode = FREAD|FWRITE; + rc = t_kopen(NULL, dev, fmode, &tiptr, cr); + if (rc != 0) { + cmn_err(CE_NOTE, "t_kopen failed, rc=%d", rc); + return (rc); + } + ASSERT(tiptr != NULL); nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP); nbp->nbp_timo.tv_sec = SMB_NBTIMO; - nbp->nbp_state = NBST_CLOSED; /* really IDLE */ + nbp->nbp_state = NBST_IDLE; nbp->nbp_vc = vcp; - nbp->nbp_sndbuf = smb_tcpsndbuf; - nbp->nbp_rcvbuf = smb_tcprcvbuf; + nbp->nbp_tiptr = tiptr; + nbp->nbp_fmode = fmode; nbp->nbp_cred = cr; crhold(cr); mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL); + vcp->vc_tdata = nbp; return (0); @@ -543,6 +559,8 @@ smb_nbst_done(struct smb_vc *vcp) } /* + * XXX - Later, get rid of nb_loan_fp, nb_unloan_fp + * * Loan a transport file pointer (from user space) to this * IOD endpoint. There should be no other thread using this * endpoint when we do this, but lock for consistency. @@ -632,21 +650,62 @@ smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr) return (error); } -/*ARGSUSED*/ static int smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap) { - return (ENOTSUP); + struct nbpcb *nbp = vcp->vc_tdata; + TIUSER *tiptr = nbp->nbp_tiptr; + int err; + + /* Only default bind supported. */ + if (sap != NULL) + return (ENOTSUP); + + err = t_kbind(tiptr, NULL, NULL); + + return (err); } -/*ARGSUSED*/ static int smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap) { - return (ENOTSUP); + struct t_call call; + struct nbpcb *nbp = vcp->vc_tdata; + TIUSER *tiptr = nbp->nbp_tiptr; + int alen, err; + + /* Need the address length */ + switch (sap->sa_family) { + case AF_INET: + alen = sizeof (struct sockaddr_in); + break; + case AF_INET6: + alen = sizeof (struct sockaddr_in6); + break; + default: + return (EAFNOSUPPORT); + } + + /* sockaddr goes in the "addr" netbuf */ + bzero(&call, sizeof (call)); + call.addr.buf = (char *)sap; + call.addr.len = alen; + call.addr.maxlen = alen; + + err = t_kconnect(tiptr, &call, NULL); + if (err != 0) + return (err); + + mutex_enter(&nbp->nbp_lock); + + nbp->nbp_flags |= NBF_CONNECTED; + nbp->nbp_state = NBST_SESSION; + + mutex_exit(&nbp->nbp_lock); + + return (0); } -/*ARGSUSED*/ static int smb_nbst_disconnect(struct smb_vc *vcp) { @@ -833,42 +892,78 @@ smb_nbst_poll(struct smb_vc *vcp, int ticks) return (ENOTSUP); } +/*ARGSUSED*/ static int smb_nbst_getparam(struct smb_vc *vcp, int param, void *data) { + return (EINVAL); +} + +static int +smb_nbst_setparam(struct smb_vc *vcp, int param, void *data) +{ + struct t_optmgmt oreq, ores; + struct { + struct T_opthdr oh; + int ival; + } opts; struct nbpcb *nbp = vcp->vc_tdata; + int level, name, err; 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; + case SMBTP_TCP_NODELAY: + level = IPPROTO_TCP; + name = TCP_NODELAY; break; -#ifdef SMBTP_SELECTID - case SMBTP_SELECTID: - *(void **)data = nbp->nbp_selectid; + + case SMBTP_TCP_CON_TMO: /* int mSec */ + level = IPPROTO_TCP; + name = TCP_CONN_ABORT_THRESHOLD; break; -#endif -#ifdef SMBTP_UPCALL - case SMBTP_UPCALL: - *(void **)data = nbp->nbp_upcall; + + case SMBTP_KEEPALIVE: // SO_KEEPALIVE + case SMBTP_SNDBUF: // SO_SNDBUF + case SMBTP_RCVBUF: // SO_RCVBUF + case SMBTP_RCVTIMEO: // SO_RCVTIMEO + level = SOL_SOCKET; + name = param; break; -#endif + default: return (EINVAL); } - return (0); -} -/*ARGSUSED*/ -static int -smb_nbst_setparam(struct smb_vc *vcp, int param, void *data) -{ - return (EINVAL); + /* opt header */ + opts.oh.len = sizeof (opts); + opts.oh.level = level; + opts.oh.name = name; + opts.oh.status = 0; + opts.ival = *(int *)data; + + oreq.flags = T_NEGOTIATE; + oreq.opt.buf = (void *)&opts; + oreq.opt.len = sizeof (opts); + oreq.opt.maxlen = oreq.opt.len; + + ores.flags = 0; + ores.opt.buf = NULL; + ores.opt.len = 0; + ores.opt.maxlen = 0; + + err = t_koptmgmt(nbp->nbp_tiptr, &oreq, &ores); + if (err != 0) { + cmn_err(CE_NOTE, "t_opgmgnt, err = %d", err); + return (EPROTO); + } + + if (ores.flags != T_SUCCESS) { + cmn_err(CE_NOTE, "smb_nbst_setparam: " + "flags 0x%x, status 0x%x", + (int)ores.flags, (int)opts.oh.status); + return (EPROTO); + } + + return (0); } /* diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h index f810a538cd..3c5e86639e 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h @@ -32,13 +32,14 @@ * $Id: smb_trantcp.h,v 1.8 2004/08/03 23:50:01 lindak Exp $ */ /* - * Copyright 2012 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _NETSMB_SMB_TRANTCP_H_ #define _NETSMB_SMB_TRANTCP_H_ enum nbstate { NBST_CLOSED, + NBST_IDLE, NBST_RQSENT, NBST_SESSION, NBST_RETARGET, diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c index fb587cd79e..5209732a1e 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c @@ -33,9 +33,10 @@ */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -60,28 +61,6 @@ static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg); -/* - * Ioctl function for SMBIOC_FLAGS2 - */ -int -smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags) -{ - struct smb_vc *vcp = NULL; - - /* This ioctl requires a session. */ - if ((vcp = sdp->sd_vc) == NULL) - return (ENOTCONN); - - /* - * Return the flags2 value. - */ - if (ddi_copyout(&vcp->vc_hflags2, (void *)arg, - sizeof (u_int16_t), flags)) - return (EFAULT); - - return (0); -} - /* * Ioctl function for SMBIOC_GETSSNKEY * Size copied out is SMBIOC_HASH_SZ. @@ -105,7 +84,10 @@ smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags) /* * Return the session key. */ - if (ddi_copyout(vcp->vc_ssn_key, (void *)arg, + if (vcp->vc_ssnkey == NULL || + vcp->vc_ssnkeylen < SMBIOC_HASH_SZ) + return (EINVAL); + if (ddi_copyout(vcp->vc_ssnkey, (void *)arg, SMBIOC_HASH_SZ, flags)) return (EFAULT); @@ -113,112 +95,18 @@ smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags) } /* - * Ioctl function for SMBIOC_REQUEST - */ -int -smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) -{ - struct smb_cred scred; - struct smb_share *ssp; - smbioc_rq_t *ioc = NULL; - struct smb_rq *rqp = NULL; - struct mbchain *mbp; - struct mdchain *mdp; - uint32_t rsz; - int err, mbseg; - - /* This ioctl requires a share. */ - if ((ssp = sdp->sd_share) == NULL) - return (ENOTCONN); - - smb_credinit(&scred, cr); - ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); - if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { - err = EFAULT; - goto out; - } - - /* See ddi_copyin, ddi_copyout */ - mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER; - - /* - * Lots of SMB commands could be safe, but - * these are the only ones used by libsmbfs. - */ - switch (ioc->ioc_cmd) { - /* These are OK */ - case SMB_COM_CLOSE: - case SMB_COM_FLUSH: - case SMB_COM_NT_CREATE_ANDX: - case SMB_COM_OPEN_PRINT_FILE: - case SMB_COM_CLOSE_PRINT_FILE: - break; - - default: - err = EPERM; - goto out; - } - - err = smb_rq_alloc(SSTOCP(ssp), ioc->ioc_cmd, &scred, &rqp); - if (err) - goto out; - - mbp = &rqp->sr_rq; - err = mb_put_mem(mbp, ioc->ioc_tbuf, ioc->ioc_tbufsz, mbseg); - - err = smb_rq_simple(rqp); - if (err == 0) { - /* - * This may have been an open, so save the - * generation ID of the share, which we - * check before trying read or write. - */ - sdp->sd_vcgenid = ssp->ss_vcgenid; - - /* - * Have reply data. to copyout. - * SMB header already parsed. - */ - mdp = &rqp->sr_rp; - rsz = msgdsize(mdp->md_top) - SMB_HDRLEN; - if (ioc->ioc_rbufsz < rsz) { - err = EOVERFLOW; - goto out; - } - ioc->ioc_rbufsz = rsz; - err = md_get_mem(mdp, ioc->ioc_rbuf, rsz, mbseg); - if (err) - goto out; - - } - - ioc->ioc_errclass = rqp->sr_errclass; - ioc->ioc_serror = rqp->sr_serror; - ioc->ioc_error = rqp->sr_error; - (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); - -out: - if (rqp != NULL) - smb_rq_done(rqp); /* free rqp */ - kmem_free(ioc, sizeof (*ioc)); - smb_credrele(&scred); - - return (err); - -} - -/* - * Ioctl function for SMBIOC_T2RQ + * Ioctl function for SMBIOC_XACTNP (transact named pipe) */ int -smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) +smb_usr_xnp(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) { struct smb_cred scred; struct smb_share *ssp; - smbioc_t2rq_t *ioc = NULL; + smbioc_xnp_t *ioc = NULL; struct smb_t2rq *t2p = NULL; struct mdchain *mdp; int err, len, mbseg; + uint16_t setup[2]; /* This ioctl requires a share. */ if ((ssp = sdp->sd_share) == NULL) @@ -234,91 +122,64 @@ smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) /* See ddi_copyin, ddi_copyout */ mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER; - if (ioc->ioc_setupcnt > SMBIOC_T2RQ_MAXSETUP) { - err = EINVAL; - goto out; - } - /* * Fill in the FID for libsmbfs transact named pipe. */ - if (ioc->ioc_setupcnt > 1 && ioc->ioc_setup[1] == 0xFFFF) { + if (ioc->ioc_fh == -1) { if (sdp->sd_vcgenid != ssp->ss_vcgenid) { err = ESTALE; goto out; } - ioc->ioc_setup[1] = (uint16_t)sdp->sd_smbfid; + ioc->ioc_fh = sdp->sd_smbfid; } + setup[0] = TRANS_TRANSACT_NAMED_PIPE; + setup[1] = (uint16_t)ioc->ioc_fh; + t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP); - err = smb_t2_init(t2p, SSTOCP(ssp), - ioc->ioc_setup, ioc->ioc_setupcnt, &scred); + err = smb_t2_init(t2p, SSTOCP(ssp), setup, 2, &scred); if (err) goto out; - t2p->t2_setupcount = ioc->ioc_setupcnt; - t2p->t2_setupdata = ioc->ioc_setup; - - /* This ioc member is a fixed-size array. */ - if (ioc->ioc_name[0]) { - /* Get the name length - carefully! */ - ioc->ioc_name[SMBIOC_T2RQ_MAXNAME-1] = '\0'; - t2p->t_name_len = strlen(ioc->ioc_name); - t2p->t_name = ioc->ioc_name; - } + t2p->t2_setupcount = 2; + t2p->t2_setupdata = setup; + + t2p->t_name = "\\PIPE\\"; + t2p->t_name_len = 6; + t2p->t2_maxscount = 0; - t2p->t2_maxpcount = ioc->ioc_rparamcnt; - t2p->t2_maxdcount = ioc->ioc_rdatacnt; + t2p->t2_maxpcount = 0; + t2p->t2_maxdcount = ioc->ioc_rdlen; - /* Transmit parameters */ - err = smb_cpdatain(&t2p->t2_tparam, - ioc->ioc_tparamcnt, ioc->ioc_tparam, mbseg); - if (err) - goto out; + /* Transmit parameters (none) */ /* Transmit data */ err = smb_cpdatain(&t2p->t2_tdata, - ioc->ioc_tdatacnt, ioc->ioc_tdata, mbseg); + ioc->ioc_tdlen, ioc->ioc_tdata, mbseg); if (err) goto out; err = smb_t2_request(t2p); - /* Copyout returned parameters. */ - mdp = &t2p->t2_rparam; - if (err == 0 && mdp->md_top != NULL) { - /* User's buffer large enough? */ - len = m_fixhdr(mdp->md_top); - if (len > ioc->ioc_rparamcnt) { - err = EMSGSIZE; - goto out; - } - ioc->ioc_rparamcnt = (ushort_t)len; - err = md_get_mem(mdp, ioc->ioc_rparam, len, mbseg); - if (err) - goto out; - } else - ioc->ioc_rparamcnt = 0; + /* No returned parameters. */ /* Copyout returned data. */ mdp = &t2p->t2_rdata; if (err == 0 && mdp->md_top != NULL) { /* User's buffer large enough? */ len = m_fixhdr(mdp->md_top); - if (len > ioc->ioc_rdatacnt) { + if (len > ioc->ioc_rdlen) { err = EMSGSIZE; goto out; } - ioc->ioc_rdatacnt = (ushort_t)len; + ioc->ioc_rdlen = (ushort_t)len; err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg); if (err) goto out; } else - ioc->ioc_rdatacnt = 0; + ioc->ioc_rdlen = 0; - ioc->ioc_errclass = t2p->t2_sr_errclass; - ioc->ioc_serror = t2p->t2_sr_serror; - ioc->ioc_error = t2p->t2_sr_error; - ioc->ioc_rpflags2 = t2p->t2_sr_rpflags2; + if (t2p->t2_sr_error == NT_STATUS_BUFFER_OVERFLOW) + ioc->ioc_more = 1; (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); @@ -825,24 +686,22 @@ smb_usr_drop_tree(smb_dev_t *sdp, int cmd) return (0); } - /* - * Ioctl function: SMBIOC_IOD_WORK - * - * Become the reader (IOD) thread, until either the connection is - * reset by the server, or until the connection is idle longer than - * some max time. (max idle time not yet implemented) + * Ioctl handler for all SMBIOC_IOD_... */ int -smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) +smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) { - struct smb_vc *vcp = NULL; + struct smb_vc *vcp; int err = 0; - /* Must have a valid session. */ + /* Must be the IOD. */ + if ((sdp->sd_flags & NSMBFL_IOD) == 0) + return (EINVAL); + /* Must have a VC and no share. */ if ((vcp = sdp->sd_vc) == NULL) return (EINVAL); - if (vcp->vc_flags & SMBV_GONE) + if (sdp->sd_share != NULL) return (EINVAL); /* @@ -859,39 +718,53 @@ smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) return (err); /* - * Copy the "work" state, etc. into the VC - * The MAC key is copied separately. + * Copy the "work" state, etc. into the VC, + * and back to the caller on the way out. + * Clear the "out only" part. */ if (ddi_copyin((void *)arg, &vcp->vc_work, sizeof (smbioc_ssn_work_t), flags)) { err = EFAULT; goto out; } - if (vcp->vc_u_maclen) { - vcp->vc_mackeylen = vcp->vc_u_maclen; - vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP); - if (ddi_copyin(vcp->vc_u_mackey.lp_ptr, vcp->vc_mackey, - vcp->vc_mackeylen, flags)) { - err = EFAULT; - goto out; - } - } + vcp->vc_work.wk_out_state = 0; - err = smb_iod_vc_work(vcp, cr); + switch (cmd) { - /* Caller wants state here. */ - vcp->vc_work.wk_out_state = vcp->vc_state; + case SMBIOC_IOD_CONNECT: + err = nsmb_iod_connect(vcp); + break; - (void) ddi_copyout(&vcp->vc_work, (void *)arg, - sizeof (smbioc_ssn_work_t), flags); + case SMBIOC_IOD_NEGOTIATE: + err = nsmb_iod_negotiate(vcp, cr); + break; -out: - if (vcp->vc_mackey) { - kmem_free(vcp->vc_mackey, vcp->vc_mackeylen); - vcp->vc_mackey = NULL; - vcp->vc_mackeylen = 0; + case SMBIOC_IOD_SSNSETUP: + err = nsmb_iod_ssnsetup(vcp, cr); + break; + + case SMBIOC_IOD_WORK: + err = smb_iod_vc_work(vcp, flags, cr); + break; + + case SMBIOC_IOD_IDLE: + err = smb_iod_vc_idle(vcp); + break; + + case SMBIOC_IOD_RCFAIL: + err = smb_iod_vc_rcfail(vcp); + break; + + default: + err = ENOTTY; + break; } +out: + vcp->vc_work.wk_out_state = vcp->vc_state; + (void) ddi_copyout(&vcp->vc_work, (void *)arg, + sizeof (smbioc_ssn_work_t), flags); + /* * The IOD thread is leaving the driver. Clear iod_thr, * and wake up anybody waiting for us to quit. @@ -904,67 +777,104 @@ out: return (err); } -/* - * Ioctl functions: SMBIOC_IOD_IDLE, SMBIOC_IOD_RCFAIL - * - * Wait for user-level requests to be enqueued on this session, - * and then return to the user-space helper, which will then - * initiate a reconnect, etc. - */ int -smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags) +smb_usr_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) { - struct smb_vc *vcp = NULL; - int err = 0; - - /* Must have a valid session. */ - if ((vcp = sdp->sd_vc) == NULL) - return (EINVAL); - if (vcp->vc_flags & SMBV_GONE) - return (EINVAL); + int err; /* - * Is there already an IOD for this VC? - * (Should never happen.) + * Serialize ioctl calls. The smb_usr_... functions + * don't expect concurrent calls on a given sdp. */ - SMB_VC_LOCK(vcp); - if (vcp->iod_thr == NULL) - vcp->iod_thr = curthread; - else - err = EEXIST; - SMB_VC_UNLOCK(vcp); - if (err) - return (err); - - /* nothing to copyin */ + mutex_enter(&sdp->sd_lock); + if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) { + mutex_exit(&sdp->sd_lock); + return (EBUSY); + } + sdp->sd_flags |= NSMBFL_IOCTL; + mutex_exit(&sdp->sd_lock); + err = 0; switch (cmd) { - case SMBIOC_IOD_IDLE: - err = smb_iod_vc_idle(vcp); + case SMBIOC_GETVERS: + (void) ddi_copyout(&nsmb_version, (void *)arg, + sizeof (nsmb_version), flags); + break; + + case SMBIOC_GETSSNKEY: + err = smb_usr_get_ssnkey(sdp, arg, flags); + break; + + case SMBIOC_DUP_DEV: + err = smb_usr_dup_dev(sdp, arg, flags); + break; + + case SMBIOC_XACTNP: + err = smb_usr_xnp(sdp, arg, flags, cr); + break; + + case SMBIOC_READ: + case SMBIOC_WRITE: + err = smb_usr_rw(sdp, cmd, arg, flags, cr); + break; + + case SMBIOC_NTCREATE: + err = smb_usr_ntcreate(sdp, arg, flags, cr); + break; + + case SMBIOC_PRINTJOB: + err = smb_usr_printjob(sdp, arg, flags, cr); break; + case SMBIOC_CLOSEFH: + err = smb_usr_closefh(sdp, cr); + break; + + case SMBIOC_SSN_CREATE: + case SMBIOC_SSN_FIND: + err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr); + break; + + case SMBIOC_SSN_KILL: + case SMBIOC_SSN_RELE: + err = smb_usr_drop_ssn(sdp, cmd); + break; + + case SMBIOC_TREE_CONNECT: + case SMBIOC_TREE_FIND: + err = smb_usr_get_tree(sdp, cmd, arg, flags, cr); + break; + + case SMBIOC_TREE_KILL: + case SMBIOC_TREE_RELE: + err = smb_usr_drop_tree(sdp, cmd); + break; + + case SMBIOC_IOD_CONNECT: + case SMBIOC_IOD_NEGOTIATE: + case SMBIOC_IOD_SSNSETUP: + case SMBIOC_IOD_WORK: + case SMBIOC_IOD_IDLE: case SMBIOC_IOD_RCFAIL: - err = smb_iod_vc_rcfail(vcp); + err = smb_usr_iod_ioctl(sdp, cmd, arg, flags, cr); + break; + + case SMBIOC_PK_ADD: + case SMBIOC_PK_DEL: + case SMBIOC_PK_CHK: + case SMBIOC_PK_DEL_OWNER: + case SMBIOC_PK_DEL_EVERYONE: + err = smb_pkey_ioctl(cmd, arg, flags, cr); break; default: err = ENOTTY; - goto out; + break; } - /* Both of these ioctls copy out the new state. */ - (void) ddi_copyout(&vcp->vc_state, (void *)arg, - sizeof (int), flags); - -out: - /* - * The IOD thread is leaving the driver. Clear iod_thr, - * and wake up anybody waiting for us to quit. - */ - SMB_VC_LOCK(vcp); - vcp->iod_thr = NULL; - cv_broadcast(&vcp->vc_statechg); - SMB_VC_UNLOCK(vcp); + mutex_enter(&sdp->sd_lock); + sdp->sd_flags &= ~NSMBFL_IOCTL; + mutex_exit(&sdp->sd_lock); return (err); } diff --git a/usr/src/uts/common/netsmb/smb_dev.h b/usr/src/uts/common/netsmb/smb_dev.h index d2e7690062..fb20b9c753 100644 --- a/usr/src/uts/common/netsmb/smb_dev.h +++ b/usr/src/uts/common/netsmb/smb_dev.h @@ -33,9 +33,10 @@ */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _NETSMB_DEV_H_ @@ -71,9 +72,9 @@ * associated structures change in ways that would * make them incompatible with an old driver. */ -#define NSMB_VERMAJ 1 -#define NSMB_VERMIN 4000 -#define NSMB_VERSION (NSMB_VERMAJ * 100000 + NSMB_VERMIN) +#define NSMB_VERMAJ 2 +#define NSMB_VERMIN 0x100 +#define NSMB_VERSION ((NSMB_VERMAJ << 16) | NSMB_VERMIN) /* * Some errno values we need to expose to the library. @@ -84,7 +85,7 @@ * EAUTH is used for CIFS authentication errors. */ #ifndef EBADRPC -#define EBADRPC 113 +#define EBADRPC 113 #endif #ifndef EAUTH #define EAUTH 114 @@ -111,9 +112,7 @@ #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 */ +#define SMBVOPT_ANONYMOUS 0x0020 /* using a NULL session */ #define SMBVOPT_SIGNING_ENABLED 0x0100 /* sign if server agrees */ #define SMBVOPT_SIGNING_REQUIRED 0x0200 /* signing required */ @@ -137,13 +136,18 @@ /* * network IO daemon states - * really connection states. */ enum smbiod_state { - SMBIOD_ST_IDLE = 0, /* no user requests enqueued yet */ - SMBIOD_ST_RECONNECT, /* a [re]connect attempt is in progress */ + SMBIOD_ST_UNINIT = 0, /* uninitialized */ + SMBIOD_ST_RECONNECT, /* a [re]connect attempt requested */ SMBIOD_ST_RCFAILED, /* a reconnect attempt has failed */ - SMBIOD_ST_VCACTIVE, /* session established */ + SMBIOD_ST_CONNECTED, /* Transport (TCP) connected */ + SMBIOD_ST_NEGOTIATED, /* Negotiated SMB/SMB2+ */ + SMBIOD_ST_AUTHCONT, /* Session setup continuing */ + SMBIOD_ST_AUTHFAIL, /* Session setup failed */ + SMBIOD_ST_AUTHOK, /* Session setup success */ + SMBIOD_ST_VCACTIVE, /* iod_work running */ + SMBIOD_ST_IDLE, /* no trees, will go DEAD */ SMBIOD_ST_DEAD /* connection gone, no IOD */ }; @@ -232,55 +236,19 @@ typedef struct smbioc_tcon { smbioc_oshare_t tc_sh; } smbioc_tcon_t; - -/* - * Negotiated protocol parameters - */ -struct smb_sopt { - int16_t sv_proto; /* protocol dialect */ - uchar_t sv_sm; /* security mode */ - int16_t sv_tz; /* offset in min relative to UTC */ - uint16_t sv_maxmux; /* max number of outstanding rq's */ - uint16_t sv_maxvcs; /* max number of VCs */ - uint16_t sv_rawmode; - uint32_t sv_maxtx; /* maximum transmit buf size */ - uint32_t sv_maxraw; /* maximum raw-buffer size */ - uint32_t sv_skey; /* session key */ - uint32_t sv_caps; /* capabilites SMB_CAP_ */ -}; -typedef struct smb_sopt smb_sopt_t; - -/* - * State carried in/out of the driver by the IOD thread. - * Inside the driver, these are members of the "VC" object. - */ -struct smb_iods { - int32_t is_tran_fd; /* transport FD */ - uint32_t is_vcflags; /* SMBV_... */ - uint8_t is_hflags; /* SMB header flags */ - uint16_t is_hflags2; /* SMB header flags2 */ - uint16_t is_smbuid; /* SMB header UID */ - uint16_t is_next_mid; /* SMB header MID */ - uint32_t is_txmax; /* max tx/rx packet size */ - uint32_t is_rwmax; /* max read/write data size */ - uint32_t is_rxmax; /* max readx data size */ - uint32_t is_wxmax; /* max writex data size */ - uint8_t is_ssn_key[SMBIOC_HASH_SZ]; /* session key */ - /* Signing state */ - uint32_t is_next_seq; /* my next sequence number */ - uint32_t is_u_maclen; /* MAC key length */ - lptr_t is_u_mackey; /* user-space ptr! */ -}; -typedef struct smb_iods smb_iods_t; - /* * This is the operational state information passed * in and out of the driver for SMBIOC_SSN_WORK */ struct smbioc_ssn_work { - smb_iods_t wk_iods; - smb_sopt_t wk_sopt; - int wk_out_state; + uint32_t wk_out_state; /* out-only */ + uint32_t wk_u_ssnkey_len; /* ssn key length */ + lptr_t wk_u_ssnkey_buf; /* user-space ptr! */ + uint32_t wk_u_auth_rlen; /* recv auth tok len */ + uint32_t wk_u_auth_wlen; /* send auth tok len */ + lptr_t wk_u_auth_rbuf; /* recv auth tok buf */ + lptr_t wk_u_auth_wbuf; /* send auth tok buf */ + uint8_t wk_ssn_key[SMBIOC_HASH_SZ]; /* session key */ }; typedef struct smbioc_ssn_work smbioc_ssn_work_t; @@ -288,57 +256,6 @@ typedef struct smbioc_ssn_work smbioc_ssn_work_t; * User-level SMB requests */ -/* - * SMBIOC_REQUEST (simple SMB request) - */ -typedef struct smbioc_rq { - uchar_t ioc_cmd; - uint8_t ioc_errclass; - uint16_t ioc_serror; - uint32_t ioc_error; - uint32_t ioc_tbufsz; /* transmit */ - uint32_t ioc_rbufsz; /* receive */ - lptr_t _ioc_tbuf; - lptr_t _ioc_rbuf; -} smbioc_rq_t; -#define ioc_tbuf _ioc_tbuf.lp_ptr -#define ioc_rbuf _ioc_rbuf.lp_ptr - - -#define SMBIOC_T2RQ_MAXSETUP 4 -#define SMBIOC_T2RQ_MAXNAME 128 - -typedef struct smbioc_t2rq { - uint16_t ioc_setup[SMBIOC_T2RQ_MAXSETUP]; - int32_t ioc_setupcnt; - char ioc_name[SMBIOC_T2RQ_MAXNAME]; - 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; - 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 - - -typedef struct smbioc_flags { - int32_t ioc_level; /* 0 - session, 1 - share */ - int32_t ioc_flags; - int32_t ioc_mask; -} smbioc_flags_t; - typedef struct smbioc_rw { int32_t ioc_fh; uint32_t ioc_cnt; @@ -348,6 +265,18 @@ typedef struct smbioc_rw { #define ioc_offset _ioc_offset._f #define ioc_base _ioc_base.lp_ptr +/* Transact on named pipe (send/recv) */ +typedef struct smbioc_xnp { + int32_t ioc_fh; + uint32_t ioc_tdlen; /* transmit len */ + uint32_t ioc_rdlen; /* recv maxlen */ + uint32_t ioc_more; /* more data to read */ + lptr_t _ioc_tdata; + lptr_t _ioc_rdata; +} smbioc_xnp_t; +#define ioc_tdata _ioc_tdata.lp_ptr +#define ioc_rdata _ioc_rdata.lp_ptr + typedef struct smbioc_ntcreate { uint32_t ioc_req_acc; uint32_t ioc_efattr; @@ -383,18 +312,16 @@ typedef struct smbioc_pk { * Keep GETVERS first and use it to verify * driver compatibility with the library. */ -#define SMBIOC_BASE ((('n' << 8) | 's') << 8) +#define SMBIOC_BASE ((('n' << 8) | 's') << 8) typedef enum nsmb_ioc { SMBIOC_GETVERS = SMBIOC_BASE, /* keep first */ - SMBIOC_FLAGS2, /* get hflags2 */ + SMBIOC_FLAGS2, /* obsolete */ SMBIOC_GETSSNKEY, /* get SMB session key */ SMBIOC_DUP_DEV, /* duplicate dev handle */ - SMBIOC_REQUEST, /* simple request */ - SMBIOC_T2RQ, /* trans2 request */ - SMBIOC_READ, /* read (pipe) */ SMBIOC_WRITE, /* write (pipe) */ + SMBIOC_XACTNP, /* "transact" (pipe) */ SMBIOC_NTCREATE, /* open or create */ SMBIOC_PRINTJOB, /* open print job */ SMBIOC_CLOSEFH, /* from ntcreate or printjob */ @@ -409,9 +336,12 @@ typedef enum nsmb_ioc { SMBIOC_TREE_KILL, SMBIOC_TREE_RELE, + SMBIOC_IOD_CONNECT, /* Setup connection */ + SMBIOC_IOD_NEGOTIATE, /* SMB/SMB2 negotiate */ + SMBIOC_IOD_SSNSETUP, /* SMB/SMB2 session setup */ SMBIOC_IOD_WORK, /* work on session requests */ SMBIOC_IOD_IDLE, /* wait for requests on this session */ - SMBIOC_IOD_RCFAIL, /* notify that reconnect failed */ + SMBIOC_IOD_RCFAIL, /* tell driver reconnect failed */ /* Password Keychain (PK) support. */ SMBIOC_PK_ADD, /* Add/Modify a password entry */ diff --git a/usr/src/uts/common/sys/t_kuser.h b/usr/src/uts/common/sys/t_kuser.h index 7aac9d94d2..b3c4da657c 100644 --- a/usr/src/uts/common/sys/t_kuser.h +++ b/usr/src/uts/common/sys/t_kuser.h @@ -98,6 +98,7 @@ extern int t_kconnect(TIUSER *, struct t_call *, struct t_call *); extern int t_kfree(TIUSER *, char *, int); extern int t_kgetstate(TIUSER *, int *); extern int t_kopen(struct file *, dev_t, int, TIUSER **, struct cred *); +extern int t_koptmgmt(TIUSER *, struct t_optmgmt *, struct t_optmgmt *); extern int t_krcvudata(TIUSER *, struct t_kunitdata *, int *, int *); extern int t_ksndudata(TIUSER *, struct t_kunitdata *, frtn_t *); extern int t_kspoll(TIUSER *, int, int, int *); diff --git a/usr/src/uts/intel/nsmb/ioc_check.ref b/usr/src/uts/intel/nsmb/ioc_check.ref index 9d670f24c3..e966bfdef5 100644 --- a/usr/src/uts/intel/nsmb/ioc_check.ref +++ b/usr/src/uts/intel/nsmb/ioc_check.ref @@ -17,65 +17,22 @@ #define TC_FLAGS 0x0 #define TC_OPT 0x4 #define TC_SH 0x8 -#define SV_PROTO 0x0 -#define SV_SM 0x2 -#define SV_TZ 0x4 -#define SV_MAXMUX 0x6 -#define SV_MAXVCS 0x8 -#define SV_RAWMODE 0xa -#define SV_MAXTX 0xc -#define SV_MAXRAW 0x10 -#define SV_SKEY 0x14 -#define SV_CAPS 0x18 -#define IS_TRAN_FD 0x0 -#define IS_VCFLAGS 0x4 -#define IS_HFLAGS 0x8 -#define IS_HFLAGS2 0xa -#define IS_SMBUID 0xc -#define IS_NEXT_MID 0xe -#define IS_TXMAX 0x10 -#define IS_RWMAX 0x14 -#define IS_RXMAX 0x18 -#define IS_WXMAX 0x1c -#define IS_SSN_KEY 0x20 -#define IS_SSN_KEY_INCR 0x1 -#define IS_NEXT_SEQ 0x30 -#define IS_U_MACLEN 0x34 -#define IS_U_MACKEY 0x38 -#define WK_IODS 0x0 -#define WK_SOPT 0x40 -#define WK_OUT_STATE 0x5c -#define SIZEOF_SMBIOC_RQ 0x20 -#define IOC_CMD 0x0 -#define IOC_RQ_ERRCLASS 0x1 -#define IOC_RQ_SERROR 0x2 -#define IOC_RQ_ERROR 0x4 -#define IOC_TBUFSZ 0x8 -#define IOC_RBUFSZ 0xc -#define _IOC_TBUF 0x10 -#define _IOC_RBUF 0x18 -#define SIZEOF_SMBIOC_T2RQ 0xc0 -#define IOC_SETUP 0x0 -#define IOC_SETUP_INCR 0x2 -#define IOC_SETUPCNT 0x8 -#define IOC_T2_NAME 0xc -#define IOC_T2_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 0x8 -#define IOC_FLAGS 0x4 +#define WK_OUT_STATE 0x0 +#define WK_U_SSNKEY_LEN 0x4 +#define WK_U_SSNKEY_BUF 0x8 +#define WK_U_AUTH_RLEN 0x10 +#define WK_U_AUTH_WLEN 0x14 +#define WK_U_AUTH_RBUF 0x18 +#define WK_U_AUTH_WBUF 0x20 +#define WK_SSN_KEY 0x28 +#define WK_SSN_KEY_INCR 0x1 +#define SIZEOF_SMBIOC_XNP 0x20 +#define IOC_FH 0x0 +#define IOC_TDLEN 0x4 +#define IOC_RDLEN 0x8 +#define IOC_MORE 0xc +#define _IOC_TDATA 0x10 +#define _IOC_RDATA 0x18 #define SIZEOF_SMBIOC_RW 0x18 #define IOC_FH 0x0 #define IOC_CNT 0x4 diff --git a/usr/src/uts/sparc/nsmb/ioc_check.ref b/usr/src/uts/sparc/nsmb/ioc_check.ref index 9d670f24c3..e966bfdef5 100644 --- a/usr/src/uts/sparc/nsmb/ioc_check.ref +++ b/usr/src/uts/sparc/nsmb/ioc_check.ref @@ -17,65 +17,22 @@ #define TC_FLAGS 0x0 #define TC_OPT 0x4 #define TC_SH 0x8 -#define SV_PROTO 0x0 -#define SV_SM 0x2 -#define SV_TZ 0x4 -#define SV_MAXMUX 0x6 -#define SV_MAXVCS 0x8 -#define SV_RAWMODE 0xa -#define SV_MAXTX 0xc -#define SV_MAXRAW 0x10 -#define SV_SKEY 0x14 -#define SV_CAPS 0x18 -#define IS_TRAN_FD 0x0 -#define IS_VCFLAGS 0x4 -#define IS_HFLAGS 0x8 -#define IS_HFLAGS2 0xa -#define IS_SMBUID 0xc -#define IS_NEXT_MID 0xe -#define IS_TXMAX 0x10 -#define IS_RWMAX 0x14 -#define IS_RXMAX 0x18 -#define IS_WXMAX 0x1c -#define IS_SSN_KEY 0x20 -#define IS_SSN_KEY_INCR 0x1 -#define IS_NEXT_SEQ 0x30 -#define IS_U_MACLEN 0x34 -#define IS_U_MACKEY 0x38 -#define WK_IODS 0x0 -#define WK_SOPT 0x40 -#define WK_OUT_STATE 0x5c -#define SIZEOF_SMBIOC_RQ 0x20 -#define IOC_CMD 0x0 -#define IOC_RQ_ERRCLASS 0x1 -#define IOC_RQ_SERROR 0x2 -#define IOC_RQ_ERROR 0x4 -#define IOC_TBUFSZ 0x8 -#define IOC_RBUFSZ 0xc -#define _IOC_TBUF 0x10 -#define _IOC_RBUF 0x18 -#define SIZEOF_SMBIOC_T2RQ 0xc0 -#define IOC_SETUP 0x0 -#define IOC_SETUP_INCR 0x2 -#define IOC_SETUPCNT 0x8 -#define IOC_T2_NAME 0xc -#define IOC_T2_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 0x8 -#define IOC_FLAGS 0x4 +#define WK_OUT_STATE 0x0 +#define WK_U_SSNKEY_LEN 0x4 +#define WK_U_SSNKEY_BUF 0x8 +#define WK_U_AUTH_RLEN 0x10 +#define WK_U_AUTH_WLEN 0x14 +#define WK_U_AUTH_RBUF 0x18 +#define WK_U_AUTH_WBUF 0x20 +#define WK_SSN_KEY 0x28 +#define WK_SSN_KEY_INCR 0x1 +#define SIZEOF_SMBIOC_XNP 0x20 +#define IOC_FH 0x0 +#define IOC_TDLEN 0x4 +#define IOC_RDLEN 0x8 +#define IOC_MORE 0xc +#define _IOC_TDATA 0x10 +#define _IOC_RDATA 0x18 #define SIZEOF_SMBIOC_RW 0x18 #define IOC_FH 0x0 #define IOC_CNT 0x4 -- cgit v1.2.3 From adee678425979226b2b55d1a0b39ce4c989382e9 Mon Sep 17 00:00:00 2001 From: Gordon Ross Date: Fri, 16 Mar 2018 14:17:36 -0400 Subject: 9735 Need to provide SMB 2.1 Client Reviewed by: Evan Layton Reviewed by: Matt Barden Reviewed by: Rick McNeal Reviewed by: Saso Kiselkov Reviewed by: Joyce McIntosh Approved by: Joshua M. Clulow --- usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d | 19 +- usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c | 14 +- usr/src/cmd/mdb/common/modules/nsmb/nsmb.c | 88 +- usr/src/lib/libshare/smbfs/libshare_smbfs.c | 39 +- usr/src/lib/libshare/smbfs/libshare_smbfs.h | 6 +- usr/src/lib/libsmbfs/Makefile.com | 3 +- usr/src/lib/libsmbfs/cflib.h | 4 + usr/src/lib/libsmbfs/netsmb/smb_lib.h | 5 + usr/src/lib/libsmbfs/netsmb/smbfs_api.h | 7 +- .../libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip | 2 +- .../smb/THIRDPARTYLICENSE.boris_popov.descrip | 2 +- .../libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip | 2 +- .../smb/THIRDPARTYLICENSE.microsoft.descrip | 2 +- usr/src/lib/libsmbfs/smb/connect.c | 75 +- usr/src/lib/libsmbfs/smb/ctx.c | 147 +- usr/src/lib/libsmbfs/smb/file.c | 3 - usr/src/lib/libsmbfs/smb/iod_wk.c | 17 +- usr/src/lib/libsmbfs/smb/mapfile-vers | 5 + usr/src/lib/libsmbfs/smb/print.c | 24 +- usr/src/lib/libsmbfs/smb/rc_scf.c | 231 ++ usr/src/lib/libsmbfs/smb/rcfile.c | 76 +- usr/src/lib/libsmbfs/smb/rcfile_priv.h | 28 +- usr/src/lib/smbclnt/libfknsmb/Makefile.com | 5 +- usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers | 21 +- usr/src/lib/smbclnt/libfksmbfs/Makefile.com | 4 +- usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c | 4 +- usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c | 4 +- usr/src/lib/smbsrv/libmlsvc/common/samlib.c | 8 +- usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c | 4 +- usr/src/man/man4/nsmbrc.4 | 35 +- usr/src/uts/common/Makefile.files | 4 +- .../fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple | 22 + .../smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip | 1 + .../smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov | 29 + .../netsmb/THIRDPARTYLICENSE.boris_popov.descrip | 1 + usr/src/uts/common/fs/smbclnt/netsmb/offsets.in | 20 +- usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c | 382 +++ usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h | 44 + usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c | 253 ++ usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c | 1325 ++++++++++ usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c | 139 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h | 130 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c | 18 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c | 1393 +++++++--- usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c | 286 ++- usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h | 38 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c | 40 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c | 383 +-- usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h | 96 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c | 236 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c | 215 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h | 4 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c | 104 +- usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c | 268 +- usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c | 54 +- usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c | 36 +- usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c | 47 +- usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h | 7 +- usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c | 2708 +++----------------- usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c | 926 +++++++ usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c | 896 +++++++ usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c | 294 ++- usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h | 184 +- usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c | 4 +- usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c | 310 ++- usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c | 186 +- usr/src/uts/common/fs/smbsrv/smb2_ioctl.c | 4 +- usr/src/uts/common/fs/smbsrv/smb_common_transact.c | 6 +- usr/src/uts/common/fs/smbsrv/smb_dfs.c | 4 +- .../uts/common/fs/smbsrv/smb_nt_transact_ioctl.c | 4 +- usr/src/uts/common/fs/smbsrv/smb_opipe.c | 4 +- usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c | 4 +- usr/src/uts/common/fs/smbsrv/smb_vss.c | 2 +- usr/src/uts/common/netsmb/mchain.h | 7 +- usr/src/uts/common/netsmb/smb.h | 62 +- usr/src/uts/common/netsmb/smb2.h | 465 ++++ usr/src/uts/common/netsmb/smb_dev.h | 26 +- usr/src/uts/common/smb/Makefile | 4 +- usr/src/uts/common/smb/ntaccess.h | 237 ++ usr/src/uts/common/smb/winioctl.h | 547 ++++ usr/src/uts/common/smbsrv/Makefile | 4 +- usr/src/uts/common/smbsrv/ntaccess.h | 237 -- usr/src/uts/common/smbsrv/smb.h | 4 +- usr/src/uts/common/smbsrv/winioctl.h | 547 ---- usr/src/uts/intel/nsmb/ioc_check.ref | 32 +- usr/src/uts/sparc/nsmb/ioc_check.ref | 32 +- 86 files changed, 9274 insertions(+), 4925 deletions(-) create mode 100644 usr/src/lib/libsmbfs/smb/rc_scf.c create mode 100644 usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple create mode 100644 usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip create mode 100644 usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov create mode 100644 usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip create mode 100644 usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c create mode 100644 usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h create mode 100644 usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c create mode 100644 usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c create mode 100644 usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c create mode 100644 usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c create mode 100644 usr/src/uts/common/netsmb/smb2.h create mode 100644 usr/src/uts/common/smb/ntaccess.h create mode 100644 usr/src/uts/common/smb/winioctl.h delete mode 100644 usr/src/uts/common/smbsrv/ntaccess.h delete mode 100644 usr/src/uts/common/smbsrv/winioctl.h (limited to 'usr/src/lib/libsmbfs/smb/ctx.c') diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d index 823115bf9c..b36fd13d6f 100644 --- a/usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d +++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d @@ -11,7 +11,7 @@ */ /* - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -19,21 +19,6 @@ * Usage: dtrace -s Watch-fksmbcl.d -p $PID */ -self int trace; - -/* - * Trace almost everything - */ -pid$target:fksmbcl::entry -{ - self->trace++; -} - -pid$target:fksmbcl::return -{ - self->trace--; -} - /* * If traced, print entry/return */ @@ -42,7 +27,6 @@ pid$target:libsmbfs.so.1::entry, pid$target:libfksmbfs.so.1::entry, pid$target:libfknsmb.so.1::entry, pid$target:libfakekernel.so.1::entry -/self->trace > 0/ { printf("\t0x%x", arg0); printf("\t0x%x", arg1); @@ -57,7 +41,6 @@ pid$target:libsmbfs.so.1::return, pid$target:libfksmbfs.so.1::return, pid$target:libfknsmb.so.1::return, pid$target:libfakekernel.so.1::entry -/self->trace > 0/ { printf("\t0x%x", arg1); } diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c index 65b0312558..8b1757ea62 100644 --- a/usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c +++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c @@ -10,7 +10,7 @@ */ /* - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -910,6 +911,17 @@ fakekernel_putlog(char *msg, size_t len, int flags) (void) fflush(stdout); } +/* + * Print nsmb debug messages via driver smb_debugmsg() + */ +void +smb_debugmsg(const char *func, char *msg) +{ + if (smb_debug < 2) + return; + printf("[kmod] %s: %s\n", func, msg); +} + /* * Enable libumem debugging */ diff --git a/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c b/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c index 8b3b76c38a..24e690f98a 100644 --- a/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c +++ b/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c @@ -20,9 +20,10 @@ */ /* - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ @@ -72,12 +73,13 @@ print_str(uintptr_t addr) */ typedef struct smb_co_walk_data { uintptr_t pp; - int level; /* SMBL_SM, SMBL_VC, SMBL_SHARE */ + 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; + smb_fh_t fh; } u; } smb_co_walk_data_t; @@ -114,6 +116,9 @@ smb_co_walk_init(mdb_walk_state_t *wsp, int level) case SMBL_SHARE: smbw->size = sizeof (smbw->u.ss); break; + case SMBL_FH: + smbw->size = sizeof (smbw->u.fh); + break; default: smbw->size = sizeof (smbw->u); break; @@ -179,6 +184,24 @@ smb_ss_walk_init(mdb_walk_state_t *wsp) return (smb_co_walk_init(wsp, SMBL_SHARE)); } +/* + * Walk the file hande list below some share. + */ +int +smb_fh_walk_init(mdb_walk_state_t *wsp) +{ + + /* + * Initial walk_addr is address of parent (share) + */ + if (wsp->walk_addr == 0) { + mdb_warn("::walk smb_fh does not support global walks\n"); + return (WALK_ERR); + } + + return (smb_co_walk_init(wsp, SMBL_FH)); +} + /* * Common walk_step for walking structs inherited * from smb_connobj_t (smb_vc_t, smb_share_t) @@ -220,6 +243,30 @@ typedef struct smb_co_cbdata { mdb_ctf_id_t ctf_id; } smb_co_cbdata_t; +/* + * Call-back function for walking a file handle list. + */ +/* ARGSUSED */ +int +smb_fh_cb(uintptr_t addr, const void *data, void *arg) +{ + const smb_fh_t *fhp = data; + // smb_co_cbdata_t *cbd = arg; + + mdb_inc_indent(2); + mdb_printf(" %-p", addr); + if (fhp->fh_fid2.fid_volatile != 0) { + mdb_printf("\t0x%llx\n", + (long long) fhp->fh_fid2.fid_volatile); + } else { + mdb_printf("\t0x%x\n", fhp->fh_fid1); + } + + mdb_dec_indent(2); + + return (WALK_NEXT); +} + /* * Call-back function for walking a share list. */ @@ -228,12 +275,20 @@ smb_ss_cb(uintptr_t addr, const void *data, void *arg) { const smb_share_t *ssp = data; smb_co_cbdata_t *cbd = arg; + uint32_t tid; - mdb_printf(" %-p\t%s\n", addr, ssp->ss_name); + tid = ssp->ss2_tree_id; + if (tid == 0) + tid = ssp->ss_tid; - if (cbd->flags & OPT_VERBOSE) { + mdb_printf(" %-p\t0x%x\t%s\n", addr, tid, ssp->ss_name); + + if (cbd->flags & OPT_RECURSE) { mdb_inc_indent(2); - /* Anything wanted here? */ + if (mdb_pwalk("nsmb_fh", smb_fh_cb, cbd, addr) < 0) { + mdb_warn("failed to walk 'nsmb_fh'"); + /* Don't: return (WALK_ERR); */ + } mdb_dec_indent(2); } @@ -414,6 +469,7 @@ rqlist_walk_step(mdb_walk_state_t *wsp) typedef struct rqlist_cbdata { int printed_header; + int vcflags; uintptr_t uid; /* optional filtering by UID */ } rqlist_cbdata_t; @@ -429,8 +485,13 @@ rqlist_cb(uintptr_t addr, const void *data, void *arg) } mdb_printf(" %-p", addr); /* smb_rq_t */ - mdb_printf(" x%04x", rq->sr_mid); - mdb_printf(" x%02x", rq->sr_cmd); + if ((cbd->vcflags & SMBV_SMB2) != 0) { + mdb_printf(" x%04llx", (long long)rq->sr2_messageid); + mdb_printf(" x%02x", rq->sr2_command); + } else { + 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"); @@ -443,9 +504,20 @@ int rqlist_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { rqlist_cbdata_t cbd; + smb_vc_t *vcp; + size_t vcsz; memset(&cbd, 0, sizeof (cbd)); + /* Need the VC again to get */ + 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); + } + cbd.vcflags = vcp->vc_flags; + /* * Initial walk_addr is address of parent (VC) */ @@ -606,6 +678,8 @@ static const mdb_walker_t walkers[] = { 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_fh", "walk nsmb share list for some VC", + smb_fh_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", diff --git a/usr/src/lib/libshare/smbfs/libshare_smbfs.c b/usr/src/lib/libshare/smbfs/libshare_smbfs.c index b1f19f917d..7c9b4fa58a 100644 --- a/usr/src/lib/libshare/smbfs/libshare_smbfs.c +++ b/usr/src/lib/libshare/smbfs/libshare_smbfs.c @@ -22,6 +22,8 @@ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -70,6 +72,7 @@ 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 *); +static int protocol_validator(int, char *, char *); static int signing_validator(int, char *, char *); int propset_changed = 0; @@ -182,6 +185,12 @@ struct smbclnt_proto_option_defs smbclnt_proto_options[] = { { "signing", NULL, PROTO_OPT_SIGNING, 0, 0, MAX_VALUE_BUFLEN, signing_validator}, + { "min_protocol", NULL, PROTO_OPT_MIN_PROTOCOL, + 0, 0, MAX_VALUE_BUFLEN, + protocol_validator}, + { "max_protocol", NULL, PROTO_OPT_MAX_PROTOCOL, + 0, 0, MAX_VALUE_BUFLEN, + protocol_validator}, {NULL} }; @@ -270,18 +279,30 @@ ip_address_validator(int index, char *section, char *value) static int minauth_validator(int index, char *section, char *value) { + int ival; + 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 + ival = smb_cf_minauth_from_str(value); + if (ival == -1) return (SA_BAD_VALUE); + + return (SA_OK); +} + +/*ARGSUSED*/ +static int +protocol_validator(int index, char *section, char *value) +{ + int ival; + + if (value == NULL) + return (SA_BAD_VALUE); + ival = smb_cf_version_from_str(value); + if (ival == -1) + return (SA_BAD_VALUE); + + return (SA_OK); } /*ARGSUSED*/ diff --git a/usr/src/lib/libshare/smbfs/libshare_smbfs.h b/usr/src/lib/libshare/smbfs/libshare_smbfs.h index 8f95e7de68..d77fef814a 100644 --- a/usr/src/lib/libshare/smbfs/libshare_smbfs.h +++ b/usr/src/lib/libshare/smbfs/libshare_smbfs.h @@ -22,6 +22,8 @@ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -59,8 +61,10 @@ extern struct smbclnt_proto_option_defs smbclnt_proto_options[]; #define PROTO_OPT_DOMAIN 9 #define PROTO_OPT_WORKGROUP 10 #define PROTO_OPT_SIGNING 11 +#define PROTO_OPT_MIN_PROTOCOL 12 +#define PROTO_OPT_MAX_PROTOCOL 13 -#define SMBC_OPT_MAX PROTO_OPT_SIGNING +#define SMBC_OPT_MAX PROTO_OPT_MAX_PROTOCOL /* * Flags values diff --git a/usr/src/lib/libsmbfs/Makefile.com b/usr/src/lib/libsmbfs/Makefile.com index e69b199ad0..be5ad05c42 100644 --- a/usr/src/lib/libsmbfs/Makefile.com +++ b/usr/src/lib/libsmbfs/Makefile.com @@ -64,6 +64,7 @@ OBJ_LIB=\ ntlmssp.o \ print.o \ rcfile.o \ + rc_scf.o \ spnego.o \ spnegoparse.o \ ssp.o \ @@ -89,7 +90,7 @@ $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) CSTD= $(CSTD_GNU99) -LDLIBS += -lsocket -lnsl -lc -lmd -lpkcs11 -lkrb5 -lsec -lidmap +LDLIBS += -lsocket -lnsl -lc -lmd -lpkcs11 -lkrb5 -lsec -lidmap -lscf -luuid # normal warnings... CFLAGS += $(CCVERBOSE) diff --git a/usr/src/lib/libsmbfs/cflib.h b/usr/src/lib/libsmbfs/cflib.h index 0e8d6b57ee..85db96fcfd 100644 --- a/usr/src/lib/libsmbfs/cflib.h +++ b/usr/src/lib/libsmbfs/cflib.h @@ -35,6 +35,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _CFLIB_H_ @@ -85,6 +87,8 @@ int cf_getopt(int, char * const *, const char *); void cf_opt_lock(void); void cf_opt_unlock(void); +char *cf_get_client_uuid(void); + 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 *); diff --git a/usr/src/lib/libsmbfs/netsmb/smb_lib.h b/usr/src/lib/libsmbfs/netsmb/smb_lib.h index c9aa810c91..ae71332e97 100644 --- a/usr/src/lib/libsmbfs/netsmb/smb_lib.h +++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.h @@ -126,6 +126,8 @@ struct smb_ctx { */ #define ct_ssn ct_iod_ssn.iod_ossn #define ct_vopt ct_iod_ssn.iod_ossn.ssn_vopt +#define ct_minver ct_iod_ssn.iod_ossn.ssn_minver +#define ct_maxver ct_iod_ssn.iod_ossn.ssn_maxver #define ct_owner ct_iod_ssn.iod_ossn.ssn_owner #define ct_srvaddr ct_iod_ssn.iod_ossn.ssn_srvaddr #define ct_domain ct_iod_ssn.iod_ossn.ssn_domain @@ -194,6 +196,9 @@ int smb_iod_work(struct smb_ctx *); int smb_open_rcfile(char *); void smb_close_rcfile(void); +int smb_cf_minauth_from_str(char *); +int smb_cf_version_from_str(char *); + void smb_simplecrypt(char *dst, const char *src); int smb_simpledecrypt(char *dst, const char *src); diff --git a/usr/src/lib/libsmbfs/netsmb/smbfs_api.h b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h index b1f4b1e198..7b87b571ff 100644 --- a/usr/src/lib/libsmbfs/netsmb/smbfs_api.h +++ b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h @@ -22,7 +22,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _NETSMB_SMBFS_API_H @@ -48,7 +49,7 @@ extern "C" { * EAUTH is used for CIFS authentication errors. */ #ifndef EBADRPC -#define EBADRPC 113 +#define EBADRPC 113 #endif #ifndef EAUTH #define EAUTH 114 @@ -122,6 +123,8 @@ int smb_ctx_setauthflags(struct smb_ctx *, int); int smb_ctx_setcharset(struct smb_ctx *, const char *); int smb_ctx_setfullserver(struct smb_ctx *, const char *); int smb_ctx_setsigning(struct smb_ctx *, int ena, int req); +int smb_ctx_setminver(struct smb_ctx *, int ver); +int smb_ctx_setmaxver(struct smb_ctx *, int ver); int smb_ctx_setnbflags(struct smb_ctx *, int ena, int bcast); int smb_ctx_setscope(struct smb_ctx *, const char *); diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip index aa3d6ad7e1..35fdfd0404 100644 --- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip @@ -1 +1 @@ -PORTIONS OF LIBSMBFS IN CIFS CLIENT +PORTIONS OF LIBSMBFS IN SMB CLIENT diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip index d7cc9ebbd7..35fdfd0404 100644 --- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip @@ -1 +1 @@ -CIFS CLIENT SOFTWARE +PORTIONS OF LIBSMBFS IN SMB CLIENT diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip index aa3d6ad7e1..35fdfd0404 100644 --- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip @@ -1 +1 @@ -PORTIONS OF LIBSMBFS IN CIFS CLIENT +PORTIONS OF LIBSMBFS IN SMB CLIENT diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip index aa3d6ad7e1..35fdfd0404 100644 --- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip @@ -1 +1 @@ -PORTIONS OF LIBSMBFS IN CIFS CLIENT +PORTIONS OF LIBSMBFS IN SMB CLIENT diff --git a/usr/src/lib/libsmbfs/smb/connect.c b/usr/src/lib/libsmbfs/smb/connect.c index a45fa90958..c231fe0e8a 100644 --- a/usr/src/lib/libsmbfs/smb/connect.c +++ b/usr/src/lib/libsmbfs/smb/connect.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,8 @@ #include #include +#include + #include "charsets.h" #include "private.h" #include "smb_crypt.h" @@ -115,12 +118,18 @@ smb_iod_state_name(enum smbiod_state st) /* * Make a new connection, or reconnect. + * + * This is called first from the door service thread in smbiod + * (so that can report success or failure to the door client) + * and thereafter it's called when we need to reconnect after a + * network outage (or whatever might cause connection loss). */ int smb_iod_connect(smb_ctx_t *ctx) { smbioc_ossn_t *ossn = &ctx->ct_ssn; smbioc_ssn_work_t *work = &ctx->ct_work; + char *uuid_str; int err; struct mbdata blob; char *nego_buf = NULL; @@ -150,6 +159,20 @@ smb_iod_connect(smb_ctx_t *ctx) } } + /* + * Get local machine uuid. + */ + uuid_str = cf_get_client_uuid(); + if (uuid_str == NULL) { + err = EINVAL; + smb_error(dgettext(TEXT_DOMAIN, + "can't get local UUID"), err); + return (err); + } + (void) uuid_parse(uuid_str, ctx->ct_work.wk_cl_guid); + free(uuid_str); + uuid_str = NULL; + /* * We're called with each IP address * already copied into ct_srvaddr. @@ -227,6 +250,13 @@ out: return (err); } +/* + * smb_ssnsetup_spnego + * + * This does an SMB session setup sequence using SPNEGO. + * The state changes seen during this sequence are there + * just to help track what's going on. + */ int smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb) { @@ -249,25 +279,39 @@ smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb) } for (;;) { err = smb__ssnsetup(ctx, &send_mb, &recv_mb); - if (err != 0 && err != EINPROGRESS) { - DPRINT("smb__ssnsetup, err=%d", err); - goto out; - } - DPRINT("smb__ssnsetup, new state=%s", + DPRINT("smb__ssnsetup rc=%d, new state=%s", err, smb_iod_state_name(work->wk_out_state)); - if (work->wk_out_state == SMBIOD_ST_AUTHOK) { - err = 0; + + if (err == 0) { + /* + * Session setup complete w/ success. + * Should have state AUTHOK + */ + if (work->wk_out_state != SMBIOD_ST_AUTHOK) { + DPRINT("Wrong state (expected AUTHOK)"); + } break; } - if (work->wk_out_state == SMBIOD_ST_AUTHFAIL) { - err = EAUTH; + + if (err != EINPROGRESS) { + /* + * Session setup complete w/ failure. + * Should have state AUTHFAIL + */ + if (work->wk_out_state != SMBIOD_ST_AUTHFAIL) { + DPRINT("Wrong state (expected AUTHFAIL)"); + } goto out; } + + /* + * err == EINPROGRESS + * Session setup continuing. + * Should have state AUTHCONT + */ if (work->wk_out_state != SMBIOD_ST_AUTHCONT) { - err = EPROTO; - goto out; + DPRINT("Wrong state (expected AUTHCONT)"); } - /* state == SMBIOD_ST_AUTHCONT */ /* middle calls get both in, out */ err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb); @@ -277,7 +321,12 @@ smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb) } } - /* NULL output indicates last call. */ + /* + * Only get here via break in the err==0 case above, + * so we're finalizing a successful session setup. + * + * NULL output token here indicates the final call. + */ (void) ssp_ctx_next_token(ctx, &recv_mb, NULL); /* diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c index 43ca516f81..3aa67fd5f5 100644 --- a/usr/src/lib/libsmbfs/smb/ctx.c +++ b/usr/src/lib/libsmbfs/smb/ctx.c @@ -165,6 +165,8 @@ dump_iod_ssn(smb_iod_ssn_t *is) ssn->ssn_domain, ssn->ssn_user); printf(" ct_vopt=0x%x, ct_owner=%d\n", ssn->ssn_vopt, ssn->ssn_owner); + printf(" ct_minver=0x%x, ct_maxver=0x%x\n", + ssn->ssn_minver, ssn->ssn_maxver); printf(" ct_authflags=0x%x\n", is->iod_authflags); printf(" ct_nthash:"); @@ -259,6 +261,7 @@ smb_ctx_init(struct smb_ctx *ctx) ctx->ct_owner = SMBM_ANY_OWNER; ctx->ct_authflags = SMB_AT_DEFAULT; ctx->ct_minauth = SMB_AT_MINAUTH; + ctx->ct_maxver = SMB2_DIALECT_MAX; /* * Default domain, user, ... @@ -856,6 +859,37 @@ smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require) return (0); } +/* + * Handle .nsmbrc "minver" option. + * Must be <= maxver + */ +int +smb_ctx_setminver(struct smb_ctx *ctx, int ver) +{ + if (ver < 0 || ver > ctx->ct_maxver) + return (EINVAL); + ctx->ct_minver = (uint16_t)ver; + return (0); +} + +/* + * Handle .nsmbrc "maxver" option. + * Must be >= minver + * + * Any "too high" value is just clamped, so the caller + * doesn't need to know what's the highest we support. + */ +int +smb_ctx_setmaxver(struct smb_ctx *ctx, int ver) +{ + if (ver < 1 || ver < ctx->ct_minver) + return (EINVAL); + if (ver > SMB2_DIALECT_MAX) + ver = SMB2_DIALECT_MAX; + ctx->ct_maxver = (uint16_t)ver; + return (0); +} + static int smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) { @@ -1120,8 +1154,12 @@ smb_ctx_resolve(struct smb_ctx *ctx) * If we don't have a p/w yet, * try the keychain. */ - if (ctx->ct_password[0] == '\0') - (void) smb_get_keychain(ctx); + if (ctx->ct_password[0] == '\0' && + smb_get_keychain(ctx) == 0) { + strlcpy(ctx->ct_password, "$HASH", + sizeof (ctx->ct_password)); + } + /* * Mask out disallowed auth types. */ @@ -1362,6 +1400,35 @@ minauth_table[] = { { NULL } }; +int +smb_cf_minauth_from_str(char *str) +{ + struct nv *nvp; + + for (nvp = minauth_table; nvp->name; nvp++) + if (strcmp(nvp->name, str) == 0) + return (nvp->value); + return (-1); +} + + +static struct nv +smbver_table[] = { + { "2.1", SMB2_DIALECT_0210 }, + { "1", 1 }, + { NULL, 0 } +}; + +int +smb_cf_version_from_str(char *str) +{ + struct nv *nvp; + + for (nvp = smbver_table; nvp->name; nvp++) + if (strcmp(nvp->name, str) == 0) + return (nvp->value); + return (-1); +} /* * level values: @@ -1374,7 +1441,9 @@ static int smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) { char *p; + int ival; int error; + int minver, maxver; #ifdef KICONV_SUPPORT if (level > 0) { @@ -1392,19 +1461,79 @@ smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) if (level <= 1) { /* Section is: [default] or [server] */ + /* + * Handle min_protocol, max_protocol + * (SMB protocol versions) + */ + minver = -1; + rc_getstringptr(smb_rc, sname, "min_protocol", &p); + if (p != NULL) { + minver = smb_cf_version_from_str(p); + if (minver == -1) { + smb_error(dgettext(TEXT_DOMAIN, +"invalid min_protocol value \"%s\" specified in the section %s"), + 0, p, sname); + } + } + maxver = -1; + rc_getstringptr(smb_rc, sname, "max_protocol", &p); + if (p != NULL) { + maxver = smb_cf_version_from_str(p); + if (maxver == -1) { + smb_error(dgettext(TEXT_DOMAIN, +"invalid max_protocol value \"%s\" specified in the section %s"), + 0, p, sname); + } + } + + /* + * If setting both min/max protocol, + * validate against each other + */ + if (minver != -1 && maxver != -1) { + if (minver > maxver) { + smb_error(dgettext(TEXT_DOMAIN, +"invalid min/max protocol combination in the section %s"), + 0, sname); + } else { + ctx->ct_minver = minver; + ctx->ct_maxver = maxver; + } + } + + /* + * Setting just min or max, validate against + * current settings + */ + if (minver != -1) { + if (minver > ctx->ct_maxver) { + smb_error(dgettext(TEXT_DOMAIN, +"invalid min/max protocol combination in the section %s"), + 0, sname); + } else { + ctx->ct_minver = minver; + } + } + if (maxver != -1) { + if (maxver < ctx->ct_minver) { + smb_error(dgettext(TEXT_DOMAIN, +"invalid min/max protocol combination in the section %s"), + 0, sname); + } else { + ctx->ct_maxver = maxver; + } + } + rc_getstringptr(smb_rc, sname, "minauth", &p); if (p) { /* * "minauth" was set in this section; override * the current minimum authentication setting. */ - struct nv *nvp; - for (nvp = minauth_table; nvp->name; nvp++) - if (strcmp(p, nvp->name) == 0) - break; - if (nvp->name) - ctx->ct_minauth = nvp->value; - else { + ival = smb_cf_minauth_from_str(p); + if (ival != -1) { + ctx->ct_minauth = ival; + } else { /* * Unknown minimum authentication level. */ diff --git a/usr/src/lib/libsmbfs/smb/file.c b/usr/src/lib/libsmbfs/smb/file.c index 1c4e2dc236..3d2a431142 100644 --- a/usr/src/lib/libsmbfs/smb/file.c +++ b/usr/src/lib/libsmbfs/smb/file.c @@ -217,7 +217,6 @@ smb_fh_read(int fd, off64_t offset, size_t count, struct smbioc_rw rwrq; bzero(&rwrq, sizeof (rwrq)); - rwrq.ioc_fh = -1; /* tell driver to supply this */ rwrq.ioc_base = dst; rwrq.ioc_cnt = count; rwrq.ioc_offset = offset; @@ -234,7 +233,6 @@ smb_fh_write(int fd, off64_t offset, size_t count, struct smbioc_rw rwrq; bzero(&rwrq, sizeof (rwrq)); - rwrq.ioc_fh = -1; /* tell driver to supply this */ rwrq.ioc_base = (char *)src; rwrq.ioc_cnt = count; rwrq.ioc_offset = offset; @@ -262,7 +260,6 @@ smb_fh_xactnp(int fd, /* this gets copyin & copyout */ bzero(&ioc, sizeof (ioc)); - ioc.ioc_fh = -1; /* tell driver to supply this */ ioc.ioc_tdlen = tdlen; ioc.ioc_rdlen = *rdlen; ioc.ioc_more = 0; diff --git a/usr/src/lib/libsmbfs/smb/iod_wk.c b/usr/src/lib/libsmbfs/smb/iod_wk.c index b19f1f3f0f..38e9d5e0de 100644 --- a/usr/src/lib/libsmbfs/smb/iod_wk.c +++ b/usr/src/lib/libsmbfs/smb/iod_wk.c @@ -104,6 +104,7 @@ smb_iod_work(smb_ctx_t *ctx) DPRINT("ioc_idle: err %d", err); goto out; } + DPRINT("Ret. from _ioc_idle"); continue; case SMBIOD_ST_RECONNECT: @@ -119,16 +120,14 @@ smb_iod_work(smb_ctx_t *ctx) * will need to run smbutil to get * a new thread with new auth info. */ - if (err == EAUTH) + if (err == EAUTH) { + DPRINT("iod_connect: EAUTH (give up)"); goto out; - continue; - - case SMBIOD_ST_RCFAILED: + } /* - * Reconnect failed. Kill off any - * requests waiting in the driver, - * then get ready to try again. - * Next state is normally IDLE. + * Reconnect failed. Notify any requests + * that we're not connected, and delay. + * Next state will be IDLE or RECONNECT. */ DPRINT("Call _iod_rcfail..."); if (nsmb_ioctl(ctx->ct_dev_fd, @@ -152,9 +151,11 @@ smb_iod_work(smb_ctx_t *ctx) DPRINT("iod_work: err %d", err); goto out; } + DPRINT("Ret. from _ioc_work"); continue; case SMBIOD_ST_DEAD: + DPRINT("got state=DEAD"); err = 0; goto out; diff --git a/usr/src/lib/libsmbfs/smb/mapfile-vers b/usr/src/lib/libsmbfs/smb/mapfile-vers index 73ab2504f5..a94b3bc6e1 100644 --- a/usr/src/lib/libsmbfs/smb/mapfile-vers +++ b/usr/src/lib/libsmbfs/smb/mapfile-vers @@ -68,6 +68,9 @@ SYMBOL_VERSION SUNWprivate { nsmb_close { FLAGS = NODIRECT }; nsmb_ioctl { FLAGS = NODIRECT }; + smb_cf_minauth_from_str; + smb_cf_version_from_str; + smb_close_rcfile; smb_ctx_alloc; @@ -91,6 +94,8 @@ SYMBOL_VERSION SUNWprivate { smb_ctx_setauthflags; smb_ctx_setdomain; smb_ctx_setfullserver; + smb_ctx_setminver; + smb_ctx_setmaxver; smb_ctx_setnbflags; smb_ctx_setpassword; smb_ctx_setpwhash; diff --git a/usr/src/lib/libsmbfs/smb/print.c b/usr/src/lib/libsmbfs/smb/print.c index 80fcab7d10..698dd8359f 100644 --- a/usr/src/lib/libsmbfs/smb/print.c +++ b/usr/src/lib/libsmbfs/smb/print.c @@ -33,7 +33,7 @@ */ /* - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -57,12 +57,24 @@ #include "private.h" +/* + * Replacing invalid characters in print job titles: + * + * The spec. is unclear about what characters are allowed in a + * print job title (used with NtCreate) so out of caution this + * makes sure the title contains none of the characters that + * are known to be illegal in a file name component. + */ +static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS; + int smb_open_printer(struct smb_ctx *ctx, const char *title, int setuplen, int mode) { smbioc_printjob_t ioc; - int err, tlen, new_fd; + char *p; + int err, tlen; + int new_fd = -1; int32_t from_fd; tlen = strlen(title); @@ -91,6 +103,14 @@ smb_open_printer(struct smb_ctx *ctx, const char *title, ioc.ioc_prmode = mode; strlcpy(ioc.ioc_title, title, SMBIOC_MAX_NAME); + /* + * The title is used in NtCreate so sanitize by + * replacing any illegal chars with spaces. + */ + for (p = ioc.ioc_title; *p != '\0'; p++) + if (strchr(invalid_chars, *p) != NULL) + *p = ' '; + if (nsmb_ioctl(new_fd, SMBIOC_PRINTJOB, &ioc) == -1) { err = errno; goto errout; diff --git a/usr/src/lib/libsmbfs/smb/rc_scf.c b/usr/src/lib/libsmbfs/smb/rc_scf.c new file mode 100644 index 0000000000..477982c0c8 --- /dev/null +++ b/usr/src/lib/libsmbfs/smb/rc_scf.c @@ -0,0 +1,231 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + +/* + * Support functions for getting things libsmbfs needs + * from the SMF configuration (using libscf). + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "rcfile_priv.h" + +#define IDMAP_SERVICE_FMRI "svc:/system/idmap" +#define IDMAP_PG_NAME "config" +#define MACHINE_UUID "machine_uuid" + +#define SMBC_DEFAULT_INSTANCE_FMRI "svc:/network/smb/client:default" + +scf_handle_t *_scf_handle_create_and_bind(scf_version_t ver); + +/* + * Get the "machine_uuid" from idmap, as a string (allocated) + */ +char * +cf_get_client_uuid(void) +{ + char val_buf[64]; + char *ret = NULL; + + scf_handle_t *h = NULL; + scf_service_t *svc = NULL; + scf_propertygroup_t *pg = NULL; + scf_property_t *prop = NULL; + scf_value_t *val = NULL; + + if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL) + goto out; + + if ((svc = scf_service_create(h)) == NULL || + (pg = scf_pg_create(h)) == NULL || + (prop = scf_property_create(h)) == NULL || + (val = scf_value_create(h)) == NULL) + goto out; + + if (scf_handle_decode_fmri(h, IDMAP_SERVICE_FMRI, + NULL, svc, NULL, NULL, NULL, 0) == -1) + goto out; + + + if (scf_service_get_pg(svc, IDMAP_PG_NAME, pg) != 0) + goto out; + if (scf_pg_get_property(pg, MACHINE_UUID, prop) != 0) + goto out; + if (scf_property_get_value(prop, val) != 0) + goto out; + if (scf_value_get_as_string(val, val_buf, sizeof (val_buf)) < 0) + goto out; + + ret = strdup(val_buf); + +out: + scf_value_destroy(val); + scf_property_destroy(prop); + scf_pg_destroy(pg); + scf_service_destroy(svc); + + if (h != NULL) + scf_handle_destroy(h); + + return (ret); +} + +/* + * Get the output of "sharectl get smbfs" into a file, without an + * actual fork/exec of sharectl. + * + * Each section of the smbfs settings are represented as an SMF + * property group with an "S-" prefix and a UUID, and the section + * name itself a property which can have a more flexible name than + * a property group name can have. + */ +int +rc_scf_get_sharectl(FILE *fp) +{ + char sect_name[256]; + char prop_name[256]; + char val_buf[1024]; + + scf_handle_t *h = NULL; + scf_service_t *svc = NULL; + scf_instance_t *inst = NULL; + scf_propertygroup_t *pg = NULL; + scf_property_t *prop = NULL; + scf_value_t *val = NULL; + scf_iter_t *pgiter = NULL; + scf_iter_t *propiter = NULL; + scf_iter_t *valiter = NULL; + int ret = -1; + + if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL) + goto out; + + if ((svc = scf_service_create(h)) == NULL || + (inst = scf_instance_create(h)) == NULL || + (pgiter = scf_iter_create(h)) == NULL || + (propiter = scf_iter_create(h)) == NULL || + (valiter = scf_iter_create(h)) == NULL || + (pg = scf_pg_create(h)) == NULL || + (prop = scf_property_create(h)) == NULL || + (val = scf_value_create(h)) == NULL) + goto out; + + if (scf_handle_decode_fmri(h, SMBC_DEFAULT_INSTANCE_FMRI, + NULL, svc, inst, NULL, NULL, 0) == -1) + goto out; + + if (scf_iter_instance_pgs_composed(pgiter, inst, NULL) == -1) + goto out; + while ((ret = scf_iter_next_pg(pgiter, pg)) == 1) { + /* + * Using prop_name array for pg name temporarily. + * Skip any property groups names other than "S-*". + */ + if (scf_pg_get_name(pg, prop_name, sizeof (prop_name)) < 0) + continue; + if (strncmp(prop_name, "S-", 2) != 0) + continue; + + /* + * Get the "section" name, which is a property of + * this property group. + */ + if (scf_pg_get_property(pg, "section", prop) != 0) + continue; + if (scf_property_get_value(prop, val) != 0) + continue; + if (scf_value_get_as_string(val, sect_name, + sizeof (sect_name)) < 0) + continue; + + /* + * Have an S-* property group with a "section" name. + * Print the section start. + */ + fprintf(fp, "[%s]\n", sect_name); + + /* + * Now print the remaining properties in this PG, + * but skip the special "section" (name) prop. + */ + if (scf_iter_pg_properties(propiter, pg) == -1) + goto out; + while ((ret = scf_iter_next_property(propiter, prop)) == 1) { + + if (scf_property_get_name(prop, prop_name, + sizeof (prop_name)) < 0) + continue; + + /* Skip the "section" prop. now */ + if (strcmp(prop_name, "section") == 0) + continue; + + if (scf_property_get_value(prop, val) != 0) + continue; + + if (scf_value_get_as_string(val, val_buf, + sizeof (val_buf)) < 0) + continue; + + fprintf(fp, "%s=%s\n", prop_name, val_buf); + } + } + ret = 0; + +out: + fflush(fp); + + scf_value_destroy(val); + scf_property_destroy(prop); + scf_pg_destroy(pg); + scf_iter_destroy(valiter); + scf_iter_destroy(propiter); + scf_iter_destroy(pgiter); + scf_instance_destroy(inst); + scf_service_destroy(svc); + + if (h != NULL) + scf_handle_destroy(h); + + return (ret); +} + +/* + * Simple test wrapper. Compile with: + * cc -o rc_scf_test -I.. -DTEST_MAIN rc_scf.c -lscf + */ +#ifdef TEST_MAIN +int +main(int argc, char **arv) +{ + char *s; + int rc; + + rc = rc_scf_get_sharectl(stdout); + printf("# rc=%d\n", rc); + return (0); +} +#endif /* TEST_MAIN */ diff --git a/usr/src/lib/libsmbfs/smb/rcfile.c b/usr/src/lib/libsmbfs/smb/rcfile.c index 56335d0954..d7ee2d15af 100644 --- a/usr/src/lib/libsmbfs/smb/rcfile.c +++ b/usr/src/lib/libsmbfs/smb/rcfile.c @@ -32,7 +32,7 @@ * $Id: rcfile.c,v 1.1.1.2 2001/07/06 22:38:43 conrad Exp $ */ /* - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -60,7 +60,6 @@ #define SMB_CFG_FILE "/etc/nsmb.conf" #define OLD_SMB_CFG_FILE "/usr/local/etc/nsmb.conf" #endif -#define SMBFS_SHARECTL_CMD "/usr/sbin/sharectl get smbfs" extern int smb_debug; @@ -150,37 +149,77 @@ rc_merge(const char *filename, struct rcfile **rcfile) } /* - * Like rc_open, but does popen of command: - * sharectl get smbfs + * Like rc_open, but creates a temporary file and + * reads the sharectl settings into it. + * The file is deleted when we close it. */ static int -rc_popen_cmd(const char *command, struct rcfile **rcfile) +rc_open_sharectl(struct rcfile **rcfile) { - struct rcfile *rcp; - FILE *f; + static char template[24] = "/tmp/smbfsXXXXXX"; + struct rcfile *rcp = NULL; + FILE *fp = NULL; + int err; + int fd = -1; assert(MUTEX_HELD(&rcfile_mutex)); - f = popen(command, "r"); - if (f == NULL) - return (errno); - insecure_nsmbrc = 0; + fd = mkstemp(template); + if (fd < 0) { + err = errno; + goto errout; + } + + fp = fdopen(fd, "w+"); + if (fp == NULL) { + err = errno; + close(fd); + goto errout; + } + fd = -1; /* The fp owns this fd now. */ + + /* + * Get smbfs sharectl settings into the file. + */ + if ((err = rc_scf_get_sharectl(fp)) != 0) + goto errout; rcp = malloc(sizeof (struct rcfile)); if (rcp == NULL) { - fclose(f); - return (ENOMEM); + err = ENOMEM; + goto errout; } bzero(rcp, sizeof (struct rcfile)); - rcp->rf_name = strdup(command); - rcp->rf_f = f; + + rcp->rf_name = strdup(template); + if (rcp->rf_name == NULL) { + err = ENOMEM; + goto errout; + } + rcp->rf_f = fp; + rcp->rf_flags = RCFILE_DELETE_ON_CLOSE; + SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); + insecure_nsmbrc = 0; rc_parse(rcp); *rcfile = rcp; /* fclose(f) in rc_close */ return (0); + +errout: + if (rcp != NULL) + free(rcp); + if (fp != NULL) { + fclose(fp); + fd = -1; + } + if (fd != -1) + close(fd); + + return (err); } + static int rc_close(struct rcfile *rcp) { @@ -189,6 +228,9 @@ rc_close(struct rcfile *rcp) mutex_lock(&rcfile_mutex); fclose(rcp->rf_f); + if (rcp->rf_flags & RCFILE_DELETE_ON_CLOSE) + (void) unlink(rcp->rf_name); + for (p = SLIST_FIRST(&rcp->rf_sect); p; ) { n = p; p = SLIST_NEXT(p, rs_next); @@ -663,8 +705,8 @@ smb_open_rcfile(char *home) fn = SMB_CFG_FILE; error = rc_open(fn, &smb_rc); #else - fn = SMBFS_SHARECTL_CMD; - error = rc_popen_cmd(fn, &smb_rc); + fn = "(sharectl get smbfs)"; + error = rc_open_sharectl(&smb_rc); #endif if (error != 0 && error != ENOENT) { /* Error from fopen. strerror is OK. */ diff --git a/usr/src/lib/libsmbfs/smb/rcfile_priv.h b/usr/src/lib/libsmbfs/smb/rcfile_priv.h index ef9e31d7fc..b239c77a67 100644 --- a/usr/src/lib/libsmbfs/smb/rcfile_priv.h +++ b/usr/src/lib/libsmbfs/smb/rcfile_priv.h @@ -30,9 +30,26 @@ * SUCH DAMAGE. */ +/* + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + +#ifndef _RCFILE_PRIV_H +#define _RCFILE_PRIV_H + +/* + * Private RC file support. + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + struct rckey { SLIST_ENTRY(rckey) rk_next; - char *rk_name; + char *rk_name; char *rk_value; }; @@ -52,3 +69,12 @@ struct rcfile { #define RCFILE_HOME_NSMBRC 1 #define RCFILE_IS_INSECURE 2 +#define RCFILE_DELETE_ON_CLOSE 4 + +int rc_scf_get_sharectl(FILE *); + +#ifdef __cplusplus +} +#endif + +#endif /* _RCFILE_PRIV_H */ diff --git a/usr/src/lib/smbclnt/libfknsmb/Makefile.com b/usr/src/lib/smbclnt/libfknsmb/Makefile.com index 3c79d72974..01da52d337 100644 --- a/usr/src/lib/smbclnt/libfknsmb/Makefile.com +++ b/usr/src/lib/smbclnt/libfknsmb/Makefile.com @@ -22,7 +22,7 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# Copyright 2017 Nexenta Systems, Inc. All rights reserved. +# Copyright 2018 Nexenta Systems, Inc. All rights reserved. # LIBRARY = libfknsmb.a @@ -57,6 +57,9 @@ OBJS_NSMB = \ smb_tran.o \ smb_trantcp.o \ smb_usr.o \ + smb2_rq.o \ + smb2_sign.o \ + smb2_smb.o \ subr_mchain.o OBJECTS = \ diff --git a/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers b/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers index 1123cc1e85..27fbd87b4d 100644 --- a/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers +++ b/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers @@ -20,7 +20,7 @@ # # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. -# Copyright 2017 Nexenta Systems, Inc. All rights reserved. +# Copyright 2018 Nexenta Systems, Inc. All rights reserved. # # @@ -57,12 +57,15 @@ SYMBOL_VERSION SUNWprivate { mb_done; mb_init; mb_initm; + mb_put_mbchain; + mb_put_mbuf; mb_put_mem; mb_put_padbyte; mb_put_uint16le; mb_put_uint32le; mb_put_uint64le; mb_put_uint8; + mb_put_uio; mb_reserve; md_done; @@ -82,9 +85,15 @@ SYMBOL_VERSION SUNWprivate { smb_credinit; smb_credrele; + smb_debugmsg { FLAGS = NODIRECT }; smb_dev2share; - smb_dos2unixtime; - smb_errmsg; + smb_errmsg { FLAGS = NODIRECT }; + smb_fh_close; + smb_fh_create; + smb_fh_hold; + smb_fh_opened; + smb_fh_rele; + smb_get_dstring; smb_nt_alloc; smb_nt_done; smb_nt_request; @@ -110,12 +119,16 @@ SYMBOL_VERSION SUNWprivate { smb_time_local2NT; smb_time_local2server; smb_time_server2local; - smb_time_unix2dos; smb_timo_append; smb_timo_open; smb_timo_read; smb_timo_write; + smb2_rq_simple; + smb2_rq_simple_timed; + smb2_smb_close; + smb2_smb_ntcreate; + local: *; }; diff --git a/usr/src/lib/smbclnt/libfksmbfs/Makefile.com b/usr/src/lib/smbclnt/libfksmbfs/Makefile.com index 5eb9728c12..abc12a9464 100644 --- a/usr/src/lib/smbclnt/libfksmbfs/Makefile.com +++ b/usr/src/lib/smbclnt/libfksmbfs/Makefile.com @@ -22,7 +22,7 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# Copyright 2017 Nexenta Systems, Inc. All rights reserved. +# Copyright 2018 Nexenta Systems, Inc. All rights reserved. # LIBRARY = libfksmbfs.a @@ -55,6 +55,8 @@ OBJS_FS_SMBFS = \ smbfs_client.o \ smbfs_node.o \ smbfs_smb.o \ + smbfs_smb1.o \ + smbfs_smb2.o \ smbfs_subr.o \ smbfs_subr2.o \ smbfs_acl.o \ diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c b/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c index 7524e2db55..b6b669cd27 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c index 956fbbad15..942650545f 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c index 8b0c4e3fbd..edf6952a8d 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -37,7 +37,7 @@ #include #include -#include +#include #include #include @@ -47,8 +47,8 @@ #define letohl(x) ((uint32_t)(x)) #else /* (BYTE_ORDER == LITTLE_ENDIAN) */ /* little-endian values on big-endian (swap) */ -#define letohl(x) BSWAP_32(x) -#define htolel(x) BSWAP_32(x) +#define letohl(x) BSWAP_32(x) +#define htolel(x) BSWAP_32(x) #endif /* (BYTE_ORDER == LITTLE_ENDIAN) */ /* diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c b/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c index dd15469c15..38dc21b712 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include #include diff --git a/usr/src/man/man4/nsmbrc.4 b/usr/src/man/man4/nsmbrc.4 index 2468be8f28..5eaffa9f63 100644 --- a/usr/src/man/man4/nsmbrc.4 +++ b/usr/src/man/man4/nsmbrc.4 @@ -3,7 +3,8 @@ .\" 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] -.TH NSMBRC 4 "Dec 8, 2008" +.\" Copyright 2018 Nexenta Systems, Inc. All rights reserved. +.TH NSMBRC 4 "May 8, 2018" .SH NAME nsmbrc \- configuration file for Solaris CIFS client requests .SH SYNOPSIS @@ -13,7 +14,6 @@ nsmbrc \- configuration file for Solaris CIFS client requests .fi .SH DESCRIPTION -.sp .LP Global behavior of the Solaris CIFS client is defined by property values that are stored in the Service Management Facility (SMF). The \fB\&.nsmbrc\fR file @@ -134,6 +134,32 @@ This property can only be set in the default and server sections. The default value is \fBntlm\fR. .RE +.sp +.ne 2 +.na +\fB\fBmin_protocol\fR\fR +.ad +.sp .6 +.RS 4n +Is the minimum SMB protocol level that will be negotiated, +which must be one of: \fB1\fR, \fB2.1\fR +This property can only be set in the default and server sections. +The default value is \fB1\fR. +.RE + +.sp +.ne 2 +.na +\fB\fBmax_protocol\fR\fR +.ad +.sp .6 +.RS 4n +Is the maximum SMB protocol level that will be negotiated, +which must be one of: \fB1\fR, \fB2.1\fR +This property can only be set in the default and server sections. +The default value is \fB2.1\fR. +.RE + .sp .ne 2 .na @@ -254,7 +280,6 @@ property. Use the \fBdomain\fR property instead. .RE .SH EXAMPLES -.sp .LP The examples in this section show how to use the \fB\&.nsmbrc\fR file and the \fBsmbutil\fR command to configure the \fBex.com\fR environment. @@ -360,7 +385,6 @@ shown are those set by the previous example. .sp .SH FILES -.sp .ne 2 .na \fB\fB$HOME/.nsmbrc\fR\fR @@ -372,7 +396,6 @@ connection. .RE .SH ATTRIBUTES -.sp .LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -388,13 +411,11 @@ Interface Stability Committed .TE .SH SEE ALSO -.sp .LP \fBsmbutil\fR(1), \fBmount_smbfs\fR(1M), \fBsharectl\fR(1M), \fBnsswitch.conf\fR(4), \fBuser_attr\fR(4), \fBattributes\fR(5), \fBrbac\fR(5), \fBsmbfs\fR(7FS) .SH NOTES -.sp .LP By default, passwords stored in the \fB\&.nsmbrc\fR file are ignored unless \fBonly\fR the file owner has read and write permission. diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 98a01e9993..7469b797d0 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -1272,11 +1272,13 @@ VSCAN_OBJS += vscan_drv.o vscan_svc.o vscan_door.o NSMB_OBJS += smb_conn.o smb_dev.o smb_iod.o smb_pass.o \ smb_rq.o smb_sign.o smb_smb.o smb_subrs.o \ smb_time.o smb_tran.o smb_trantcp.o smb_usr.o \ - subr_mchain.o nsmb_sign_kcf.o + smb2_rq.o smb2_sign.o smb2_smb.o subr_mchain.o \ + nsmb_sign_kcf.o SMBFS_COMMON_OBJS += smbfs_ntacl.o SMBFS_OBJS += smbfs_vfsops.o smbfs_vnops.o smbfs_node.o \ smbfs_acl.o smbfs_client.o smbfs_smb.o \ + smbfs_smb1.o smbfs_smb2.o \ smbfs_subr.o smbfs_subr2.o \ smbfs_rwlock.o smbfs_xattr.o \ $(SMBFS_COMMON_OBJS) diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple new file mode 100644 index 0000000000..a42fec94d8 --- /dev/null +++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2001 - 2012 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * 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 2.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.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip new file mode 100644 index 0000000000..96b9771514 --- /dev/null +++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip @@ -0,0 +1 @@ +PORTIONS OF NSMB DRIVER IN SMB CLIENT diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov new file mode 100644 index 0000000000..583923c355 --- /dev/null +++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov @@ -0,0 +1,29 @@ + Copyright (c) 2000, 2001 Boris Popov + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by Boris Popov. + 4. Neither the name of the author nor the names of any co-contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip new file mode 100644 index 0000000000..96b9771514 --- /dev/null +++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip @@ -0,0 +1 @@ +PORTIONS OF NSMB DRIVER IN SMB CLIENT diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in index 1d3bc3e6f5..a78b08bba0 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in +++ b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in @@ -52,8 +52,10 @@ smbioc_ssn_ident id_user smbioc_ossn - ssn_vopt ssn_owner + ssn_vopt + ssn_minver + ssn_maxver ssn_id ssn_srvname @@ -76,22 +78,22 @@ smbioc_ssn_work wk_u_auth_wlen wk_u_auth_rbuf wk_u_auth_wbuf - wk_ssn_key + wk_cl_guid + +smbioc_rw SIZEOF_SMBIOC_RW + ioc_cnt + ioc_flags + _ioc_offset + _ioc_base smbioc_xnp SIZEOF_SMBIOC_XNP - ioc_fh ioc_tdlen ioc_rdlen ioc_more + ioc_pad1 _ioc_tdata _ioc_rdata -smbioc_rw SIZEOF_SMBIOC_RW - ioc_fh - ioc_cnt - _ioc_offset - _ioc_base - smbioc_ntcreate SIZEOF_NTCREATE ioc_req_acc ioc_efattr diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c new file mode 100644 index 0000000000..44041ad975 --- /dev/null +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * 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 2.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.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +static const uint8_t SMB2_SIGNATURE[4] = SMB2_PROTOCOL_ID; + +static int smb2_rq_enqueue(struct smb_rq *rqp); +static int smb2_rq_reply(struct smb_rq *rqp); + +/* + * Given a request with it's body already composed, + * rewind to the start and fill in the SMB2 header. + * This is called when the request is enqueued, + * so we have the final message ID etc. + */ +void +smb2_rq_fillhdr(struct smb_rq *rqp) +{ + struct mbchain mbtmp, *mbp = &mbtmp; + uint16_t creditcharge, creditrequest; + size_t len; + mblk_t *m; + + ASSERT((rqp->sr2_nextcmd & 7) == 0); + if (rqp->sr2_nextcmd != 0) { + len = msgdsize(rqp->sr_rq.mb_top); + ASSERT((len & 7) == 0); + } + + /* + * When sending negotiate, we don't technically know yet + * if the server handles SMB 2.1 or later and credits. + * Negotiate is supposed to set these to zero. + */ + if (rqp->sr2_command == SMB2_NEGOTIATE) { + creditcharge = creditrequest = 0; + } else { + creditcharge = rqp->sr2_creditcharge; + creditrequest = rqp->sr2_creditsrequested; + } + + /* + * Fill in the SMB2 header using a dup of the first mblk, + * which points at the same data but has its own wptr, + * so we can rewind without trashing the message. + */ + m = dupb(rqp->sr_rq.mb_top); + m->b_wptr = m->b_rptr; /* rewind */ + mb_initm(mbp, m); + + mb_put_mem(mbp, SMB2_SIGNATURE, 4, MB_MSYSTEM); + mb_put_uint16le(mbp, SMB2_HDR_SIZE); /* Struct Size */ + mb_put_uint16le(mbp, creditcharge); + mb_put_uint32le(mbp, 0); /* Status */ + mb_put_uint16le(mbp, rqp->sr2_command); + mb_put_uint16le(mbp, creditrequest); + mb_put_uint32le(mbp, rqp->sr2_rqflags); + mb_put_uint32le(mbp, rqp->sr2_nextcmd); + mb_put_uint64le(mbp, rqp->sr2_messageid); + + mb_put_uint32le(mbp, rqp->sr_pid); /* Process ID */ + mb_put_uint32le(mbp, rqp->sr2_rqtreeid); /* Tree ID */ + mb_put_uint64le(mbp, rqp->sr2_rqsessionid); /* Session ID */ + /* The MAC signature is filled in by smb2_vc_sign() */ + + /* This will free the mblk from dupb. */ + mb_done(mbp); +} + +int +smb2_rq_simple(struct smb_rq *rqp) +{ + return (smb2_rq_simple_timed(rqp, smb2_timo_default)); +} + +/* + * Simple request-reply exchange + */ +int +smb2_rq_simple_timed(struct smb_rq *rqp, int timeout) +{ + int error; + + rqp->sr_flags &= ~SMBR_RESTART; + rqp->sr_timo = timeout; /* in seconds */ + rqp->sr_state = SMBRQ_NOTSENT; + + error = smb2_rq_enqueue(rqp); + if (error == 0) + error = smb2_rq_reply(rqp); + + return (error); +} + + +static int +smb2_rq_enqueue(struct smb_rq *rqp) +{ + struct smb_vc *vcp = rqp->sr_vc; + struct smb_share *ssp = rqp->sr_share; + int error = 0; + + ASSERT((vcp->vc_flags & SMBV_SMB2) != 0); + + /* + * Normal requests may initiate a reconnect, + * and/or wait for state changes to finish. + * Some requests set the NORECONNECT flag + * to avoid all that (i.e. tree discon) + */ + if (rqp->sr_flags & SMBR_NORECONNECT) { + if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { + SMBSDEBUG("bad vc_state=%d\n", vcp->vc_state); + return (ENOTCONN); + } + if (ssp != NULL && + ((ssp->ss_flags & SMBS_CONNECTED) == 0)) + return (ENOTCONN); + goto ok_out; + } + + /* + * If we're not connected, initiate a reconnect + * and/or wait for an existing one to finish. + */ + if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { + error = smb_iod_reconnect(vcp); + if (error != 0) + return (error); + } + + /* + * If this request has a "share" object + * that needs a tree connect, do it now. + */ + if (ssp != NULL && (ssp->ss_flags & SMBS_CONNECTED) == 0) { + error = smb_share_tcon(ssp, rqp->sr_cred); + if (error) + return (error); + } + + /* + * We now know what UID + TID to use. + * Store them in the request. + */ +ok_out: + rqp->sr2_rqsessionid = vcp->vc2_session_id; + rqp->sr2_rqtreeid = ssp ? ssp->ss2_tree_id : SMB2_TID_UNKNOWN; + error = smb2_iod_addrq(rqp); + + return (error); +} + +/* + * Used by the IOD thread during connection setup, + * and for smb2_echo after network timeouts. Note that + * unlike smb2_rq_simple, callers must check sr_error. + */ +int +smb2_rq_internal(struct smb_rq *rqp, int timeout) +{ + struct smb_vc *vcp = rqp->sr_vc; + int error; + + ASSERT((vcp->vc_flags & SMBV_SMB2) != 0); + + rqp->sr_flags &= ~SMBR_RESTART; + rqp->sr_timo = timeout; /* in seconds */ + rqp->sr_state = SMBRQ_NOTSENT; + + /* + * In-line smb2_rq_enqueue(rqp) here, as we don't want it + * trying to reconnect etc. for an internal request. + */ + rqp->sr2_rqsessionid = vcp->vc2_session_id; + rqp->sr2_rqtreeid = SMB2_TID_UNKNOWN; + rqp->sr_flags |= SMBR_INTERNAL; + error = smb2_iod_addrq(rqp); + if (error != 0) + return (error); + + /* + * In-line a variant of smb2_rq_reply(rqp) here as we may + * need to do custom parsing for SMB1-to-SMB2 negotiate. + */ + if (rqp->sr_timo == SMBNOREPLYWAIT) { + smb_iod_removerq(rqp); + return (0); + } + + error = smb_iod_waitrq_int(rqp); + if (error) + return (error); + + /* + * If the request was signed, validate the + * signature on the response. + */ + if (rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) { + error = smb2_rq_verify(rqp); + if (error) + return (error); + } + + /* + * Parse the SMB2 header. + */ + error = smb2_rq_parsehdr(rqp); + + /* + * Skip the error translation smb2_rq_reply does. + * Callers of this expect "raw" NT status. + */ + + return (error); +} + +/* + * Wait for a reply to this request, then parse it. + */ +static int +smb2_rq_reply(struct smb_rq *rqp) +{ + int error; + + if (rqp->sr_timo == SMBNOREPLYWAIT) { + smb_iod_removerq(rqp); + return (0); + } + + error = smb_iod_waitrq(rqp); + if (error) + return (error); + + /* + * If the request was signed, validate the + * signature on the response. + */ + if (rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) { + error = smb2_rq_verify(rqp); + if (error) + return (error); + } + + /* + * Parse the SMB2 header + */ + error = smb2_rq_parsehdr(rqp); + if (error != 0) + return (error); + + if (rqp->sr_error != 0) { + error = smb_maperr32(rqp->sr_error); + } + + if (error != 0) { + /* + * 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. + */ + rqp->sr_flags |= SMBR_MOREDATA; + error = 0; + } + } else { + rqp->sr_flags &= ~SMBR_MOREDATA; + } + + return (error); +} + +/* + * Parse the SMB 2+ Header + */ +int +smb2_rq_parsehdr(struct smb_rq *rqp) +{ + struct mdchain *mdp = &rqp->sr_rp; + uint32_t protocol_id; + uint16_t length = 0; + uint16_t credit_charge; + uint16_t command; + uint64_t message_id = 0; + int error = 0; + + /* Get Protocol ID */ + md_get_uint32le(mdp, &protocol_id); + + /* Get/Check structure size is 64 */ + md_get_uint16le(mdp, &length); + if (length != 64) + return (EBADRPC); + + md_get_uint16le(mdp, &credit_charge); + md_get_uint32le(mdp, &rqp->sr_error); + md_get_uint16le(mdp, &command); + md_get_uint16le(mdp, &rqp->sr2_rspcreditsgranted); + md_get_uint32le(mdp, &rqp->sr2_rspflags); + md_get_uint32le(mdp, &rqp->sr2_rspnextcmd); + md_get_uint64le(mdp, &message_id); + + if ((rqp->sr2_rspflags & SMB2_FLAGS_ASYNC_COMMAND) == 0) { + /* + * Sync Header + */ + + /* Get Process ID */ + md_get_uint32le(mdp, &rqp->sr2_rsppid); + + /* Get Tree ID */ + md_get_uint32le(mdp, &rqp->sr2_rsptreeid); + } else { + /* + * Async Header + */ + + /* Get Async ID */ + md_get_uint64le(mdp, &rqp->sr2_rspasyncid); + } + + /* Get Session ID */ + error = md_get_uint64le(mdp, &rqp->sr2_rspsessionid); + if (error) + return (error); + + /* Skip MAC Signature */ + error = md_get_mem(mdp, NULL, 16, MB_MSYSTEM); + + return (error); +} diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h new file mode 100644 index 0000000000..812c679b2f --- /dev/null +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 - 2012 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * 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 2.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.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + +#ifndef _NETSMB_SMB2_RQ_H_ +#define _NETSMB_SMB2_RQ_H_ + +#include + +/* + * Note: Pad all structures to 8 byte boundaries + */ + +int smb2_rq_parsehdr(struct smb_rq *rqp); +void smb2_rq_fillhdr(struct smb_rq *rqp); + +int smb2_rq_simple(struct smb_rq *rqp); +int smb2_rq_simple_timed(struct smb_rq *rqp, int timeout); +int smb2_rq_internal(struct smb_rq *rqp, int timeout); + +#endif /* _NETSMB_SMB2_RQ_H_ */ diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c new file mode 100644 index 0000000000..46bf28c370 --- /dev/null +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c @@ -0,0 +1,253 @@ +/* + * 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + +/* + * Support for SMB2 "signing" (message integrity) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define SMB2_SIG_OFF 48 +#define SMB2_SIG_LEN 16 + +/* + * smb2_sign_init + * + * Get the mechanism info and initilize SMB2 signing. + */ +int +smb2_sign_init(smb_vc_t *vcp) +{ + uint_t copysize; + int rc; + + ASSERT(vcp->vc_ssnkey != NULL); + ASSERT(vcp->vc_mackey == NULL); + + rc = smb2_hmac_getmech(&vcp->vc_signmech); + if (rc != 0) { + cmn_err(CE_NOTE, "smb2 can't get signing mechanism"); + return (EAUTH); + } + + /* + * Convert the session key to the MAC key. + * + * For SMB2, the signing key is just the first 16 bytes + * of the session key (truncated or padded with zeros). + * [MS-SMB2] 3.2.5.3.1 + * + * SMB3 would do KDF here. + */ + vcp->vc_mackeylen = SMB2_SIG_LEN; + vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP); + copysize = vcp->vc_ssnkeylen; + if (copysize > vcp->vc_mackeylen) + copysize = vcp->vc_mackeylen; + bcopy(vcp->vc_ssnkey, vcp->vc_mackey, copysize); + + return (0); +} + + +/* + * Compute MAC signature of packet data, using the stored MAC key. + * + * The signature is in the last 16 bytes of the SMB2 header. + * The signature algorighm is to compute HMAC SHA256 over the + * entire command, with the signature field set to zeros. + * + * See similar code for the server side: + * uts/common/fs/smbsrv/smb2_signing.c : smb2_sign_calc + */ +static int +smb2_compute_MAC(struct smb_vc *vcp, mblk_t *mp, uchar_t *signature) +{ + uint8_t tmp_hdr[SMB2_HDR_SIZE]; + smb_sign_ctx_t ctx = 0; + mblk_t *m = mp; + int size; + int rc; + + if (vcp->vc_mackey == NULL) + return (-1); + + rc = smb2_hmac_init(&ctx, &vcp->vc_signmech, + vcp->vc_mackey, vcp->vc_mackeylen); + if (rc != 0) + return (rc); + + /* Our caller should ensure mp has a contiguous header */ + ASSERT(m != NULL); + ASSERT(MBLKL(m) >= SMB2_HDRLEN); + + /* + * Copy of the SMB2 header, zero out the signature, and digest. + */ + size = SMB2_HDRLEN; + bcopy(m->b_rptr, tmp_hdr, size); + bzero(tmp_hdr + SMB2_SIG_OFF, SMB2_SIG_LEN); + rc = smb2_hmac_update(ctx, tmp_hdr, size); + if (rc != 0) + return (rc); + + /* + * Digest the rest of the SMB2 header packet, starting at + * the data just after the SMB2 header. + */ + size = MBLKL(m) - SMB2_HDRLEN; + rc = smb2_hmac_update(ctx, m->b_rptr + SMB2_HDRLEN, size); + if (rc != 0) + return (rc); + m = m->b_cont; + + /* Digest rest of the SMB2 message. */ + while (m != NULL) { + size = MBLKL(m); + if (size > 0) { + rc = smb2_hmac_update(ctx, m->b_rptr, size); + if (rc != 0) + return (rc); + } + m = m->b_cont; + } + rc = smb2_hmac_final(ctx, signature); + + return (rc); +} + +/* + * Sign a request with HMAC-MD5. + */ +void +smb2_rq_sign(struct smb_rq *rqp) +{ + struct smb_vc *vcp = rqp->sr_vc; + mblk_t *mp = rqp->sr_rq.mb_top; + uint8_t *sigloc; + int rc; + + /* + * smb_rq_new() ensures this, + * but just in case.. + */ + ASSERT(MBLKL(mp) >= SMB2_HDRLEN); + sigloc = mp->b_rptr + SMB2_SIG_OFF; + + if (vcp->vc_mackey == NULL) + return; + + /* + * This will compute the MAC and store it + * directly into the message at sigloc. + */ + rc = smb2_compute_MAC(vcp, mp, sigloc); + if (rc != 0) { + SMBSDEBUG("Crypto error %d", rc); + bzero(sigloc, SMB2_SIG_LEN); + } +} + +/* + * Verify reply signature. + */ +int +smb2_rq_verify(struct smb_rq *rqp) +{ + struct smb_vc *vcp = rqp->sr_vc; + mblk_t *mp = rqp->sr_rp.md_top; + uint8_t sigbuf[SMB2_SIG_LEN]; + uint8_t *sigloc; + int rc; + + /* + * Note vc_mackey and vc_mackeylen gets filled in by + * smb_usr_iod_work as the connection comes in. + */ + if (vcp->vc_mackey == NULL) { + SMBSDEBUG("no mac key\n"); + return (0); + } + + /* + * Let caller deal with empty reply or short messages by + * returning zero. Caller will fail later, in parsing. + */ + if (mp == NULL) { + SMBSDEBUG("empty reply\n"); + return (0); + } + + /* smb2_iod_process ensures this */ + ASSERT(MBLKL(mp) >= SMB2_HDRLEN); + sigloc = mp->b_rptr + SMB2_SIG_OFF; + + /* + * Compute the expected signature in sigbuf. + */ + rc = smb2_compute_MAC(vcp, mp, sigbuf); + if (rc != 0) { + SMBSDEBUG("Crypto error %d", rc); + /* + * If we can't compute a MAC, then there's + * no point trying other seqno values. + */ + return (EBADRPC); + } + + /* + * Compare the computed signature with the + * one found in the message (at sigloc) + */ + if (bcmp(sigbuf, sigloc, SMB2_SIG_LEN) == 0) + return (0); + + SMBERROR("BAD signature, Server=%s MID=0x%llx\n", + vcp->vc_srvname, (long long)rqp->sr2_messageid); + + return (EBADRPC); +} diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c new file mode 100644 index 0000000000..c3df18faa9 --- /dev/null +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c @@ -0,0 +1,1325 @@ +/* + * Copyright (c) 2011 - 2013 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * 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 2.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.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define NDIALECTS 1 +static const uint16_t smb2_dialects[1] = { + SMB2_DIALECT_0210 +}; + +/* Optional capabilities we advertise (none yet). */ +uint32_t smb2_clnt_caps = 0; + +/* How many credits to ask for during ssn. setup. */ +uint16_t smb2_ss_req_credits = 64; + +/* + * Default timeout values, all in seconds. + * Make these tunable (only via mdb for now). + */ +int smb2_timo_notice = 15; +int smb2_timo_default = 30; +int smb2_timo_logon = 45; +int smb2_timo_open = 45; +int smb2_timo_read = 45; +int smb2_timo_write = 60; +int smb2_timo_append = 90; + +/* + * This is a special handler for the odd SMB1-to-SMB2 negotiate + * response, where an SMB1 request gets an SMB2 response. + * + * Unlike most parse functions here, this needs to parse both + * the SMB2 header and the nego. response body. Note that + * the only "SMB2" dialect our SMB1 negotiate offered was + * { SMB_DIALECT_SMB2_FF, "SMB 2.???"} so the only valid + * SMB2 dialect we should get is: SMB2_DIALECT_02ff + */ +int +smb2_parse_smb1nego_resp(struct smb_rq *rqp) +{ + struct smb_vc *vcp = rqp->sr_vc; + struct smb_sopt *sp = &vcp->vc_sopt; + struct mdchain *mdp; + uint16_t length = 0; + int error; + + /* Get pointer to response data */ + smb_rq_getreply(rqp, &mdp); + + error = smb2_rq_parsehdr(rqp); + if (error != 0) + return (error); + + /* + * Parse SMB 2/3 Negotiate Response + * We are already pointing to begining of Response data + */ + + /* Check structure size is 65 */ + md_get_uint16le(mdp, &length); + if (length != 65) + return (EBADRPC); + + /* Get Security Mode */ + md_get_uint16le(mdp, &sp->sv2_security_mode); + + /* Get Dialect. */ + error = md_get_uint16le(mdp, &sp->sv2_dialect); + if (error != 0) + return (error); + + /* What dialect did we get? */ + if (sp->sv2_dialect != SMB2_DIALECT_02ff) { + SMBERROR("Unknown dialect 0x%x\n", sp->sv2_dialect); + return (EINVAL); + } + /* Set our (internal) SMB1 dialect also. */ + sp->sv_proto = SMB_DIALECT_SMB2_FF; + + /* + * This request did not go through smb2_iod_addrq and + * smb2_iod_process() so the SMB2 message ID state is + * behind what we need it to be. Fix that. + */ + vcp->vc2_next_message_id = 1; + vcp->vc2_limit_message_id = 2; + + /* + * Skip parsing the rest. We'll get a normal + * SMB2 negotiate next and do negotiate then. + */ + return (0); +} + +int +smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) +{ + smb_sopt_t *sp = &vcp->vc_sopt; + smbioc_ssn_work_t *wk = &vcp->vc_work; + struct smb_rq *rqp = NULL; + struct mbchain *mbp = NULL; + struct mdchain *mdp = NULL; + uint16_t ndialects = NDIALECTS; + boolean_t will_sign = B_FALSE; + uint16_t length = 0; + uint16_t security_mode; + uint16_t sec_buf_off; + uint16_t sec_buf_len; + int err, i; + + /* + * Compute security mode + */ + if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) { + security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED; + } else { + security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED; + } + + err = smb_rq_alloc(VCTOCP(vcp), SMB2_NEGOTIATE, scred, &rqp); + if (err) + return (err); + + /* + * Build the SMB2 negotiate request. + */ + smb_rq_getrequest(rqp, &mbp); + mb_put_uint16le(mbp, 36); /* Struct Size */ + mb_put_uint16le(mbp, ndialects); /* Dialect Count */ + mb_put_uint16le(mbp, security_mode); + mb_put_uint16le(mbp, 0); /* Reserved */ + mb_put_uint32le(mbp, smb2_clnt_caps); + mb_put_mem(mbp, vcp->vc_cl_guid, 16, MB_MSYSTEM); + mb_put_uint64le(mbp, 0); /* Start Time */ + for (i = 0; i < ndialects; i++) { /* Dialects */ + mb_put_uint16le(mbp, smb2_dialects[i]); + } + + /* + * Do the OTW call. + */ + err = smb2_rq_internal(rqp, smb2_timo_default); + if (err) { + goto errout; + } + /* Should only get status success. */ + if (rqp->sr_error != NT_STATUS_SUCCESS) { + err = ENOTSUP; + goto errout; + } + + /* + * Decode the negotiate response + */ + smb_rq_getreply(rqp, &mdp); + + md_get_uint16le(mdp, &length); /* Struct size */ + if (length != 65) { + err = EBADRPC; + goto errout; + } + + md_get_uint16le(mdp, &sp->sv2_security_mode); + md_get_uint16le(mdp, &sp->sv2_dialect); + md_get_uint16le(mdp, NULL); /* reserved */ + md_get_mem(mdp, sp->sv2_guid, 16, MB_MSYSTEM); + md_get_uint32le(mdp, &sp->sv2_capabilities); + md_get_uint32le(mdp, &sp->sv2_maxtransact); + md_get_uint32le(mdp, &sp->sv2_maxread); + md_get_uint32le(mdp, &sp->sv2_maxwrite); + md_get_uint64le(mdp, NULL); /* curr_time */ + md_get_uint64le(mdp, NULL); /* boot_time */ + + /* Get Security Blob offset and length */ + md_get_uint16le(mdp, &sec_buf_off); + err = md_get_uint16le(mdp, &sec_buf_len); + if (err != 0) + goto errout; + md_get_uint32le(mdp, NULL); /* reserved */ + + /* + * Security buffer offset is from the beginning of SMB 2 Header + * Calculate how much further we have to go to get to it. + * Current offset is: SMB2_HDRLEN + 64 + */ + if (sec_buf_len != 0) { + int skip = (int)sec_buf_off - (SMB2_HDRLEN + 64); + if (skip < 0) { + err = EBADRPC; + goto errout; + } + if (skip > 0) { + md_get_mem(mdp, NULL, skip, MB_MSYSTEM); + } + + /* + * Copy the security blob out to user space. + * Buffer addr,size in vc_auth_rbuf,rlen + */ + if (wk->wk_u_auth_rlen < sec_buf_len) { + SMBSDEBUG("vc_auth_rbuf too small"); + /* Give caller required size. */ + wk->wk_u_auth_rlen = sec_buf_len; + err = EMSGSIZE; + goto errout; + } + wk->wk_u_auth_rlen = sec_buf_len; + err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr, + sec_buf_len, MB_MUSER); + if (err) { + goto errout; + } + } + + /* + * Decoded everything. Now decisions. + */ + + /* + * Turn on signing if either Server or client requires it, + * except: anonymous sessions can't sign. + */ + if ((sp->sv2_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || + (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED)) + will_sign = B_TRUE; + if (vcp->vc_vopt & SMBVOPT_ANONYMOUS) + will_sign = B_FALSE; + SMBSDEBUG("Security signatures: %d", (int)will_sign); + if (will_sign) + vcp->vc_flags |= SMBV_SIGNING; + + /* + * ToDo - too many places are looking at sv_caps, so for now + * set the SMB1 capabilities too. Later we should use the + * sv2_capabilities for SMB 2+. + */ + sp->sv_caps = (SMB_CAP_UNICODE | + SMB_CAP_LARGE_FILES | + SMB_CAP_STATUS32 | + SMB_CAP_LARGE_READX | + SMB_CAP_LARGE_WRITEX | + SMB_CAP_EXT_SECURITY); + if (sp->sv2_capabilities & SMB2_CAP_DFS) + sp->sv_caps |= SMB_CAP_DFS; + + /* + * A few sanity checks on what we received, + * becuse we will send these in ssnsetup. + * + * Maximum outstanding requests (we care), + * and Max. VCs (we only use one). Also, + * MaxBufferSize lower limit per spec. + */ + if (sp->sv2_maxread < 0x8000) { + SMBSDEBUG("maxread too small\n"); + err = ENOTSUP; + goto errout; + } + if (sp->sv2_maxwrite < 0x8000) { + SMBSDEBUG("maxwrite too small\n"); + err = ENOTSUP; + goto errout; + } + if (sp->sv2_maxtransact < 0x4000) { + SMBSDEBUG("maxtransact too small\n"); + err = ENOTSUP; + goto errout; + } + + /* Here too, fill SMB1 fields */ + vcp->vc_rxmax = sp->sv2_maxread; + vcp->vc_wxmax = sp->sv2_maxwrite; + vcp->vc_txmax = sp->sv2_maxtransact; + + smb_rq_done(rqp); + return (0); + +errout: + smb_rq_done(rqp); + if (err == 0) + err = EBADRPC; + return (err); +} + +int +smb2_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred) +{ + // smb_sopt_t *sv = &vcp->vc_sopt; + smbioc_ssn_work_t *wk = &vcp->vc_work; + struct smb_rq *rqp = NULL; + struct mbchain *mbp = NULL; + struct mdchain *mdp = NULL; + char *sb; + int err, ret; + uint16_t sblen; + uint16_t length = 0; + uint16_t session_flags; + uint16_t sec_buf_off; + uint16_t sec_buf_len; + uint8_t security_mode; + + /* + * Compute security mode + */ + if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) { + security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED; + } else { + security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED; + } + + sb = wk->wk_u_auth_wbuf.lp_ptr; + sblen = (uint16_t)wk->wk_u_auth_wlen; + + err = smb_rq_alloc(VCTOCP(vcp), SMB2_SESSION_SETUP, scred, &rqp); + if (err != 0) { + ret = err; + goto out; + } + + /* + * Always ask for some credits. The server usually will + * only grant these credits once we've authenticated. + */ + rqp->sr2_creditsrequested = smb2_ss_req_credits; + + /* + * Build the SMB Session Setup request. + */ + smb_rq_getrequest(rqp, &mbp); + + mb_put_uint16le(mbp, 25); /* Struct size */ + mb_put_uint8(mbp, 0); /* VcNumber */ + mb_put_uint8(mbp, security_mode); + mb_put_uint32le(mbp, smb2_clnt_caps); /* Capabilities */ + mb_put_uint32le(mbp, 0); /* Channel - always 0 */ + + /* + * Security buffer offset and length. Normally would use + * ptr = mb_reserve() and fill in later, but since only a + * small amount of fixed-size stuff follows (12 bytes) + * we can just compute the offset now. + */ + mb_put_uint16le(mbp, mbp->mb_count + 12); + mb_put_uint16le(mbp, sblen); + mb_put_uint64le(mbp, vcp->vc2_prev_session_id); + err = mb_put_mem(mbp, sb, sblen, MB_MUSER); + if (err != 0) { + ret = err; + goto out; + } + + /* + * Run the request. The return value here should be the + * return from this function, unless we fail decoding. + * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and + * the caller expects EINPROGRESS for that case. + */ + ret = smb2_rq_internal(rqp, smb2_timo_logon); + if (ret != 0) + goto out; + switch (rqp->sr_error) { + case NT_STATUS_SUCCESS: + break; + case NT_STATUS_MORE_PROCESSING_REQUIRED: + /* Keep going, but return... */ + ret = EINPROGRESS; + break; + default: + ret = EAUTH; + goto out; + } + + /* + * After the first Session Setup Response, + * save the session ID. + */ + if (vcp->vc2_session_id == 0) + vcp->vc2_session_id = rqp->sr2_rspsessionid; + + /* + * Decode the session setup response + */ + smb_rq_getreply(rqp, &mdp); + + md_get_uint16le(mdp, &length); /* Struct size */ + if (length != 9) { + ret = EBADRPC; + goto out; + } + + md_get_uint16le(mdp, &session_flags); + md_get_uint16le(mdp, &sec_buf_off); + err = md_get_uint16le(mdp, &sec_buf_len); + if (err != 0) { + ret = err; + goto out; + } + + /* + * Security buffer offset is from the beginning of SMB 2 Header + * Calculate how much further we have to go to get to it. + * Current offset is: SMB2_HDRLEN + 8 + */ + if (sec_buf_len != 0) { + int skip = (int)sec_buf_off - (SMB2_HDRLEN + 8); + if (skip < 0) { + ret = EBADRPC; + goto out; + } + if (skip > 0) { + md_get_mem(mdp, NULL, skip, MB_MSYSTEM); + } + + /* + * Copy the security blob out to user space. + * Buffer addr,size in vc_auth_rbuf,rlen + */ + if (wk->wk_u_auth_rlen < sec_buf_len) { + SMBSDEBUG("vc_auth_rbuf too small"); + /* Give caller required size. */ + wk->wk_u_auth_rlen = sec_buf_len; + ret = EMSGSIZE; + goto out; + } + wk->wk_u_auth_rlen = sec_buf_len; + err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr, + sec_buf_len, MB_MUSER); + if (err != 0) { + ret = err; + goto out; + } + } + +out: + if (err != 0 && err != EINPROGRESS) { + /* Session ID no longer valid. */ + vcp->vc2_session_id = 0; + } + if (rqp) + smb_rq_done(rqp); + + return (ret); +} + +int +smb2_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred) +{ + struct smb_rq *rqp; + struct mbchain *mbp; + int error; + + if (vcp->vc2_session_id == 0) + return (0); + + error = smb_rq_alloc(VCTOCP(vcp), SMB2_LOGOFF, scred, &rqp); + if (error) + return (error); + + /* + * Fill in Logoff part + */ + smb_rq_getrequest(rqp, &mbp); + mb_put_uint16le(mbp, 4); /* Struct size */ + mb_put_uint16le(mbp, 0); /* Reserved */ + + /* + * Run this with a relatively short timeout. (5 sec.) + * We don't really care about the result here. + * Also, don't reconnect for this, of course! + */ + rqp->sr_flags |= SMBR_NORECONNECT; + error = smb2_rq_internal(rqp, 5); + smb_rq_done(rqp); + return (error); +} + +int +smb2_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) +{ + struct smb_vc *vcp; + struct smb_rq *rqp = NULL; + struct mbchain *mbp; + struct mdchain *mdp; + char *unc_name = NULL; + int error, unc_len; + uint16_t plen, *plenp; + uint16_t options = 0; + uint_t cnt0; + uint32_t net_stype; + uint16_t structure_size = 0; + uint8_t smb2stype; + + 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. + */ + error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_CONNECT, scred, &rqp); + if (error) + return (error); + + /* + * Build the UNC name, i.e. "//server/share" + * but with backslashes of course. + * size math: three slashes, one null. + */ + unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name); + unc_name = kmem_alloc(unc_len, KM_SLEEP); + (void) snprintf(unc_name, unc_len, "\\\\%s\\%s", + vcp->vc_srvname, ssp->ss_name); + SMBSDEBUG("unc_name: \"%s\"", unc_name); + + /* + * Build the request. + */ + mbp = &rqp->sr_rq; + + mb_put_uint16le(mbp, 9); /* Struct size */ + mb_put_uint16le(mbp, 0); /* Reserved */ + mb_put_uint16le(mbp, 72); /* Path Offset */ + + /* + * Fill in path length after we put the string, so we know + * the length after conversion from UTF-8 to UCS-2. + */ + plenp = mb_reserve(mbp, 2); + cnt0 = mbp->mb_count; + + /* UNC resource name (without the null) */ + error = smb_put_dmem(mbp, vcp, unc_name, unc_len - 1, + SMB_CS_NONE, NULL); + if (error) + goto out; + + /* Now go back and fill in the path length. */ + plen = (uint16_t)(mbp->mb_count - cnt0); + *plenp = htoles(plen); + + /* + * Run the request. + * + * Using NOINTR_RECV because we don't want to risk + * missing a successful tree connect response, + * which would "leak" Tree IDs. + */ + rqp->sr_flags |= SMBR_NOINTR_RECV; + error = smb2_rq_simple(rqp); + SMBSDEBUG("%d\n", error); + if (error) { + /* + * If we get the server name wrong, i.e. due to + * mis-configured name services, this will be + * NT_STATUS_DUPLICATE_NAME. Log this error. + */ + SMBERROR("(%s) failed, status=0x%x", + unc_name, rqp->sr_error); + goto out; + } + + /* + * Parse the tree connect response + */ + smb_rq_getreply(rqp, &mdp); + + /* Check structure size is 16 */ + md_get_uint16le(mdp, &structure_size); + if (structure_size != 16) { + error = EBADRPC; + goto out; + } + + md_get_uint8(mdp, &smb2stype); + md_get_uint8(mdp, NULL); /* reserved */ + md_get_uint32le(mdp, &ssp->ss2_share_flags); + md_get_uint32le(mdp, &ssp->ss2_share_caps); + error = md_get_uint32le(mdp, NULL); /* maxAccessRights */ + if (error) + goto out; + + /* + * Convert SMB2 share type to NetShareEnum share type + */ + switch (smb2stype) { + case SMB2_SHARE_TYPE_DISK: + net_stype = STYPE_DISKTREE; + break; + case SMB2_SHARE_TYPE_PIPE: + net_stype = STYPE_IPC; + break; + case SMB2_SHARE_TYPE_PRINT: + net_stype = STYPE_PRINTQ; + break; + default: + net_stype = STYPE_UNKNOWN; + break; + } + ssp->ss_type = net_stype; + + /* + * Map SMB 2/3 capabilities to SMB 1 options, + * for common code that looks there. + */ + if (ssp->ss2_share_caps & SMB2_SHARE_CAP_DFS) + options |= SMB_SHARE_IS_IN_DFS; + + /* Update share state */ + SMB_SS_LOCK(ssp); + ssp->ss2_tree_id = rqp->sr2_rsptreeid; + ssp->ss_vcgenid = vcp->vc_genid; + ssp->ss_options = options; + ssp->ss_flags |= SMBS_CONNECTED; + SMB_SS_UNLOCK(ssp); + +out: + if (unc_name) + kmem_free(unc_name, unc_len); + smb_rq_done(rqp); + return (error); +} + +int +smb2_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->ss2_tree_id == SMB2_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), SMB2_TREE_DISCONNECT, scred, &rqp); + if (error) + return (error); + rqp->sr_share = ssp; /* See "by hand" above. */ + + /* + * Fill in SMB2 Tree Disconnect part + */ + smb_rq_getrequest(rqp, &mbp); + mb_put_uint16le(mbp, 4); /* Struct size */ + mb_put_uint16le(mbp, 0); /* Reserved */ + + /* + * 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. + * Also, don't reconnect for this, of course! + */ + rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT); + error = smb2_rq_simple_timed(rqp, 5); + + smb_rq_done(rqp); + + /* Whether we get an error or not... */ + ssp->ss2_tree_id = SMB2_TID_UNKNOWN; + + return (error); +} + +/* + * Put the name, first skipping a leading slash. + */ +static int +put_name_skip_slash(struct mbchain *mbp, struct mbchain *name_mbp) +{ + mblk_t *m; + + if (name_mbp == NULL) + return (0); + m = name_mbp->mb_top; + if (m == NULL) + return (0); + + /* Use a dup of the message to leave the passed one untouched. */ + m = dupmsg(m); + if (m == NULL) + return (ENOSR); + + if (MBLKL(m) >= 2 && + m->b_rptr[0] == '\\' && + m->b_rptr[1] == '\0') + m->b_rptr += 2; + + return (mb_put_mbuf(mbp, m)); +} + +/* + * Modern create/open of file or directory. + * + * The passed name is a full path relative to the share root. + * Callers prepare paths with a leading slash (backslash) + * because that's what SMB1 expected. SMB2 does not allow the + * leading slash here. To make life simpler for callers skip a + * leading slash here. That allows callers use use common logic + * for building paths without needing to know if the connection + * is using SMB1 or SMB2 (just build paths with a leading slash). + */ +int +smb2_smb_ntcreate( + struct smb_share *ssp, + struct mbchain *name_mb, + struct mbchain *cctx_in, + struct mdchain *cctx_out, + uint32_t cr_flags, /* create flags */ + uint32_t req_acc, /* requested access */ + uint32_t efa, /* ext. file attrs (DOS attr +) */ + uint32_t share_acc, + uint32_t open_disp, /* open disposition */ + uint32_t createopt, /* NTCREATEX_OPTIONS_ */ + uint32_t impersonate, /* NTCREATEX_IMPERSONATION_... */ + struct smb_cred *scrp, + smb2fid_t *fidp, /* returned FID */ + uint32_t *cr_act_p, /* optional create action */ + struct smbfattr *fap) /* optional attributes */ +{ + struct smbfattr fa; + struct smb_rq *rqp; + struct mbchain *mbp; + struct mdchain *mdp; + uint16_t *name_offp; + uint16_t *name_lenp; + uint32_t *cctx_offp; + uint32_t *cctx_lenp; + uint32_t rcc_off, rcc_len; + smb2fid_t smb2_fid; + uint64_t llongint; + uint32_t longint, createact; + uint_t off, len; + int error; + uint16_t StructSize = 57; // [MS-SMB2] + + bzero(&fa, sizeof (fa)); + + error = smb_rq_alloc(SSTOCP(ssp), SMB2_CREATE, scrp, &rqp); + if (error) + return (error); + + /* + * Todo: Assemble creat contexts (if needed) + * into an mbchain. + */ + + /* + * Build the SMB 2/3 Create Request + */ + smb_rq_getrequest(rqp, &mbp); + mb_put_uint16le(mbp, StructSize); + mb_put_uint8(mbp, 0); /* Security flags */ + mb_put_uint8(mbp, SMB2_OPLOCK_LEVEL_NONE); /* Oplock level */ + mb_put_uint32le(mbp, impersonate); /* Impersonation Level */ + mb_put_uint64le(mbp, cr_flags); + mb_put_uint64le(mbp, 0); /* Reserved */ + mb_put_uint32le(mbp, req_acc); + mb_put_uint32le(mbp, efa); /* File attributes */ + mb_put_uint32le(mbp, share_acc); /* Share access */ + mb_put_uint32le(mbp, open_disp); /* Create disposition */ + mb_put_uint32le(mbp, createopt); /* Create options */ + + name_offp = mb_reserve(mbp, 2); /* Name offset */ + name_lenp = mb_reserve(mbp, 2); /* Name len */ + + cctx_offp = mb_reserve(mbp, 4); /* Context offset */ + cctx_lenp = mb_reserve(mbp, 4); /* Context len */ + + /* + * Put the file name, which is provided in an mbchain. + * If there's a leading slash, skip it (see above). + */ + off = mbp->mb_count; + *name_offp = htoles((uint16_t)off); + error = put_name_skip_slash(mbp, name_mb); + if (error) + goto out; + len = mbp->mb_count - off; + *name_lenp = htoles((uint16_t)len); + + /* + * Now the create contexts (if provided) + */ + if (cctx_in != NULL) { + off = mbp->mb_count; + *cctx_offp = htolel((uint32_t)off); + mb_put_mbchain(mbp, cctx_in); + len = mbp->mb_count - off; + *cctx_lenp = htolel((uint32_t)len); + } else { + *cctx_offp = 0; + *cctx_lenp = 0; + } + + /* + * If we didn't put any variable-sized data, we'll have + * put exactly 56 bytes of data, and we need to pad out + * this request to the 57 bytes StructSize indicated. + */ + if (mbp->mb_count < (StructSize + SMB2_HDRLEN)) + mb_put_uint8(mbp, 0); + + /* + * Don't want to risk missing a successful + * open response, or we could "leak" FIDs. + */ + rqp->sr_flags |= SMBR_NOINTR_RECV; + error = smb2_rq_simple_timed(rqp, smb2_timo_open); + if (error) + goto out; + + /* + * Parse SMB 2/3 Create Response + */ + smb_rq_getreply(rqp, &mdp); + + /* Check structure size is 89 */ + error = md_get_uint16le(mdp, &StructSize); + if (StructSize != 89) { + error = EBADRPC; + goto out; + } + + md_get_uint8(mdp, NULL); /* oplock lvl granted */ + md_get_uint8(mdp, NULL); /* mbz */ + md_get_uint32le(mdp, &createact); /* create_action */ + md_get_uint64le(mdp, &llongint); /* creation time */ + smb_time_NT2local(llongint, &fa.fa_createtime); + md_get_uint64le(mdp, &llongint); /* access time */ + smb_time_NT2local(llongint, &fa.fa_atime); + md_get_uint64le(mdp, &llongint); /* write time */ + smb_time_NT2local(llongint, &fa.fa_mtime); + md_get_uint64le(mdp, &llongint); /* change time */ + smb_time_NT2local(llongint, &fa.fa_ctime); + md_get_uint64le(mdp, &llongint); /* allocation size */ + fa.fa_allocsz = llongint; + md_get_uint64le(mdp, &llongint); /* EOF position */ + fa.fa_size = llongint; + md_get_uint32le(mdp, &longint); /* attributes */ + fa.fa_attr = longint; + md_get_uint32le(mdp, NULL); /* reserved */ + + /* Get SMB 2/3 File ID and create user fid to return */ + md_get_uint64le(mdp, &smb2_fid.fid_persistent); + error = md_get_uint64le(mdp, &smb2_fid.fid_volatile); + if (error) + goto out; + + /* Get Context Offset */ + error = md_get_uint32le(mdp, &rcc_off); + if (error) + goto out; + /* Get Context Length */ + error = md_get_uint32le(mdp, &rcc_len); + if (error) + goto out; + + /* + * If the caller wants the returned create contexts, parse. + * Context offset is from the beginning of SMB 2/3 Header + * Calculate how much further we have to go to get to it. + * Current offset is: SMB2_HDRLEN + 88 + */ + if (rcc_len != 0) { + int skip = (int)rcc_off - (SMB2_HDRLEN + 88); + if (skip < 0) { + error = EBADRPC; + goto out; + } + if (skip > 0) { + md_get_mem(mdp, NULL, skip, MB_MSYSTEM); + } + if (cctx_out != NULL) { + mblk_t *m = NULL; + error = md_get_mbuf(mdp, rcc_len, &m); + if (error) + goto out; + md_initm(cctx_out, m); + } + } + +out: + smb_rq_done(rqp); + if (error) + return (error); + + *fidp = smb2_fid; + if (cr_act_p) + *cr_act_p = createact; + if (fap) + *fap = fa; /* struct copy */ + + return (0); +} + +int +smb2_smb_close(struct smb_share *ssp, smb2fid_t *fid, struct smb_cred *scrp) +{ + struct smb_rq *rqp; + struct mbchain *mbp; + int error; + + error = smb_rq_alloc(SSTOCP(ssp), SMB2_CLOSE, scrp, &rqp); + if (error) + return (error); + + /* + * Build the SMB 2/3 Close Request + */ + smb_rq_getrequest(rqp, &mbp); + mb_put_uint16le(mbp, 24); /* Struct size */ + mb_put_uint16le(mbp, 0); /* Flags */ + mb_put_uint32le(mbp, 0); /* Reserved */ + + mb_put_uint64le(mbp, fid->fid_persistent); + mb_put_uint64le(mbp, fid->fid_volatile); + + /* Make sure we send, but only if already connected */ + rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT); + error = smb2_rq_simple(rqp); + smb_rq_done(rqp); + return (error); +} + +int +smb2_smb_ioctl( + struct smb_share *ssp, + smb2fid_t *fid, + struct mbchain *data_in, + struct mdchain *data_out, + uint32_t *data_out_sz, /* max / returned */ + uint32_t ctl_code, + struct smb_cred *scrp) +{ + struct smb_rq *rqp; + struct mbchain *mbp; + struct mdchain *mdp; + uint32_t *data_in_offp; + uint32_t *data_in_lenp; + uint32_t data_out_off; + uint32_t data_out_len; + uint16_t length = 0; + uint_t off, len; + int error; + + error = smb_rq_alloc(SSTOCP(ssp), SMB2_IOCTL, scrp, &rqp); + if (error) + return (error); + + /* + * Build the SMB 2 IOCTL Request + */ + smb_rq_getrequest(rqp, &mbp); + mb_put_uint16le(mbp, 57); /* Struct size */ + mb_put_uint16le(mbp, 0); /* Reserved */ + mb_put_uint32le(mbp, ctl_code); + + mb_put_uint64le(mbp, fid->fid_persistent); + mb_put_uint64le(mbp, fid->fid_volatile); + + data_in_offp = mb_reserve(mbp, 4); + data_in_lenp = mb_reserve(mbp, 4); + mb_put_uint32le(mbp, 0); /* Max input resp */ + + mb_put_uint32le(mbp, 0); /* Output offset */ + mb_put_uint32le(mbp, 0); /* Output count */ + mb_put_uint32le(mbp, *data_out_sz); + + mb_put_uint32le(mbp, SMB2_IOCTL_IS_FSCTL); /* Flags */ + mb_put_uint32le(mbp, 0); /* Reserved2 */ + + /* + * Now data_in (if provided) + */ + if (data_in != NULL) { + off = mbp->mb_count; + *data_in_offp = htolel((uint32_t)off); + mb_put_mbchain(mbp, data_in); + len = mbp->mb_count - off; + *data_in_lenp = htolel((uint32_t)len); + } else { + *data_in_offp = 0; + *data_in_lenp = 0; + } + + /* + * Run the request + */ + error = smb2_rq_simple_timed(rqp, smb2_timo_default); + if (error) + goto out; + + /* + * Parse SMB 2 Ioctl Response + */ + smb_rq_getreply(rqp, &mdp); + + /* Check structure size is 49 */ + md_get_uint16le(mdp, &length); + if (length != 49) { + error = EBADRPC; + goto out; + } + md_get_uint16le(mdp, NULL); /* reserved */ + md_get_uint32le(mdp, NULL); /* Get CtlCode */ + md_get_uint64le(mdp, NULL); /* fid_persistent */ + md_get_uint64le(mdp, NULL); /* fid_volatile */ + md_get_uint32le(mdp, NULL); /* Get Input offset */ + md_get_uint32le(mdp, NULL); /* Get Input count */ + + error = md_get_uint32le(mdp, &data_out_off); + if (error) + goto out; + error = md_get_uint32le(mdp, &data_out_len); + if (error) + goto out; + + md_get_uint32le(mdp, NULL); /* Flags */ + md_get_uint32le(mdp, NULL); /* reserved */ + + /* + * If the caller wants the ioctl output data, parse. + * Current offset is: SMB2_HDRLEN + 48 + * Always return the received length. + */ + *data_out_sz = data_out_len; + if (data_out_len != 0) { + int skip = (int)data_out_off - (SMB2_HDRLEN + 48); + if (skip < 0) { + error = EBADRPC; + goto out; + } + if (skip > 0) { + md_get_mem(mdp, NULL, skip, MB_MSYSTEM); + } + if (data_out != NULL) { + mblk_t *m = NULL; + error = md_get_mbuf(mdp, data_out_len, &m); + if (error) + goto out; + md_initm(data_out, m); + } + } + +out: + smb_rq_done(rqp); + + return (error); +} + +int +smb2_smb_read(smb_fh_t *fhp, uint32_t *lenp, + uio_t *uiop, smb_cred_t *scred, int timo) +{ + struct smb_share *ssp = FHTOSS(fhp); + struct smb_rq *rqp; + struct mbchain *mbp; + struct mdchain *mdp; + int error; + uint64_t off64 = uiop->uio_loffset; + uint32_t rlen; + uint16_t length = 0; + uint8_t data_offset; + + error = smb_rq_alloc(SSTOCP(ssp), SMB2_READ, scred, &rqp); + if (error) + return (error); + + /* + * Build the SMB 2 Read Request + */ + smb_rq_getrequest(rqp, &mbp); + mb_put_uint16le(mbp, 49); /* Struct size */ + mb_put_uint16le(mbp, 0); /* Padding and Reserved */ + + mb_put_uint32le(mbp, *lenp); /* Length of read */ + mb_put_uint64le(mbp, off64); /* Offset */ + + mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent); + mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile); + + mb_put_uint32le(mbp, 1); /* MinCount */ + /* (only indicates blocking) */ + + mb_put_uint32le(mbp, 0); /* Channel */ + mb_put_uint32le(mbp, 0); /* Remaining */ + mb_put_uint32le(mbp, 0); /* Channel offset/len */ + mb_put_uint8(mbp, 0); /* data "blob" (pad) */ + + if (timo == 0) + timo = smb2_timo_read; + error = smb2_rq_simple_timed(rqp, timo); + if (error) + goto out; + + /* + * Parse SMB 2 Read Response + */ + smb_rq_getreply(rqp, &mdp); + + /* Check structure size is 17 */ + md_get_uint16le(mdp, &length); + if (length != 17) { + error = EBADRPC; + goto out; + } + md_get_uint8(mdp, &data_offset); + md_get_uint8(mdp, NULL); /* reserved */ + + /* Get Data Length read */ + error = md_get_uint32le(mdp, &rlen); + if (error) + goto out; + + md_get_uint32le(mdp, NULL); /* Data Remaining (always 0) */ + md_get_uint32le(mdp, NULL); /* Get Reserved2 (always 0) */ + + /* + * Data offset is from the beginning of SMB 2/3 Header + * Calculate how much further we have to go to get to it. + */ + if (data_offset < (SMB2_HDRLEN + 16)) { + error = EBADRPC; + goto out; + } + if (data_offset > (SMB2_HDRLEN + 16)) { + int skip = data_offset - (SMB2_HDRLEN + 16); + md_get_mem(mdp, NULL, skip, MB_MSYSTEM); + } + + /* + * Get the data + */ + if (rlen == 0) { + *lenp = rlen; + goto out; + } + /* paranoid */ + if (rlen > *lenp) { + SMBSDEBUG("bad server! rlen %d, len %d\n", + rlen, *lenp); + rlen = *lenp; + } + + error = md_get_uio(mdp, uiop, rlen); + if (error) + goto out; + + /* Success */ + *lenp = rlen; + +out: + smb_rq_done(rqp); + return (error); +} + +int +smb2_smb_write(smb_fh_t *fhp, uint32_t *lenp, + uio_t *uiop, smb_cred_t *scred, int timo) +{ + struct smb_share *ssp = FHTOSS(fhp); + struct smb_rq *rqp; + struct mbchain *mbp; + struct mdchain *mdp; + int error; + uint64_t off64 = uiop->uio_loffset; + uint32_t rlen; + uint16_t data_offset; + uint16_t length = 0; + + error = smb_rq_alloc(SSTOCP(ssp), SMB2_WRITE, scred, &rqp); + if (error) + return (error); + + /* + * Build the SMB 2 Write Request + */ + smb_rq_getrequest(rqp, &mbp); + mb_put_uint16le(mbp, 49); /* Struct size */ + data_offset = SMB2_HDRLEN + 48; + mb_put_uint16le(mbp, data_offset); /* Data Offset */ + mb_put_uint32le(mbp, *lenp); /* Length of write */ + mb_put_uint64le(mbp, off64); /* Offset */ + + mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent); + mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile); + + mb_put_uint32le(mbp, 0); /* Channel */ + mb_put_uint32le(mbp, 0); /* Remaining */ + mb_put_uint32le(mbp, 0); /* Channel offset/len */ + mb_put_uint32le(mbp, 0); /* Write flags */ + + error = mb_put_uio(mbp, uiop, *lenp); + if (error) + goto out; + + if (timo == 0) + timo = smb2_timo_write; + error = smb2_rq_simple_timed(rqp, timo); + if (error) + goto out; + + /* + * Parse SMB 2/3 Write Response + */ + smb_rq_getreply(rqp, &mdp); + + /* Check structure size is 17 */ + md_get_uint16le(mdp, &length); + if (length != 17) { + error = EBADRPC; + goto out; + } + + md_get_uint16le(mdp, NULL); /* Get Reserved */ + + /* Get Data Length written */ + error = md_get_uint32le(mdp, &rlen); + if (error) + goto out; + + /* Get Data Remaining (always 0) */ + md_get_uint32le(mdp, NULL); + + /* Get Reserved2 (always 0) */ + md_get_uint32le(mdp, NULL); + + /* Success */ + *lenp = rlen; + +out: + smb_rq_done(rqp); + return (error); +} + +/* + * Note: the IOD calls this, so this request must not wait for + * connection state changes, etc. (uses smb2_rq_internal) + */ +int +smb2_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), SMB2_ECHO, scred, &rqp); + if (error) + return (error); + + /* + * Build the SMB 2 Echo Request + */ + smb_rq_getrequest(rqp, &mbp); + mb_put_uint16le(mbp, 4); /* Struct size */ + mb_put_uint16le(mbp, 0); /* Reserved */ + + rqp->sr_flags |= SMBR_NORECONNECT; + error = smb2_rq_internal(rqp, timo); + + smb_rq_done(rqp); + return (error); +} diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c index 41405c314d..398be59709 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c @@ -63,6 +63,7 @@ #include #include +#include #include #include #include @@ -82,6 +83,9 @@ 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); +static void smb_fh_free(struct smb_connobj *cp); +static void smb_fh_gone(struct smb_connobj *cp); + int smb_sm_init(void) { @@ -183,6 +187,16 @@ smb_co_rele(struct smb_connobj *co) int old_flags; SMB_CO_LOCK(co); + + /* + * When VC usecount goes from 2 to 1, signal the iod_idle CV. + * It's unfortunate to have object type-specific logic here, + * but it's hard to do this anywhere else. + */ + if (co->co_level == SMBL_VC && co->co_usecount == 2) { + smb_vc_t *vcp = CPTOVC(co); + cv_signal(&vcp->iod_idle); + } if (co->co_usecount > 1) { co->co_usecount--; SMB_CO_UNLOCK(co); @@ -370,9 +384,9 @@ smb_vc_free(struct smb_connobj *cp) if (vcp->vc_ssnkey != NULL) kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen); + cv_destroy(&vcp->iod_muxwait); cv_destroy(&vcp->iod_idle); 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)); @@ -396,9 +410,9 @@ smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp) vcp->vc_co.co_gone = smb_vc_gone; cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL); - sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL); rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL); cv_init(&vcp->iod_idle, objtype, CV_DRIVER, NULL); + cv_init(&vcp->iod_muxwait, objtype, CV_DRIVER, NULL); /* Expanded TAILQ_HEAD_INITIALIZER */ vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first; @@ -617,10 +631,14 @@ smb_share_gone(struct smb_connobj *cp) { struct smb_cred scred; struct smb_share *ssp = CPTOSS(cp); + smb_vc_t *vcp = SSTOVC(ssp); smb_credinit(&scred, NULL); smb_iod_shutdown_share(ssp); - (void) smb_smb_treedisconnect(ssp, &scred); + if (vcp->vc_flags & SMBV_SMB2) + (void) smb2_smb_treedisconnect(ssp, &scred); + else + (void) smb_smb_treedisconnect(ssp, &scred); smb_credrele(&scred); } @@ -660,6 +678,7 @@ smb_share_create(smbioc_tcon_t *tcon, struct smb_vc *vcp, cv_init(&ssp->ss_conn_done, objtype, CV_DRIVER, NULL); ssp->ss_tid = SMB_TID_UNKNOWN; + ssp->ss2_tree_id = SMB2_TID_UNKNOWN; bcopy(&tcon->tc_sh, &ssp->ss_ioc, sizeof (smbioc_oshare_t)); @@ -775,6 +794,7 @@ smb_share_invalidate(struct smb_share *ssp) int smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred) { + smb_vc_t *vcp = SSTOVC(ssp); clock_t tmo; int error; @@ -818,7 +838,10 @@ smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred) * and ss_flags |= SMBS_CONNECTED; */ SMB_SS_UNLOCK(ssp); - error = smb_smb_treeconnect(ssp, scred); + if (vcp->vc_flags & SMBV_SMB2) + error = smb2_smb_treeconnect(ssp, scred); + else + error = smb_smb_treeconnect(ssp, scred); SMB_SS_LOCK(ssp); ssp->ss_flags &= ~SMBS_RECONNECTING; @@ -833,6 +856,114 @@ out: return (error); } +/* + * File handle level functions + */ + +void +smb_fh_hold(struct smb_fh *fhp) +{ + smb_co_hold(FHTOCP(fhp)); +} + +void +smb_fh_rele(struct smb_fh *fhp) +{ + smb_co_rele(FHTOCP(fhp)); +} + +void +smb_fh_close(struct smb_fh *fhp) +{ + smb_co_kill(FHTOCP(fhp)); +} + +/* + * Normally called via smb_fh_rele() + * after co_usecount drops to zero. + * Also called via: smb_fh_kill() + */ +static void +smb_fh_gone(struct smb_connobj *cp) +{ + struct smb_cred scred; + struct smb_fh *fhp = CPTOFH(cp); + smb_share_t *ssp = FHTOSS(fhp); + int err; + + if ((fhp->fh_flags & SMBFH_VALID) == 0) + return; + + /* + * We have no durable handles (yet) so if there has been a + * reconnect, don't bother to close this handle. + */ + if (fhp->fh_vcgenid != ssp->ss_vcgenid) + return; + + smb_credinit(&scred, NULL); + err = smb_smb_close(ssp, fhp, &scred); + smb_credrele(&scred); + if (err) { + SMBSDEBUG("close err=%d\n", err); + } +} + +/* + * Normally called via smb_fh_rele() + * after co_usecount drops to zero. + */ +static void +smb_fh_free(struct smb_connobj *cp) +{ + struct smb_fh *fhp = CPTOFH(cp); + + smb_co_done(FHTOCP(fhp)); + kmem_free(fhp, sizeof (*fhp)); +} + +/* + * Allocate fh structure and attach it to the given share. + * Share expected to be locked on entry. + */ +/*ARGSUSED*/ +int +smb_fh_create(smb_share_t *ssp, struct smb_fh **fhpp) +{ + static char objtype[] = "smb_fh"; + struct smb_fh *fhp; + + fhp = kmem_zalloc(sizeof (struct smb_fh), KM_SLEEP); + smb_co_init(FHTOCP(fhp), SMBL_FH, objtype); + fhp->fh_co.co_free = smb_fh_free; + fhp->fh_co.co_gone = smb_fh_gone; + + SMB_SS_LOCK(ssp); + if ((ssp->ss_flags & SMBS_GONE) != 0) { + SMB_SS_UNLOCK(ssp); + smb_fh_free(FHTOCP(fhp)); + return (ENOTCONN); + } + + smb_co_addchild(SSTOCP(ssp), FHTOCP(fhp)); + *fhpp = fhp; + SMB_SS_UNLOCK(ssp); + + return (0); +} + +void +smb_fh_opened(struct smb_fh *fhp) +{ + smb_share_t *ssp = FHTOSS(fhp); + + SMB_FH_LOCK(fhp); + fhp->fh_vcgenid = ssp->ss_vcgenid; + fhp->fh_flags |= SMBFH_VALID; + SMB_FH_UNLOCK(fhp); +} + + /* * Solaris zones support */ diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h index 7b2b6a4690..d0a8a1dca0 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h @@ -36,6 +36,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * + * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved. * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ @@ -47,6 +48,7 @@ #include /* for SLIST below */ #include #include +#include "smb_signing.h" /* * Credentials of user/process for processing in the connection procedures @@ -66,7 +68,10 @@ typedef struct smb_cred { */ #define SMBV_UNICODE 0x0040 /* conn configured to use Unicode */ #define SMBV_EXT_SEC 0x0080 /* conn to use extended security */ -#define SMBV_WILL_SIGN 0x0100 /* negotiated signing */ +#define SMBV_SIGNING 0x0100 /* negotiated signing */ +#define SMBV_SMB2 0x0200 /* VC using SMB 2 or 3 */ +#define SMBV_HAS_FILEIDS 0x0400 /* Use File IDs for hash and inode numbers */ +#define SMBV_NO_WRITE_THRU 0x0800 /* Can't use ... */ /* * Note: the common "obj" level uses this GONE flag by @@ -87,6 +92,16 @@ typedef struct smb_cred { */ #define SMBS_GONE SMBO_GONE +/* + * bits in smb_fh fh_flags (a.k.a. ss_co.co_flags) + */ +#define SMBFH_VALID 0x0002 /* FID is valid */ +/* + * Note: the common "obj" level uses this GONE flag by + * the name SMBO_GONE. Keep this alias as a reminder. + */ +#define SMBFH_GONE SMBO_GONE + struct smb_rq; /* This declares struct smb_rqhead */ TAILQ_HEAD(smb_rqhead, smb_rq); @@ -139,9 +154,12 @@ typedef struct smb_connobj smb_connobj_t; /* * "Level" in the connection object hierarchy */ -#define SMBL_SM 0 -#define SMBL_VC 1 -#define SMBL_SHARE 2 +enum smbco_level { + SMBL_SM = 0, + SMBL_VC = 1, + SMBL_SHARE = 2, + SMBL_FH = 3 +}; /* * SMB1 Negotiated protocol parameters @@ -157,6 +175,16 @@ struct smb_sopt { uint32_t sv_maxraw; /* maximum raw-buffer size */ uint32_t sv_skey; /* session key */ uint32_t sv_caps; /* capabilites SMB_CAP_ */ + + /* SMB2+ fields */ + uint32_t sv2_sessflags; /* final session setup reply flags */ + uint16_t sv2_dialect; /* dialect (non zero for SMB 2/3 */ + uint32_t sv2_capabilities; /* capabilities */ + uint32_t sv2_maxtransact; /* max transact size */ + uint32_t sv2_maxread; /* max read size */ + uint32_t sv2_maxwrite; /* max write size */ + uint8_t sv2_guid[16]; /* GUID */ + uint16_t sv2_security_mode; /* security mode */ }; typedef struct smb_sopt smb_sopt_t; @@ -197,18 +225,28 @@ typedef struct smb_vc { int vc_ssnkeylen; /* session key length */ uint8_t *vc_mackey; /* MAC key buffer */ uint8_t *vc_ssnkey; /* session key buffer */ + smb_sign_mech_t vc_signmech; - ksema_t vc_sendlock; struct smb_tran_desc *vc_tdesc; /* transport ops. vector */ void *vc_tdata; /* transport control block */ + /* SMB2+ fields */ + uint64_t vc2_oldest_message_id; + uint64_t vc2_next_message_id; + uint64_t vc2_limit_message_id; + uint64_t vc2_session_id; /* session id */ + uint64_t vc2_prev_session_id; /* for reconnect */ + uint32_t vc2_lease_key; /* lease key gen */ + kcondvar_t iod_idle; /* IOD thread idle CV */ krwlock_t iod_rqlock; /* iod_rqlist */ - struct smb_rqhead iod_rqlist; /* list of outstanding reqs */ + struct smb_rqhead iod_rqlist; /* list of active reqs */ struct _kthread *iod_thr; /* the IOD (reader) thread */ int iod_flags; /* see SMBIOD_* below */ - int iod_newrq; /* send needed (iod_rqlock) */ - int iod_muxfull; /* maxmux limit reached */ + uint_t iod_muxcnt; /* num. active requests */ + uint_t iod_muxwant; /* waiting to be active */ + kcondvar_t iod_muxwait; + boolean_t iod_noresp; /* Logged "not responding" */ smb_iods_t vc_iods; smb_sopt_t vc_sopt; @@ -225,13 +263,16 @@ typedef struct smb_vc { /* defines for members in vc_ssn */ #define vc_owner vc_ssn.ssn_owner +#define vc_vopt vc_ssn.ssn_vopt +#define vc_minver vc_ssn.ssn_minver +#define vc_maxver vc_ssn.ssn_maxver #define vc_srvname vc_ssn.ssn_srvname #define vc_srvaddr vc_ssn.ssn_id.id_srvaddr #define vc_domain vc_ssn.ssn_id.id_domain #define vc_username vc_ssn.ssn_id.id_user -#define vc_vopt vc_ssn.ssn_vopt /* defines for members in vc_work */ +#define vc_cl_guid vc_work.wk_cl_guid /* defines for members in vc_sopt ? */ #define vc_maxmux vc_sopt.sv_maxmux @@ -250,7 +291,12 @@ typedef struct smb_vc { #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) +#define CPTOVC(cp) ((struct smb_vc *)((void *)(cp))) +#define VCTOCP(vcp) (&(vcp)->vc_co) + +#define SMB_UNICODE_STRINGS(vcp) \ + (((vcp)->vc_flags & SMBV_SMB2) != 0 || \ + ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) != 0) /* Bits in iod_flags */ #define SMBIOD_RUNNING 0x0001 @@ -268,6 +314,9 @@ typedef struct smb_share { int ss_vcgenid; /* check VC generation ID */ uint16_t ss_tid; /* TID */ uint16_t ss_options; /* option support bits */ + uint32_t ss2_tree_id; + uint32_t ss2_share_flags; + uint32_t ss2_share_caps; smbioc_oshare_t ss_ioc; } smb_share_t; @@ -282,27 +331,47 @@ typedef struct smb_share { #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 *)((void *)(cp))) -#define VCTOCP(vcp) (&(vcp)->vc_co) - #define CPTOSS(cp) ((struct smb_share *)((void *)(cp))) -#define SSTOVC(ssp) CPTOVC(((ssp)->ss_co.co_parent)) #define SSTOCP(ssp) (&(ssp)->ss_co) +#define SSTOVC(ssp) CPTOVC(((ssp)->ss_co.co_parent)) + +typedef struct smb2fid { + uint64_t fid_persistent; + uint64_t fid_volatile; +} smb2fid_t; + +/* + * smb_fh struct describes an open file handle under some share. + */ +typedef struct smb_fh { + struct smb_connobj fh_co; /* keep first! See CPTOSS */ + int fh_vcgenid; /* check VC generation ID */ + uint32_t fh_rights; /* granted access */ + smb2fid_t fh_fid2; + uint16_t fh_fid1; +} smb_fh_t; + +#define fh_lock fh_co.co_lock +#define fh_flags fh_co.co_flags + +#define SMB_FH_LOCK(fhp) mutex_enter(&(fhp)->fh_lock) +#define SMB_FH_UNLOCK(fhp) mutex_exit(&(fhp)->fh_lock) + +#define CPTOFH(cp) ((struct smb_fh *)((void *)(cp))) +#define FHTOCP(fhp) (&(fhp)->fh_co) +#define FHTOSS(fhp) CPTOSS(((fhp)->fh_co.co_parent)) /* * Call-back operations vector, so the netsmb module * can notify smbfs about events affecting mounts. * Installed in netsmb after smbfs loads. + * Note: smbfs only uses the fscb_discon hook. */ typedef struct smb_fscb { /* Called when the VC has disconnected. */ void (*fscb_disconn)(smb_share_t *); /* Called when the VC has reconnected. */ void (*fscb_connect)(smb_share_t *); - /* Called when the server becomes unresponsive. */ - void (*fscb_down)(smb_share_t *); - /* Called when the server is responding again. */ - void (*fscb_up)(smb_share_t *); } smb_fscb_t; /* Install the above vector, or pass NULL to clear it. */ void smb_fscb_set(smb_fscb_t *); @@ -315,14 +384,14 @@ typedef struct smb_dev { kmutex_t sd_lock; struct smb_vc *sd_vc; /* Reference to VC */ struct smb_share *sd_share; /* Reference to share if any */ + struct smb_fh *sd_fh; /* Reference to FH, if any */ int sd_level; /* SMBL_VC, ... */ int sd_vcgenid; /* Generation of share or VC */ int sd_poll; /* Future use */ int sd_flags; /* State of connection */ -#define NSMBFL_OPEN 0x0001 -#define NSMBFL_IOD 0x0002 -#define NSMBFL_IOCTL 0x0004 - int sd_smbfid; /* library read/write */ +#define NSMBFL_OPEN 0x0001 /* Device minor is open */ +#define NSMBFL_IOD 0x0004 /* Open by IOD */ +#define NSMBFL_IOCTL 0x0010 /* Serialize ioctl calls */ zoneid_t zoneid; /* Zone id */ } smb_dev_t; @@ -370,9 +439,11 @@ int smb_pkey_ioctl(int, intptr_t, int, cred_t *); int smb_iod_create(smb_vc_t *vcp); int smb_iod_destroy(smb_vc_t *vcp); void smb_iod_disconnect(smb_vc_t *vcp); -int smb_iod_addrq(struct smb_rq *rqp); -int smb_iod_multirq(struct smb_rq *rqp); +int smb2_iod_addrq(struct smb_rq *rqp); +int smb1_iod_addrq(struct smb_rq *rqp); +int smb1_iod_multirq(struct smb_rq *rqp); int smb_iod_waitrq(struct smb_rq *rqp); +int smb_iod_waitrq_int(struct smb_rq *rqp); void smb_iod_removerq(struct smb_rq *rqp); int smb_iod_sendrecv(struct smb_rq *, int); void smb_iod_shutdown_share(smb_share_t *ssp); @@ -380,7 +451,7 @@ void smb_iod_shutdown_share(smb_share_t *ssp); void smb_iod_sendall(smb_vc_t *); int smb_iod_recvall(smb_vc_t *, boolean_t); -int nsmb_iod_connect(smb_vc_t *vcp); +int nsmb_iod_connect(smb_vc_t *vcp, cred_t *cr); int nsmb_iod_negotiate(smb_vc_t *vcp, cred_t *cr); int nsmb_iod_ssnsetup(smb_vc_t *vcp, cred_t *cr); int smb_iod_vc_work(smb_vc_t *, int, cred_t *); @@ -426,4 +497,13 @@ void smb_share_kill(smb_share_t *ssp); void smb_share_invalidate(smb_share_t *ssp); int smb_share_tcon(smb_share_t *, smb_cred_t *); +/* + * File handle level functions + */ +int smb_fh_create(smb_share_t *ssp, struct smb_fh **fhpp); +void smb_fh_opened(struct smb_fh *fhp); +void smb_fh_close(struct smb_fh *fhp); +void smb_fh_hold(struct smb_fh *fhp); +void smb_fh_rele(struct smb_fh *fhp); + #endif /* _SMB_CONN_H */ diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c index b2788bb194..3f00ec24ed 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c @@ -69,6 +69,7 @@ #include /* for "htoles()" */ #include +#include #include #include #include @@ -196,12 +197,6 @@ _init(void) /* Initialize password Key chain DB. */ smb_pkey_init(); - /* Time conversion stuff. */ - smb_time_init(); - - /* Initialize crypto mechanisms. */ - smb_crypto_mech_init(); - #ifdef _KERNEL zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown, nsmb_zone_destroy); @@ -259,9 +254,6 @@ _fini(void) (void) zone_key_delete(nsmb_zone_key); #endif /* _KERNEL */ - /* Time conversion stuff. */ - smb_time_fini(); - /* Destroy password Key chain DB. */ smb_pkey_fini(); @@ -498,7 +490,6 @@ found: *dev = makedevice(nsmb_major, m); mutex_exit(&dev_lck); - sdp->sd_smbfid = -1; sdp->sd_flags |= NSMBFL_OPEN; sdp->zoneid = crgetzoneid(cr); mutex_init(&sdp->sd_lock, NULL, MUTEX_DRIVER, NULL); @@ -536,14 +527,17 @@ nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr) return (err); } +/*ARGSUSED*/ static int nsmb_close2(smb_dev_t *sdp, cred_t *cr) { struct smb_vc *vcp; struct smb_share *ssp; + struct smb_fh *fhp; - if (sdp->sd_smbfid != -1) - (void) smb_usr_closefh(sdp, cr); + fhp = sdp->sd_fh; + if (fhp != NULL) + smb_fh_rele(fhp); ssp = sdp->sd_share; if (ssp != NULL) diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c index 4c547df25b..48c8ef591d 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c @@ -36,6 +36,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * + * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved. * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ @@ -69,25 +70,26 @@ #include #include +#include #include #include +#include #include #include #include /* - * SMB messages are up to 64K. - * Let's leave room for two. + * SMB messages are up to 64K. Let's leave room for two. + * If we negotiate up to SMB2, increase these. XXX todo */ static int smb_tcpsndbuf = 0x20000; static int smb_tcprcvbuf = 0x20000; static int smb_connect_timeout = 10; /* seconds */ -int smb_iod_send_echo(smb_vc_t *); - -#ifdef _FAKE_KERNEL -extern void tsignal(kthread_t *, int); -#endif +static int smb1_iod_process(smb_vc_t *, mblk_t *); +static int smb2_iod_process(smb_vc_t *, mblk_t *); +static int smb_iod_send_echo(smb_vc_t *, cred_t *cr); +static int smb_iod_logoff(struct smb_vc *vcp, cred_t *cr); /* * This is set/cleared when smbfs loads/unloads @@ -107,7 +109,10 @@ smb_iod_share_disconnected(smb_share_t *ssp) smb_share_invalidate(ssp); - /* smbfs_dead() */ + /* + * This is the only fscb hook smbfs currently uses. + * Replaces smbfs_dead() from Darwin. + */ if (fscb && fscb->fscb_disconn) { fscb->fscb_disconn(ssp); } @@ -156,19 +161,22 @@ smb_iod_invrq(struct smb_vc *vcp) /* * Invalidate all outstanding requests for this connection + * Also wakeup iod_muxwant waiters. */ 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); + cv_broadcast(&vcp->iod_muxwait); } /* - * Called by smb_vc_rele, smb_vc_kill, and by the driver - * close entry point if the IOD closes its dev handle. + * Called by smb_vc_rele/smb_vc_kill on last ref, and by + * the driver close function if the IOD closes its minor. + * In those cases, the caller should be the IOD thread. * - * Forcibly kill the connection and IOD. + * Forcibly kill the connection. */ void smb_iod_disconnect(struct smb_vc *vcp) @@ -184,31 +192,29 @@ smb_iod_disconnect(struct smb_vc *vcp) } SMB_VC_UNLOCK(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. - */ SMB_TRAN_DISCONNECT(vcp); } /* * Send one request. * + * SMB1 only + * * Called by _addrq (for internal requests) * and _sendall (via _addrq, _multirq, _waitrq) + * Errors are reported via the smb_rq, using: + * smb_iod_rqprocessed(rqp, ...) */ -static int -smb_iod_sendrq(struct smb_rq *rqp) +static void +smb1_iod_sendrq(struct smb_rq *rqp) { struct smb_vc *vcp = rqp->sr_vc; mblk_t *m; int error; ASSERT(vcp); - ASSERT(SEMA_HELD(&vcp->vc_sendlock)); - ASSERT(RW_READ_HELD(&vcp->iod_rqlock)); + ASSERT(RW_WRITE_HELD(&vcp->iod_rqlock)); + ASSERT((vcp->vc_flags & SMBV_SMB2) == 0); /* * Internal requests are allowed in any state; @@ -217,101 +223,178 @@ smb_iod_sendrq(struct smb_rq *rqp) if ((rqp->sr_flags & SMBR_INTERNAL) == 0 && vcp->vc_state != SMBIOD_ST_VCACTIVE) { SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state); - return (ENOTCONN); + smb_iod_rqprocessed(rqp, ENOTCONN, SMBR_RESTART); + return; } /* - * On the first send, set the MID and (maybe) - * the signing sequence numbers. The increments - * here are serialized by vc_sendlock + * Overwrite the SMB header with the assigned MID and + * (if we're signing) sign it. */ - if (rqp->sr_sendcnt == 0) { + smb_rq_fillhdr(rqp); + if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) { + smb_rq_sign(rqp); + } - rqp->sr_mid = vcp->vc_next_mid++; + /* + * The transport send consumes the message and we'd + * prefer to keep a copy, so dupmsg() before sending. + */ + m = dupmsg(rqp->sr_rq.mb_top); + if (m == NULL) { + error = ENOBUFS; + goto fatal; + } - if (vcp->vc_mackey != NULL && (rqp->sr_rqflags2 & - SMB_FLAGS2_SECURITY_SIGNATURE) != 0) { - /* - * We're signing requests and verifying - * signatures on responses. Set the - * sequence numbers of the request and - * response here, used in smb_rq_verify. - * Note we have the signing flag during - * session setup but no key yet, and - * don't want sequence numbers there. - */ - rqp->sr_seqno = vcp->vc_next_seq++; - rqp->sr_rseqno = vcp->vc_next_seq++; - } +#ifdef DTRACE_PROBE2 + DTRACE_PROBE2(iod_sendrq, + (smb_rq_t *), rqp, (mblk_t *), m); +#endif - /* Fill in UID, TID, MID, etc. */ - smb_rq_fillhdr(rqp); + error = SMB_TRAN_SEND(vcp, m); + m = 0; /* consumed by SEND */ - /* - * Sign the message now that we're finally done - * filling in the SMB header fields, etc. - */ - if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) { - smb_rq_sign(rqp); - } + rqp->sr_lerror = error; + if (error == 0) { + SMBRQ_LOCK(rqp); + rqp->sr_flags |= SMBR_SENT; + rqp->sr_state = SMBRQ_SENT; + SMBRQ_UNLOCK(rqp); + return; } - if (rqp->sr_sendcnt++ >= 60/SMBSBTIMO) { /* one minute */ - smb_iod_rqprocessed(rqp, rqp->sr_lerror, SMBR_RESTART); + /* + * Transport send returned an error. + * Was it a fatal one? + */ + if (SMB_TRAN_FATAL(vcp, error)) { /* - * If all attempts to send a request failed, then - * something is seriously hosed. + * No further attempts should be made */ - return (ENOTCONN); + fatal: + SMBSDEBUG("TRAN_SEND returned fatal error %d\n", error); + smb_iod_rqprocessed(rqp, error, SMBR_RESTART); + return; } +} + +/* + * Send one request. + * + * SMB2 only + * + * Called by _addrq (for internal requests) + * and _sendall (via _addrq, _multirq, _waitrq) + * Errors are reported via the smb_rq, using: + * smb_iod_rqprocessed(rqp, ...) + */ +static void +smb2_iod_sendrq(struct smb_rq *rqp) +{ + struct smb_rq *c_rqp; /* compound */ + struct smb_vc *vcp = rqp->sr_vc; + mblk_t *top_m; + mblk_t *cur_m; + int error; + + ASSERT(vcp); + ASSERT(RW_WRITE_HELD(&vcp->iod_rqlock)); + ASSERT((vcp->vc_flags & SMBV_SMB2) != 0); /* - * 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); + * Internal requests are allowed in any state; + * otherwise should be active. */ - m = copymsg(rqp->sr_rq.mb_top); + if ((rqp->sr_flags & SMBR_INTERNAL) == 0 && + vcp->vc_state != SMBIOD_ST_VCACTIVE) { + SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state); + smb_iod_rqprocessed(rqp, ENOTCONN, SMBR_RESTART); + return; + } - DTRACE_PROBE2(smb_iod_sendrq, - (smb_rq_t *), rqp, (mblk_t *), m); - m_dumpm(m); + /* + * Overwrite the SMB header with the assigned MID and + * (if we're signing) sign it. If there are compounded + * requests after the top one, do those too. + */ + smb2_rq_fillhdr(rqp); + if (rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) { + smb2_rq_sign(rqp); + } + c_rqp = rqp->sr2_compound_next; + while (c_rqp != NULL) { + smb2_rq_fillhdr(c_rqp); + if (c_rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) { + smb2_rq_sign(c_rqp); + } + c_rqp = c_rqp->sr2_compound_next; + } - if (m != NULL) { - error = SMB_TRAN_SEND(vcp, m); - m = 0; /* consumed by SEND */ - } else + /* + * The transport send consumes the message and we'd + * prefer to keep a copy, so dupmsg() before sending. + * We also need this to build the compound message + * that we'll actually send. The message offset at + * the start of each compounded message should be + * eight-byte aligned. The caller preparing the + * compounded request has to take care of that + * before we get here and sign messages etc. + */ + top_m = dupmsg(rqp->sr_rq.mb_top); + if (top_m == NULL) { error = ENOBUFS; + goto fatal; + } + c_rqp = rqp->sr2_compound_next; + while (c_rqp != NULL) { + size_t len = msgdsize(top_m); + ASSERT((len & 7) == 0); + cur_m = dupmsg(c_rqp->sr_rq.mb_top); + if (cur_m == NULL) { + freemsg(top_m); + error = ENOBUFS; + goto fatal; + } + linkb(top_m, cur_m); + } + + DTRACE_PROBE2(iod_sendrq, + (smb_rq_t *), rqp, (mblk_t *), top_m); + + error = SMB_TRAN_SEND(vcp, top_m); + top_m = 0; /* consumed by SEND */ rqp->sr_lerror = error; 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); + return; } /* - * Check for fatal errors + * Transport send returned an error. + * Was it a fatal one? */ if (SMB_TRAN_FATAL(vcp, error)) { /* * No further attempts should be made */ + fatal: SMBSDEBUG("TRAN_SEND returned fatal error %d\n", error); - return (ENOTCONN); + smb_iod_rqprocessed(rqp, error, SMBR_RESTART); + return; } - if (error) - SMBSDEBUG("TRAN_SEND returned non-fatal error %d\n", error); - - return (0); } +/* + * Receive one NetBIOS (or NBT over TCP) message. If none have arrived, + * wait up to SMB_NBTIMO (15 sec.) for one to arrive, and then if still + * none have arrived, return ETIME. + */ static int -smb_iod_recv1(struct smb_vc *vcp, mblk_t **mpp) +smb_iod_recvmsg(struct smb_vc *vcp, mblk_t **mpp) { mblk_t *m; - uchar_t *hp; int error; top: @@ -321,26 +404,28 @@ top: goto top; if (error) return (error); - ASSERT(m); + ASSERT(m != NULL); - m = m_pullup(m, SMB_HDRLEN); + m = m_pullup(m, 4); 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); } +/* + * How long should we keep around an unused VC (connection)? + * There's usually a good chance connections will be reused, + * so the default is to keep such connections for 5 min. + */ +#ifdef DEBUG +int smb_iod_idle_keep_time = 60; /* seconds */ +#else +int smb_iod_idle_keep_time = 300; /* seconds */ +#endif + /* * Process incoming packets * @@ -353,19 +438,16 @@ top: int smb_iod_recvall(struct smb_vc *vcp, boolean_t poll) { - struct smb_rq *rqp; mblk_t *m; - uchar_t *hp; - ushort_t mid; int error = 0; - int etime_count = 0; /* for "server not responding", etc. */ + int etime_idle = 0; /* How many 15 sec. "ticks" idle. */ + int etime_count = 0; /* ... and when we have requests. */ for (;;) { /* * Check whether someone "killed" this VC, * or is asking the IOD to terminate. */ - if (vcp->iod_flags & SMBIOD_SHUTDOWN) { SMBIODEBUG("SHUTDOWN set\n"); /* This IOD thread will terminate. */ @@ -378,7 +460,7 @@ smb_iod_recvall(struct smb_vc *vcp, boolean_t poll) } m = NULL; - error = smb_iod_recv1(vcp, &m); + error = smb_iod_recvmsg(vcp, &m); /* * Internal requests (reconnecting) call this in a loop @@ -389,49 +471,77 @@ smb_iod_recvall(struct smb_vc *vcp, boolean_t poll) if (error == ETIME && vcp->iod_rqlist.tqh_first != NULL) { + /* - * Nothing received for 15 seconds and - * we have requests in the queue. + * Nothing received and requests waiting. + * Increment etime_count. If we were idle, + * skip the 1st tick, because we started + * waiting before there were any requests. */ - etime_count++; + if (etime_idle != 0) { + etime_idle = 0; + } else if (etime_count < INT16_MAX) { + etime_count++; + } /* - * Once, at 15 sec. notify callbacks - * and print the warning message. + * ETIME and requests in the queue. + * The first time (at 15 sec.) + * Log an error (just once). */ - if (etime_count == 1) { - /* Was: smb_iod_notify_down(vcp); */ - if (fscb && fscb->fscb_down) - smb_vc_walkshares(vcp, - fscb->fscb_down); + if (etime_count > 0 && + vcp->iod_noresp == B_FALSE) { + vcp->iod_noresp = B_TRUE; 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. + * At 30 sec. try sending an echo, which + * should cause some response. */ - if ((etime_count & 3) == 2) { - (void) smb_iod_send_echo(vcp); + if (etime_count == 2) { + SMBIODEBUG("send echo\n"); + (void) smb_iod_send_echo(vcp, CRED()); + } + /* + * At 45 sec. give up on the connection + * and try to reconnect. + */ + if (etime_count == 3) { + SMB_VC_LOCK(vcp); + smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT); + SMB_VC_UNLOCK(vcp); + SMB_TRAN_DISCONNECT(vcp); + break; } - continue; - } /* ETIME && requests in queue */ + } /* ETIME and requests in the queue */ - if (error == ETIME) { /* and req list empty */ + if (error == ETIME) { /* - * If the IOD thread holds the last reference - * to this VC, let it become IDLE, and then - * let it be destroyed if not used. + * Nothing received and no active requests. + * + * If we've received nothing from the server for + * smb_iod_idle_keep_time seconds, and the IOD + * thread holds the last reference to this VC, + * move to state IDLE and drop the TCP session. + * The IDLE handler will destroy the VC unless + * vc_state goes to RECONNECT before then. */ - if (vcp->vc_co.co_usecount > 1) + etime_count = 0; + if (etime_idle < INT16_MAX) + etime_idle++; + if ((etime_idle * SMB_NBTIMO) < + smb_iod_idle_keep_time) continue; SMB_VC_LOCK(vcp); if (vcp->vc_co.co_usecount == 1) { smb_iod_newstate(vcp, SMBIOD_ST_IDLE); SMB_VC_UNLOCK(vcp); + SMBIODEBUG("logoff & disconnect\n"); + (void) smb_iod_logoff(vcp, CRED()); + SMB_TRAN_DISCONNECT(vcp); error = 0; break; } @@ -441,97 +551,327 @@ smb_iod_recvall(struct smb_vc *vcp, boolean_t poll) if (error) { /* - * The recv. above returned some error - * we can't continue from i.e. ENOTCONN. - * It's dangerous to continue here. - * (possible infinite loop!) - * - * If this VC has shares, try reconnect; - * otherwise let this VC die now. + * The recv above returned an error indicating + * that our TCP session is no longer usable. + * Disconnect the session and get ready to + * reconnect. If we have pending requests, + * move to state reconnect immediately; + * otherwise move to state IDLE until a + * request is issued on this VC. */ SMB_VC_LOCK(vcp); - if (vcp->vc_co.co_usecount > 1) + if (vcp->iod_rqlist.tqh_first != NULL) smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT); else - smb_iod_newstate(vcp, SMBIOD_ST_DEAD); + smb_iod_newstate(vcp, SMBIOD_ST_IDLE); cv_broadcast(&vcp->vc_statechg); SMB_VC_UNLOCK(vcp); + SMB_TRAN_DISCONNECT(vcp); break; } /* * Received something. Yea! */ - if (etime_count) { - etime_count = 0; + etime_count = 0; + etime_idle = 0; + /* + * If we just completed a reconnect after logging + * "SMB server %s not responding" then log OK now. + */ + if (vcp->iod_noresp) { + vcp->iod_noresp = B_FALSE; zprintf(vcp->vc_zoneid, "SMB server %s OK\n", vcp->vc_srvname); + } - /* Was: smb_iod_notify_up(vcp); */ - if (fscb && fscb->fscb_up) - smb_vc_walkshares(vcp, fscb->fscb_up); + if ((vcp->vc_flags & SMBV_SMB2) != 0) { + error = smb2_iod_process(vcp, m); + } else { + error = smb1_iod_process(vcp, m); } /* - * Have an SMB packet. The SMB header was - * checked in smb_iod_recv1(). - * Find the request... + * Reconnect calls this in a loop with poll=TRUE + * We've received a response, so break now. */ - hp = mtod(m, uchar_t *); - /*LINTED*/ - mid = letohs(SMB_HDRMID(hp)); - SMBIODEBUG("mid %04x\n", (uint_t)mid); + if (poll) { + error = 0; + break; + } + } - rw_enter(&vcp->iod_rqlock, RW_READER); - TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) { + return (error); +} - if (rqp->sr_mid != mid) - continue; +/* + * Have what should be an SMB1 reply. Check and parse the header, + * then use the message ID to find the request this belongs to and + * post it on that request. + * + * Returns an error if the reader should give up. + * To be safe, error if we read garbage. + */ +static int +smb1_iod_process(smb_vc_t *vcp, mblk_t *m) +{ + struct mdchain md; + struct smb_rq *rqp; + uint8_t cmd, sig[4]; + uint16_t mid; + int err, skip; - DTRACE_PROBE2(smb_iod_recvrq, - (smb_rq_t *), rqp, (mblk_t *), m); - m_dumpm(m); + m = m_pullup(m, SMB_HDRLEN); + if (m == NULL) + return (ENOMEM); - 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); + /* + * Note: Intentionally do NOT md_done(&md) + * because that would free the message and + * we just want to peek here. + */ + md_initm(&md, m); + + /* + * Check the SMB header version and get the MID. + * + * The header version should be SMB1 except when we're + * doing SMB1-to-SMB2 negotiation, in which case we may + * see an SMB2 header with message ID=0 (only allowed in + * vc_state == SMBIOD_ST_CONNECTED -- negotiationg). + */ + err = md_get_mem(&md, sig, 4, MB_MSYSTEM); + if (err) + return (err); + if (sig[1] != 'S' || sig[2] != 'M' || sig[3] != 'B') { + goto bad_hdr; + } + switch (sig[0]) { + case SMB_HDR_V1: /* SMB1 */ + md_get_uint8(&md, &cmd); + /* Skip to and get the MID. At offset 5 now. */ + skip = SMB_HDR_OFF_MID - 5; + md_get_mem(&md, NULL, skip, MB_MSYSTEM); + err = md_get_uint16le(&md, &mid); + if (err) + return (err); + break; + case SMB_HDR_V2: /* SMB2+ */ + if (vcp->vc_state == SMBIOD_ST_CONNECTED) { + /* + * No need to look, can only be + * MID=0, cmd=negotiate + */ + cmd = SMB_COM_NEGOTIATE; + mid = 0; break; } + /* FALLTHROUGH */ + bad_hdr: + default: + SMBIODEBUG("Bad SMB hdr\n"); + m_freem(m); + return (EPROTO); + } + + /* + * Find the reqeuest and post the reply + */ + rw_enter(&vcp->iod_rqlock, RW_READER); + TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) { - if (rqp == NULL) { - int cmd = SMB_HDRCMD(hp); + if (rqp->sr_mid != mid) + continue; - if (cmd != SMB_COM_ECHO) - SMBSDEBUG("drop resp: mid %d, cmd %d\n", - (uint_t)mid, cmd); - m_freem(m); + DTRACE_PROBE2(iod_post_reply, + (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); + rqp = NULL; + break; + } } - rw_exit(&vcp->iod_rqlock); + smb_iod_rqprocessed_LH(rqp, 0, 0); + SMBRQ_UNLOCK(rqp); + break; + } + rw_exit(&vcp->iod_rqlock); + if (rqp == NULL) { + if (cmd != SMB_COM_ECHO) { + SMBSDEBUG("drop resp: MID 0x%04x\n", (uint_t)mid); + } + m_freem(m); /* - * Reconnect calls this in a loop with poll=TRUE - * We've received a response, so break now. + * Keep going. It's possible this reply came + * after the request timed out and went away. */ - if (poll) { - error = 0; + } + return (0); +} + +/* + * Have what should be an SMB2 reply. Check and parse the header, + * then use the message ID to find the request this belongs to and + * post it on that request. + * + * We also want to apply any credit grant in this reply now, + * rather than waiting for the owner to wake up. + */ +static int +smb2_iod_process(smb_vc_t *vcp, mblk_t *m) +{ + struct mdchain md; + struct smb_rq *rqp; + uint8_t sig[4]; + mblk_t *next_m = NULL; + uint64_t message_id, async_id; + uint32_t flags, next_cmd_off, status; + uint16_t command, credits_granted; + int err; + +top: + m = m_pullup(m, SMB2_HDRLEN); + if (m == NULL) + return (ENOMEM); + + /* + * Note: Intentionally do NOT md_done(&md) + * because that would free the message and + * we just want to peek here. + */ + md_initm(&md, m); + + /* + * Check the SMB header. Must be SMB2 + * (and later, could be SMB3 encrypted) + */ + err = md_get_mem(&md, sig, 4, MB_MSYSTEM); + if (err) + return (err); + if (sig[1] != 'S' || sig[2] != 'M' || sig[3] != 'B') { + goto bad_hdr; + } + switch (sig[0]) { + case SMB_HDR_V2: + break; + case SMB_HDR_V3E: + /* + * Todo: If encryption enabled, decrypt the message + * and restart processing on the cleartext. + */ + /* FALLTHROUGH */ + bad_hdr: + default: + SMBIODEBUG("Bad SMB2 hdr\n"); + m_freem(m); + return (EPROTO); + } + + /* + * Parse the rest of the SMB2 header, + * skipping what we don't need. + */ + md_get_uint32le(&md, NULL); /* length, credit_charge */ + md_get_uint32le(&md, &status); + md_get_uint16le(&md, &command); + md_get_uint16le(&md, &credits_granted); + md_get_uint32le(&md, &flags); + md_get_uint32le(&md, &next_cmd_off); + md_get_uint64le(&md, &message_id); + if (flags & SMB2_FLAGS_ASYNC_COMMAND) { + md_get_uint64le(&md, &async_id); + } else { + /* PID, TID (not needed) */ + async_id = 0; + } + + /* + * If this is a compound reply, split it. + * Next must be 8-byte aligned. + */ + if (next_cmd_off != 0) { + if ((next_cmd_off & 7) != 0) + SMBIODEBUG("Misaligned next cmd\n"); + else + next_m = m_split(m, next_cmd_off, 1); + } + + /* + * Apply the credit grant + */ + rw_enter(&vcp->iod_rqlock, RW_WRITER); + vcp->vc2_limit_message_id += credits_granted; + + /* + * Find the reqeuest and post the reply + */ + rw_downgrade(&vcp->iod_rqlock); + TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) { + + if (rqp->sr2_messageid != message_id) + continue; + + DTRACE_PROBE2(iod_post_reply, + (smb_rq_t *), rqp, (mblk_t *), m); + m_dumpm(m); + + /* + * If this is an interim response, just save the + * async ID but don't wakup the request. + * Don't need SMBRQ_LOCK for this. + */ + if (status == NT_STATUS_PENDING && async_id != 0) { + rqp->sr2_rspasyncid = async_id; + m_freem(m); + break; + } + + SMBRQ_LOCK(rqp); + if (rqp->sr_rp.md_top == NULL) { + md_initm(&rqp->sr_rp, m); + } else { + SMBRQ_UNLOCK(rqp); + rqp = NULL; break; } + smb_iod_rqprocessed_LH(rqp, 0, 0); + SMBRQ_UNLOCK(rqp); + break; } + rw_exit(&vcp->iod_rqlock); - return (error); + if (rqp == NULL) { + if (command != SMB2_ECHO) { + SMBSDEBUG("drop resp: MID %lld\n", + (long long)message_id); + } + m_freem(m); + /* + * Keep going. It's possible this reply came + * after the request timed out and went away. + */ + } + + /* + * If we split a compound reply, continue with the + * next part of the compound. + */ + if (next_m != NULL) { + m = next_m; + goto top; + } + + return (0); } /* @@ -545,125 +885,256 @@ smb_iod_recvall(struct smb_vc *vcp, boolean_t poll) * The smb_smb_echo call uses SMBR_INTERNAL * to avoid calling smb_iod_sendall(). */ -int -smb_iod_send_echo(smb_vc_t *vcp) +static int +smb_iod_send_echo(smb_vc_t *vcp, cred_t *cr) { smb_cred_t scred; - int err; + int err, tmo = SMBNOREPLYWAIT; + + ASSERT(vcp->iod_thr == curthread); - smb_credinit(&scred, NULL); - err = smb_smb_echo(vcp, &scred, SMBNOREPLYWAIT); + smb_credinit(&scred, cr); + if ((vcp->vc_flags & SMBV_SMB2) != 0) { + err = smb2_smb_echo(vcp, &scred, tmo); + } else { + err = smb_smb_echo(vcp, &scred, tmo); + } smb_credrele(&scred); return (err); } -/* - * The IOD thread is now just a "reader", - * so no more smb_iod_request(). Yea! - */ +/* + * Helper for smb1_iod_addrq, smb2_iod_addrq + * Returns zero if interrupted, else 1. + */ +static int +smb_iod_muxwait(smb_vc_t *vcp, boolean_t sig_ok) +{ + int rc; + + SMB_VC_LOCK(vcp); + vcp->iod_muxwant++; + if (sig_ok) { + rc = cv_wait_sig(&vcp->iod_muxwait, &vcp->vc_lock); + } else { + cv_wait(&vcp->iod_muxwait, &vcp->vc_lock); + rc = 1; + } + vcp->iod_muxwant--; + SMB_VC_UNLOCK(vcp); + + return (rc); +} /* - * Place request in the queue, and send it now if possible. + * Place request in the queue, and send it. * Called with no locks held. + * + * Called for SMB1 only + * + * The logic for how we limit active requests differs between + * SMB1 and SMB2. With SMB1 it's a simple counter ioc_muxcnt. */ int -smb_iod_addrq(struct smb_rq *rqp) +smb1_iod_addrq(struct smb_rq *rqp) { struct smb_vc *vcp = rqp->sr_vc; - int error, save_newrq; + uint16_t need; + boolean_t sig_ok = + (rqp->sr_flags & SMBR_NOINTR_SEND) == 0; ASSERT(rqp->sr_cred); + ASSERT((vcp->vc_flags & SMBV_SMB2) == 0); + + rqp->sr_owner = curthread; + rw_enter(&vcp->iod_rqlock, RW_WRITER); + +recheck: /* - * Requests from the IOD itself are marked _INTERNAL, - * and get some special treatment to avoid blocking - * the reader thread (so we don't deadlock). - * The request is not yet on the queue, so we can - * modify it's state here without locks. + * Internal requests can be added in any state, + * but normal requests only in state active. */ - rqp->sr_owner = curthread; - if (rqp->sr_owner == vcp->iod_thr) { - rqp->sr_flags |= SMBR_INTERNAL; + if ((rqp->sr_flags & SMBR_INTERNAL) == 0 && + vcp->vc_state != SMBIOD_ST_VCACTIVE) { + SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state); + rw_exit(&vcp->iod_rqlock); + return (ENOTCONN); + } - /* - * This is a request from the IOD thread. - * Always send directly from this thread. - * Note lock order: iod_rqlist, vc_sendlock - */ + /* + * If we're at the limit of active requests, block until + * enough requests complete so we can make ours active. + * Wakeup in smb_iod_removerq(). + * + * Normal callers leave one slot free, so internal + * callers can have the last slot if needed. + */ + need = 1; + if ((rqp->sr_flags & SMBR_INTERNAL) == 0) + need++; + if ((vcp->iod_muxcnt + need) > vcp->vc_maxmux) { + rw_exit(&vcp->iod_rqlock); + if (rqp->sr_flags & SMBR_INTERNAL) + return (EBUSY); + if (smb_iod_muxwait(vcp, sig_ok) == 0) + return (EINTR); rw_enter(&vcp->iod_rqlock, RW_WRITER); - TAILQ_INSERT_HEAD(&vcp->iod_rqlist, rqp, sr_link); - rw_downgrade(&vcp->iod_rqlock); + goto recheck; + } - /* - * Note: iod_sendrq expects vc_sendlock, - * so take that here, but carefully: - * Never block the IOD thread here. - */ - 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); - } + /* + * Add this request to the active list and send it. + * For SMB2 we may have a sequence of compounded + * requests, in which case we must add them all. + * They're sent as a compound in smb2_iod_sendrq. + */ + rqp->sr_mid = vcp->vc_next_mid++; + /* If signing, set the signing sequence numbers. */ + if (vcp->vc_mackey != NULL && (rqp->sr_rqflags2 & + SMB_FLAGS2_SECURITY_SIGNATURE) != 0) { + rqp->sr_seqno = vcp->vc_next_seq++; + rqp->sr_rseqno = vcp->vc_next_seq++; + } + vcp->iod_muxcnt++; + TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link); + smb1_iod_sendrq(rqp); - rw_exit(&vcp->iod_rqlock); + rw_exit(&vcp->iod_rqlock); + return (0); +} - /* - * In the non-error case, _removerq - * is done by either smb_rq_reply - * or smb_iod_waitrq. - */ - if (error) - smb_iod_removerq(rqp); +/* + * Place request in the queue, and send it. + * Called with no locks held. + * + * Called for SMB2 only. + * + * With SMB2 we have a range of valid message IDs, and we may + * only send requests when we can assign a message ID within + * the valid range. We may need to wait here for some active + * request to finish (and update vc2_limit_message_id) before + * we can get message IDs for our new request(s). Another + * difference is that the request sequence we're waiting to + * add here may require multipe message IDs, either due to + * either compounding or multi-credit requests. Therefore + * we need to wait for the availibility of how ever many + * message IDs are required by our request sequence. + */ +int +smb2_iod_addrq(struct smb_rq *rqp) +{ + struct smb_vc *vcp = rqp->sr_vc; + struct smb_rq *c_rqp; /* compound req */ + uint16_t charge; + boolean_t sig_ok = + (rqp->sr_flags & SMBR_NOINTR_SEND) == 0; - return (error); - } else { - /* - * 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); + ASSERT(rqp->sr_cred != NULL); + ASSERT((vcp->vc_flags & SMBV_SMB2) != 0); + + /* + * Figure out the credit charges + * No multi-credit messages yet. + */ + rqp->sr2_totalcreditcharge = rqp->sr2_creditcharge; + c_rqp = rqp->sr2_compound_next; + while (c_rqp != NULL) { + rqp->sr2_totalcreditcharge += c_rqp->sr2_creditcharge; + c_rqp = c_rqp->sr2_compound_next; + } + + /* + * Internal request must not be compounded + * and should use exactly one credit. + */ + if (rqp->sr_flags & SMBR_INTERNAL) { + if (rqp->sr2_compound_next != NULL) { + ASSERT(0); + return (EINVAL); } } + rqp->sr_owner = curthread; + 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++; +recheck: + /* + * Internal requests can be added in any state, + * but normal requests only in state active. + */ + if ((rqp->sr_flags & SMBR_INTERNAL) == 0 && + vcp->vc_state != SMBIOD_ST_VCACTIVE) { + SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state); + rw_exit(&vcp->iod_rqlock); + return (ENOTCONN); + } - rw_exit(&vcp->iod_rqlock); + /* + * If we're at the limit of active requests, block until + * enough requests complete so we can make ours active. + * Wakeup in smb_iod_removerq(). + * + * Normal callers leave one slot free, so internal + * callers can have the last slot if needed. + */ + charge = rqp->sr2_totalcreditcharge; + if ((rqp->sr_flags & SMBR_INTERNAL) == 0) + charge++; + if ((vcp->vc2_next_message_id + charge) > + vcp->vc2_limit_message_id) { + rw_exit(&vcp->iod_rqlock); + if (rqp->sr_flags & SMBR_INTERNAL) + return (EBUSY); + if (smb_iod_muxwait(vcp, sig_ok) == 0) + return (EINTR); + rw_enter(&vcp->iod_rqlock, RW_WRITER); + goto recheck; + } /* - * 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. + * Add this request to the active list and send it. + * For SMB2 we may have a sequence of compounded + * requests, in which case we must add them all. + * They're sent as a compound in smb2_iod_sendrq. */ - if (save_newrq == 0) - smb_iod_sendall(vcp); + rqp->sr2_messageid = vcp->vc2_next_message_id; + vcp->vc2_next_message_id += rqp->sr2_creditcharge; + TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link); + + c_rqp = rqp->sr2_compound_next; + while (c_rqp != NULL) { + c_rqp->sr2_messageid = vcp->vc2_next_message_id; + vcp->vc2_next_message_id += c_rqp->sr2_creditcharge; + TAILQ_INSERT_TAIL(&vcp->iod_rqlist, c_rqp, sr_link); + c_rqp = c_rqp->sr2_compound_next; + } + smb2_iod_sendrq(rqp); + + rw_exit(&vcp->iod_rqlock); return (0); } /* * Mark an SMBR_MULTIPACKET request as * needing another send. Similar to the - * "normal" part of smb_iod_addrq. + * "normal" part of smb1_iod_addrq. + * Only used by SMB1 */ int -smb_iod_multirq(struct smb_rq *rqp) +smb1_iod_multirq(struct smb_rq *rqp) { struct smb_vc *vcp = rqp->sr_vc; - int save_newrq; ASSERT(rqp->sr_flags & SMBR_MULTIPACKET); + if (vcp->vc_flags & SMBV_SMB2) { + ASSERT("!SMB2?"); + return (EINVAL); + } + if (rqp->sr_flags & SMBR_INTERNAL) return (EINVAL); @@ -676,32 +1147,36 @@ smb_iod_multirq(struct smb_rq *rqp) /* 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++; + smb1_iod_sendrq(rqp); 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); } - +/* + * Remove a request from the active list, and + * wake up requests waiting to go active. + * + * Shared by SMB1 + SMB2 + * + * The logic for how we limit active requests differs between + * SMB1 and SMB2. With SMB1 it's a simple counter ioc_muxcnt. + * With SMB2 we have a range of valid message IDs, and when we + * retire the oldest request we need to keep track of what is + * now the oldest message ID. In both cases, after we take a + * request out of the list here, we should be able to wake up + * a request waiting to get in the active list. + */ void smb_iod_removerq(struct smb_rq *rqp) { + struct smb_rq *rqp2; struct smb_vc *vcp = rqp->sr_vc; + boolean_t was_head = B_FALSE; rw_enter(&vcp->iod_rqlock, RW_WRITER); + #ifdef QUEUEDEBUG /* * Make sure we have not already removed it. @@ -710,45 +1185,47 @@ smb_iod_removerq(struct smb_rq *rqp) */ ASSERT(rqp->sr_link.tqe_next != (void *)1L); #endif + + if (TAILQ_FIRST(&vcp->iod_rqlist) == rqp) + was_head = B_TRUE; TAILQ_REMOVE(&vcp->iod_rqlist, rqp, sr_link); - rw_exit(&vcp->iod_rqlock); -} + if (vcp->vc_flags & SMBV_SMB2) { + rqp2 = TAILQ_FIRST(&vcp->iod_rqlist); + if (was_head && rqp2 != NULL) { + /* Do we still need this? */ + vcp->vc2_oldest_message_id = + rqp2->sr2_messageid; + } + } else { + ASSERT(vcp->iod_muxcnt > 0); + vcp->iod_muxcnt--; + } + rw_exit(&vcp->iod_rqlock); + /* + * If there are requests waiting for "mux" slots, + * wake one. + */ + SMB_VC_LOCK(vcp); + if (vcp->iod_muxwant != 0) + cv_signal(&vcp->iod_muxwait); + SMB_VC_UNLOCK(vcp); +} /* * Wait for a request to complete. - * - * 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; + int error; if (rqp->sr_flags & SMBR_INTERNAL) { - int timeleft = rqp->sr_timo; - - ASSERT((rqp->sr_flags & SMBR_MULTIPACKET) == 0); - again: - smb_iod_sendall(vcp); - error = smb_iod_recvall(vcp, B_TRUE); - if (error == ETIME) { - /* We waited SMB_NBTIMO sec. */ - timeleft -= SMB_NBTIMO; - if (timeleft > 0) - goto again; - } - - smb_iod_removerq(rqp); - if (rqp->sr_state != SMBRQ_NOTIFIED) - error = ETIME; - - return (error); + /* XXX - Do we ever take this path now? */ + return (smb_iod_waitrq_int(rqp)); } /* @@ -759,35 +1236,6 @@ smb_iod_waitrq(struct smb_rq *rqp) 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, rq=%p\n", (void *)rqp); - error = EINTR; - goto out; - } - } - /* * The request has been sent. Now wait for the response, * with the timeout specified for this request. @@ -861,13 +1309,34 @@ out: 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); +} + +/* + * Internal variant of smb_iod_waitrq(), for use in + * requests run by the IOD (reader) thread itself. + * Block only long enough to receive one reply. + */ +int +smb_iod_waitrq_int(struct smb_rq *rqp) +{ + struct smb_vc *vcp = rqp->sr_vc; + int timeleft = rqp->sr_timo; + int error; + + ASSERT((rqp->sr_flags & SMBR_MULTIPACKET) == 0); +again: + error = smb_iod_recvall(vcp, B_TRUE); + if (error == ETIME) { + /* We waited SMB_NBTIMO sec. */ + timeleft -= SMB_NBTIMO; + if (timeleft > 0) + goto again; + } + + smb_iod_removerq(rqp); + if (rqp->sr_state != SMBRQ_NOTIFIED) + error = ETIME; return (error); } @@ -896,78 +1365,16 @@ smb_iod_shutdown_share(struct smb_share *ssp) rw_exit(&vcp->iod_rqlock); } -/* - * Send all requests that need sending. - * Called from _addrq, _multirq, _waitrq - */ -void -smb_iod_sendall(smb_vc_t *vcp) -{ - struct smb_rq *rqp; - int error, muxcnt; - - /* - * Clear "newrq" to make sure threads adding - * new requests will run this function again. - */ - rw_enter(&vcp->iod_rqlock, RW_WRITER); - 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); - - /* - * 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 (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); -} - /* * Ioctl functions called by the user-level I/O Deamon (IOD) * to bring up and service a connection to some SMB server. */ +/* + * Handle ioctl SMBIOC_IOD_CONNECT + */ int -nsmb_iod_connect(struct smb_vc *vcp) +nsmb_iod_connect(struct smb_vc *vcp, cred_t *cr) { int err, val; @@ -978,6 +1385,22 @@ nsmb_iod_connect(struct smb_vc *vcp) return (EINVAL); } + /* + * Putting a TLI endpoint back in the right state for a new + * connection is a bit tricky. In theory, this could be: + * SMB_TRAN_DISCONNECT(vcp); + * SMB_TRAN_UNBIND(vcp); + * but that method often results in TOUTSTATE errors. + * It's easier to just close it and open a new endpoint. + */ + SMB_VC_LOCK(vcp); + if (vcp->vc_tdata) + SMB_TRAN_DONE(vcp); + err = SMB_TRAN_CREATE(vcp, cr); + SMB_VC_UNLOCK(vcp); + if (err != 0) + return (err); + /* * Set various options on this endpoint. * Keep going in spite of errors. @@ -1032,7 +1455,21 @@ nsmb_iod_connect(struct smb_vc *vcp) } /* + * Handle ioctl SMBIOC_IOD_NEGOTIATE * Do the whole SMB1/SMB2 negotiate + * + * This is where we send our first request to the server. + * If this is the first time we're talking to this server, + * (meaning not a reconnect) then we don't know whether + * the server supports SMB2, so we need to use the weird + * SMB1-to-SMB2 negotiation. That's where we send an SMB1 + * negotiate including dialect "SMB 2.???" and if the + * server supports SMB2 we get an SMB2 reply -- Yes, an + * SMB2 reply to an SMB1 request. A strange protocol... + * + * If on the other hand we already know the server supports + * SMB2 (because this is a reconnect) or if the client side + * has disabled SMB1 entirely, we'll skip the SMB1 part. */ int nsmb_iod_negotiate(struct smb_vc *vcp, cred_t *cr) @@ -1043,15 +1480,26 @@ nsmb_iod_negotiate(struct smb_vc *vcp, cred_t *cr) ASSERT(vcp->iod_thr == curthread); + smb_credinit(&scred, cr); + if (vcp->vc_state != SMBIOD_ST_CONNECTED) { cmn_err(CE_NOTE, "iod_negotiate: bad state %d", vcp->vc_state); - return (EINVAL); + err = EINVAL; + goto out; + } + + if (vcp->vc_maxver == 0 || vcp->vc_minver > vcp->vc_maxver) { + err = EINVAL; + goto out; } /* * (Re)init negotiated values */ bzero(sv, sizeof (*sv)); + vcp->vc2_next_message_id = 0; + vcp->vc2_limit_message_id = 1; + vcp->vc2_session_id = 0; vcp->vc_next_seq = 0; /* @@ -1071,10 +1519,54 @@ nsmb_iod_negotiate(struct smb_vc *vcp, cred_t *cr) } SMB_VC_UNLOCK(vcp); - smb_credinit(&scred, cr); - err = smb_smb_negotiate(vcp, &scred); - smb_credrele(&scred); + /* + * If this is not an SMB2 reconect (SMBV_SMB2 not set), + * and if SMB1 is enabled, do SMB1 neogotiate. Then + * if either SMB1-to-SMB2 negotiate tells us we should + * switch to SMB2, or the local configuration has + * disabled SMB1, set the SMBV_SMB2 flag. + * + * Note that vc_maxver is handled in smb_smb_negotiate + * so we never get sv_proto == SMB_DIALECT_SMB2_FF when + * the local configuration disables SMB2, and therefore + * we won't set the SMBV_SMB2 flag. + */ + if ((vcp->vc_flags & SMBV_SMB2) == 0) { + if (vcp->vc_minver < SMB2_DIALECT_BASE) { + /* + * SMB1 is enabled + */ + err = smb_smb_negotiate(vcp, &scred); + if (err != 0) + goto out; + } + /* + * If SMB1-to-SMB2 negotiate told us we should + * switch to SMB2, or if the local configuration + * disables SMB1, set the SMB2 flag. + */ + if (sv->sv_proto == SMB_DIALECT_SMB2_FF || + vcp->vc_minver >= SMB2_DIALECT_BASE) { + /* + * Switch this VC to SMB2. + */ + SMB_VC_LOCK(vcp); + vcp->vc_flags |= SMBV_SMB2; + SMB_VC_UNLOCK(vcp); + } + } + + /* + * If this is an SMB2 reconnect (SMBV_SMB2 was set before this + * function was called), or SMB1-to-SMB2 negotiate indicated + * we should switch to SMB2, or we have SMB1 disabled (both + * cases set SMBV_SMB2 above), then do SMB2 negotiate. + */ + if ((vcp->vc_flags & SMBV_SMB2) != 0) { + err = smb2_smb_negotiate(vcp, &scred); + } +out: if (err == 0) { SMB_VC_LOCK(vcp); smb_iod_newstate(vcp, SMBIOD_ST_NEGOTIATED); @@ -1082,15 +1574,18 @@ nsmb_iod_negotiate(struct smb_vc *vcp, cred_t *cr) } /* * (else) leave state as it was. - * User-level will report this error - * and close this device handle. + * User-level will either close this handle (if connecting + * for the first time) or call rcfail and then try again. */ + smb_credrele(&scred); + return (err); } /* - * Do either SMB1 or SMB2 session setup. + * Handle ioctl SMBIOC_IOD_SSNSETUP + * Do either SMB1 or SMB2 session setup (one call/reply) */ int nsmb_iod_ssnsetup(struct smb_vc *vcp, cred_t *cr) @@ -1109,8 +1604,10 @@ nsmb_iod_ssnsetup(struct smb_vc *vcp, cred_t *cr) } smb_credinit(&scred, cr); - // XXX if SMB1 else ... - err = smb_smb_ssnsetup(vcp, &scred); + if (vcp->vc_flags & SMBV_SMB2) + err = smb2_smb_ssnsetup(vcp, &scred); + else + err = smb_smb_ssnsetup(vcp, &scred); smb_credrele(&scred); SMB_VC_LOCK(vcp); @@ -1130,6 +1627,32 @@ nsmb_iod_ssnsetup(struct smb_vc *vcp, cred_t *cr) return (err); } +static int +smb_iod_logoff(struct smb_vc *vcp, cred_t *cr) +{ + smb_cred_t scred; + int err; + + ASSERT(vcp->iod_thr == curthread); + + smb_credinit(&scred, cr); + if (vcp->vc_flags & SMBV_SMB2) + err = smb2_smb_logoff(vcp, &scred); + else + err = smb_smb_logoff(vcp, &scred); + smb_credrele(&scred); + + return (err); +} + +/* + * Handle ioctl SMBIOC_IOD_WORK + * + * The smbiod agent calls this after authentication to become + * the reader for this session, so long as that's possible. + * This should only return non-zero if we want that agent to + * give up on this VC permanently. + */ /* ARGSUSED */ int smb_iod_vc_work(struct smb_vc *vcp, int flags, cred_t *cr) @@ -1185,7 +1708,10 @@ smb_iod_vc_work(struct smb_vc *vcp, int flags, cred_t *cr) */ ASSERT(vcp->vc_mackey == NULL); if (vcp->vc_ssnkey != NULL) { - err = smb_sign_init(vcp); + if (vcp->vc_flags & SMBV_SMB2) + err = smb2_sign_init(vcp); + else + err = smb_sign_init(vcp); if (err != 0) return (err); } @@ -1210,9 +1736,11 @@ smb_iod_vc_work(struct smb_vc *vcp, int flags, cred_t *cr) smb_vc_walkshares(vcp, fscb->fscb_connect); /* - * Run the "reader" loop. + * Run the "reader" loop. An error return here is normal + * (i.e. when we need to reconnect) so ignore errors. + * Note: This call updates the vc_state. */ - err = smb_iod_recvall(vcp, B_FALSE); + (void) smb_iod_recvall(vcp, B_FALSE); /* * The reader loop returned, so we must have a @@ -1237,15 +1765,20 @@ smb_iod_vc_work(struct smb_vc *vcp, int flags, cred_t *cr) } /* - * Wait around for someone to ask to use this VC. - * If the VC has only the IOD reference, then - * wait only a minute or so, then drop it. + * Handle ioctl SMBIOC_IOD_IDLE + * + * Wait around for someone to ask to use this VC again after the + * TCP session has closed. When one of the connected trees adds a + * request, smb_iod_reconnect will set vc_state to RECONNECT and + * wake this cv_wait. When a VC ref. goes away in smb_vc_rele, + * that also signals this wait so we can re-check whether we + * now hold the last ref. on this VC (and can destroy it). */ int smb_iod_vc_idle(struct smb_vc *vcp) { - clock_t tr, delta = SEC_TO_TICK(15); int err = 0; + boolean_t destroy = B_FALSE; /* * This is called by the one-and-only @@ -1253,30 +1786,50 @@ smb_iod_vc_idle(struct smb_vc *vcp) */ ASSERT(vcp->iod_thr == curthread); + /* + * Should be in state... + */ + if (vcp->vc_state != SMBIOD_ST_IDLE && + vcp->vc_state != SMBIOD_ST_RECONNECT) { + cmn_err(CE_NOTE, "iod_vc_idle: bad state %d", vcp->vc_state); + return (EINVAL); + } + SMB_VC_LOCK(vcp); - while (vcp->vc_state == SMBIOD_ST_IDLE) { - tr = cv_reltimedwait_sig(&vcp->iod_idle, &vcp->vc_lock, - delta, TR_CLOCK_TICK); - if (tr == 0) { + + while (vcp->vc_state == SMBIOD_ST_IDLE && + vcp->vc_co.co_usecount > 1) { + if (cv_wait_sig(&vcp->iod_idle, &vcp->vc_lock) == 0) { err = EINTR; break; } - if (tr < 0) { - /* timeout */ - if (vcp->vc_co.co_usecount == 1) { - /* Let this IOD terminate. */ - smb_iod_newstate(vcp, SMBIOD_ST_DEAD); - /* nobody to cv_broadcast */ - break; - } - } } + if (vcp->vc_state == SMBIOD_ST_IDLE && + vcp->vc_co.co_usecount == 1) { + /* + * We were woken because we now have the last ref. + * Arrange for this VC to be destroyed now. + * Set the "GONE" flag while holding the lock, + * to prevent a race with new references. + * The destroy happens after unlock. + */ + vcp->vc_flags |= SMBV_GONE; + destroy = B_TRUE; + } + SMB_VC_UNLOCK(vcp); + if (destroy) { + /* This sets vc_state = DEAD */ + smb_iod_disconnect(vcp); + } + return (err); } /* + * Handle ioctl SMBIOC_IOD_RCFAIL + * * After a failed reconnect attempt, smbiod will * call this to make current requests error out. */ @@ -1307,13 +1860,17 @@ smb_iod_vc_rcfail(struct smb_vc *vcp) err = EINTR; /* - * While we were waiting on the CV, the state might have - * changed to reconnect. If so, leave that; otherwise - * go to state idle until the next request. + * Normally we'll switch to state IDLE here. However, + * if something called smb_iod_reconnect() while we were + * waiting above, we'll be in in state reconnect already. + * In that case, keep state RECONNECT, so we essentially + * skip transition through state IDLE that would normally + * happen next. */ - if (vcp->vc_state == SMBIOD_ST_RCFAILED) + if (vcp->vc_state != SMBIOD_ST_RECONNECT) { smb_iod_newstate(vcp, SMBIOD_ST_IDLE); - cv_broadcast(&vcp->vc_statechg); + cv_broadcast(&vcp->vc_statechg); + } SMB_VC_UNLOCK(vcp); @@ -1334,6 +1891,7 @@ again: switch (vcp->vc_state) { case SMBIOD_ST_IDLE: + /* Tell the IOD thread it's no longer IDLE. */ smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT); cv_signal(&vcp->iod_idle); /* FALLTHROUGH */ @@ -1343,6 +1901,7 @@ again: case SMBIOD_ST_NEGOTIATED: case SMBIOD_ST_AUTHCONT: case SMBIOD_ST_AUTHOK: + /* Wait for the VC state to become ACTIVE. */ rv = cv_wait_sig(&vcp->vc_statechg, &vcp->vc_lock); if (rv == 0) { err = EINTR; diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c index 2301965762..1c62850599 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c @@ -34,6 +34,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved. * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ @@ -52,10 +53,12 @@ #include #include +#include #include #include #include #include +#include /* * How long to wait before restarting a request (after reconnect) @@ -70,9 +73,8 @@ static int smb_rq_reply(struct smb_rq *rqp); +static int smb_rq_parsehdr(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); @@ -148,7 +150,6 @@ smb_rq_init(struct smb_rq *rqp, struct smb_connobj *co, uchar_t cmd, rqp->sr_rexmit = SMBMAXRESTARTS; rqp->sr_cred = scred; /* Note: ref hold done by caller. */ - rqp->sr_pid = (uint16_t)ddi_get_pid(); error = smb_rq_new(rqp, cmd); return (error); @@ -164,7 +165,6 @@ smb_rq_new(struct smb_rq *rqp, uchar_t cmd) ASSERT(rqp != NULL); rqp->sr_sendcnt = 0; - rqp->sr_cmd = cmd; mb_done(mbp); md_done(&rqp->sr_rp); @@ -172,18 +172,42 @@ smb_rq_new(struct smb_rq *rqp, uchar_t cmd) if (error) return (error); - /* - * Is this the right place to save the flags? - */ - rqp->sr_rqflags = vcp->vc_hflags; - rqp->sr_rqflags2 = vcp->vc_hflags2; + if (vcp->vc_flags & SMBV_SMB2) { + /* + * SMB2 request initialization + */ + rqp->sr2_command = cmd; + rqp->sr2_creditcharge = 1; + rqp->sr2_creditsrequested = 1; + rqp->sr_pid = 0xFEFF; /* Made up, just like Windows */ + rqp->sr2_rqflags = 0; + if ((vcp->vc_flags & SMBV_SIGNING) != 0 && + vcp->vc_mackey != NULL) { + rqp->sr2_rqflags |= SMB2_FLAGS_SIGNED; + } - /* - * The SMB header is filled in later by - * smb_rq_fillhdr (see below) - * Just reserve space here. - */ - mb_put_mem(mbp, NULL, SMB_HDRLEN, MB_MZERO); + /* + * The SMB2 header is filled in later by + * smb2_rq_fillhdr (see smb2_rq.c) + * Just reserve space here. + */ + mb_put_mem(mbp, NULL, SMB2_HDRLEN, MB_MZERO); + } else { + /* + * SMB1 request initialization + */ + rqp->sr_cmd = cmd; + rqp->sr_pid = (uint32_t)ddi_get_pid(); + rqp->sr_rqflags = vcp->vc_hflags; + rqp->sr_rqflags2 = vcp->vc_hflags2; + + /* + * The SMB header is filled in later by + * smb_rq_fillhdr (see below) + * Just reserve space here. + */ + mb_put_mem(mbp, NULL, SMB_HDRLEN, MB_MZERO); + } return (0); } @@ -191,7 +215,7 @@ smb_rq_new(struct smb_rq *rqp, uchar_t cmd) /* * Given a request with it's body already composed, * rewind to the start and fill in the SMB header. - * This is called after the request is enqueued, + * This is called when the request is enqueued, * so we have the final MID, seq num. etc. */ void @@ -218,7 +242,7 @@ smb_rq_fillhdr(struct smb_rq *rqp) mb_put_mem(mbp, NULL, 8, MB_MZERO); /* MAC sig. (later) */ mb_put_uint16le(mbp, 0); /* reserved */ mb_put_uint16le(mbp, rqp->sr_rqtid); - mb_put_uint16le(mbp, rqp->sr_pid); + mb_put_uint16le(mbp, (uint16_t)rqp->sr_pid); mb_put_uint16le(mbp, rqp->sr_rquid); mb_put_uint16le(mbp, rqp->sr_mid); @@ -282,6 +306,8 @@ smb_rq_enqueue(struct smb_rq *rqp) struct smb_share *ssp = rqp->sr_share; int error = 0; + ASSERT((vcp->vc_flags & SMBV_SMB2) == 0); + /* * Normal requests may initiate a reconnect, * and/or wait for state changes to finish. @@ -326,37 +352,73 @@ smb_rq_enqueue(struct smb_rq *rqp) ok_out: rqp->sr_rquid = vcp->vc_smbuid; rqp->sr_rqtid = ssp ? ssp->ss_tid : SMB_TID_UNKNOWN; - error = smb_iod_addrq(rqp); + error = smb1_iod_addrq(rqp); return (error); } /* - * Used by the IOD thread during connection setup. + * Used by the IOD thread during connection setup, + * and for smb_echo after network timeouts. Note that + * unlike smb_rq_simple, callers must check sr_error. */ int smb_rq_internal(struct smb_rq *rqp, int timeout) { struct smb_vc *vcp = rqp->sr_vc; - int err; + int error; + + ASSERT((vcp->vc_flags & SMBV_SMB2) == 0); rqp->sr_flags &= ~SMBR_RESTART; rqp->sr_timo = timeout; /* in seconds */ rqp->sr_state = SMBRQ_NOTSENT; /* - * Skip smb_rq_enqueue(rqp) here, as we don't want it - * trying to reconnect etc. We're doing that. + * In-line smb_rq_enqueue(rqp) here, as we don't want it + * trying to reconnect etc. for an internal request. */ rqp->sr_rquid = vcp->vc_smbuid; rqp->sr_rqtid = SMB_TID_UNKNOWN; - err = smb_iod_addrq(rqp); - if (err != 0) - return (err); + rqp->sr_flags |= SMBR_INTERNAL; + error = smb1_iod_addrq(rqp); + if (error != 0) + return (error); - err = smb_rq_reply(rqp); + /* + * In-line a variant of smb_rq_reply(rqp) here as we may + * need to do custom parsing for SMB1-to-SMB2 negotiate. + */ + if (rqp->sr_timo == SMBNOREPLYWAIT) { + smb_iod_removerq(rqp); + return (0); + } - return (err); + error = smb_iod_waitrq_int(rqp); + if (error) + return (error); + + /* + * If the request was signed, validate the + * signature on the response. + */ + if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) { + error = smb_rq_verify(rqp); + if (error) + return (error); + } + + /* + * Parse the SMB header. + */ + error = smb_rq_parsehdr(rqp); + + /* + * Skip the error translation smb_rq_reply does. + * Callers of this expect "raw" NT status. + */ + + return (error); } /* @@ -427,15 +489,6 @@ smb_rq_bend(struct smb_rq *rqp) } int -smb_rq_intr(struct smb_rq *rqp) -{ - if (rqp->sr_flags & SMBR_INTR) - return (EINTR); - - return (0); -} - -static int smb_rq_getenv(struct smb_connobj *co, struct smb_vc **vcpp, struct smb_share **sspp) { @@ -486,14 +539,12 @@ out: } /* - * Wait for reply on the request + * Wait for a reply to this request, then parse it. */ static int smb_rq_reply(struct smb_rq *rqp) { - struct mdchain *mdp = &rqp->sr_rp; - u_int8_t tb; - int error, rperror = 0; + int error; if (rqp->sr_timo == SMBNOREPLYWAIT) { smb_iod_removerq(rqp); @@ -517,27 +568,23 @@ smb_rq_reply(struct smb_rq *rqp) /* * Parse the SMB header */ - error = md_get_uint32le(mdp, NULL); - if (error) + error = smb_rq_parsehdr(rqp); + if (error != 0) 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_error != 0) { if (rqp->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) { - rperror = smb_maperr32(rqp->sr_error); + error = smb_maperr32(rqp->sr_error); } else { uint8_t errClass = rqp->sr_error & 0xff; uint16_t errCode = rqp->sr_error >> 16; /* Convert to NT status */ rqp->sr_error = smb_doserr2status(errClass, errCode); - rperror = smb_maperror(errClass, errCode); + error = smb_maperror(errClass, errCode); } } - if (rperror) { + if (error != 0) { /* * Do a special check for STATUS_BUFFER_OVERFLOW; * it's not an error. @@ -550,22 +597,63 @@ smb_rq_reply(struct smb_rq *rqp) * STATUS_BUFFER_OVERFLOW. */ rqp->sr_flags |= SMBR_MOREDATA; - rperror = 0; + error = 0; } } else { rqp->sr_flags &= ~SMBR_MOREDATA; } - error = md_get_uint32le(mdp, NULL); - error = md_get_uint32le(mdp, NULL); - error = md_get_uint32le(mdp, NULL); + return (error); +} + +/* + * Parse the SMB header + */ +static int +smb_rq_parsehdr(struct smb_rq *rqp) +{ + struct mdchain mdp_save; + struct mdchain *mdp = &rqp->sr_rp; + u_int8_t tb, sig[4]; + int error; - error = md_get_uint16le(mdp, &rqp->sr_rptid); - error = md_get_uint16le(mdp, &rqp->sr_rppid); - error = md_get_uint16le(mdp, &rqp->sr_rpuid); + /* + * Parse the signature. The reader already checked that + * the signature is valid. Here we just have to check + * for SMB1-to-SMB2 negotiate. Caller handles an EPROTO + * as a signal that we got an SMB2 reply. If we return + * EPROTO, rewind the mdchain back where it was. + */ + mdp_save = *mdp; + error = md_get_mem(mdp, sig, 4, MB_MSYSTEM); + if (error) + return (error); + if (sig[0] != SMB_HDR_V1) { + if (rqp->sr_cmd == SMB_COM_NEGOTIATE) { + *mdp = mdp_save; + return (EPROTO); + } + return (EBADRPC); + } + + /* Check cmd */ + error = md_get_uint8(mdp, &tb); + if (tb != rqp->sr_cmd) + return (EBADRPC); + + md_get_uint32le(mdp, &rqp->sr_error); + md_get_uint8(mdp, &rqp->sr_rpflags); + md_get_uint16le(mdp, &rqp->sr_rpflags2); + + /* Skip: pid-high(2), MAC sig(8), reserved(2) */ + md_get_mem(mdp, NULL, 12, MB_MSYSTEM); + + md_get_uint16le(mdp, &rqp->sr_rptid); + md_get_uint16le(mdp, &rqp->sr_rppid); + md_get_uint16le(mdp, &rqp->sr_rpuid); error = md_get_uint16le(mdp, &rqp->sr_rpmid); - return ((error) ? error : rperror); + return (error); } @@ -1166,7 +1254,7 @@ smb_t2_request_int(struct smb_t2rq *t2p) mb_put_mbuf(mbp, m); } smb_rq_bend(rqp); - error = smb_iod_multirq(rqp); + error = smb1_iod_multirq(rqp); if (error) goto bad; } /* while left params or data */ @@ -1377,7 +1465,7 @@ smb_nt_request_int(struct smb_ntrq *ntp) mb_put_mbuf(mbp, m); } smb_rq_bend(rqp); - error = smb_iod_multirq(rqp); + error = smb1_iod_multirq(rqp); if (error) goto bad; } /* while left params or data */ @@ -1470,3 +1558,83 @@ smb_nt_request(struct smb_ntrq *ntp) } return (error); } + +/* + * Run an SMB transact named pipe. + * Note: send_mb is consumed. + */ +int +smb_t2_xnp(struct smb_share *ssp, uint16_t fid, + struct mbchain *send_mb, struct mdchain *recv_md, + uint32_t *data_out_sz, /* max / returned */ + uint32_t *more, struct smb_cred *scrp) +{ + struct smb_t2rq *t2p = NULL; + mblk_t *m; + uint16_t setup[2]; + int err; + + setup[0] = TRANS_TRANSACT_NAMED_PIPE; + setup[1] = fid; + + t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP); + err = smb_t2_init(t2p, SSTOCP(ssp), setup, 2, scrp); + if (err) { + *data_out_sz = 0; + goto out; + } + + t2p->t2_setupcount = 2; + t2p->t2_setupdata = setup; + + t2p->t_name = "\\PIPE\\"; + t2p->t_name_len = 6; + + t2p->t2_maxscount = 0; + t2p->t2_maxpcount = 0; + t2p->t2_maxdcount = (uint16_t)*data_out_sz; + + /* Transmit parameters (none) */ + + /* + * Transmit data + * + * Copy the mb, and clear the source so we + * don't end up with a double free. + */ + t2p->t2_tdata = *send_mb; + bzero(send_mb, sizeof (*send_mb)); + + /* + * Run the request + */ + err = smb_t2_request(t2p); + + /* No returned parameters. */ + + if (err == 0 && (m = t2p->t2_rdata.md_top) != NULL) { + /* + * Received data + * + * Copy the mdchain, and clear the source so we + * don't end up with a double free. + */ + *data_out_sz = msgdsize(m); + md_initm(recv_md, m); + t2p->t2_rdata.md_top = NULL; + } else { + *data_out_sz = 0; + } + + if (t2p->t2_sr_error == NT_STATUS_BUFFER_OVERFLOW) + *more = 1; + +out: + if (t2p != NULL) { + /* Note: t2p->t_name no longer allocated */ + smb_t2_done(t2p); + kmem_free(t2p, sizeof (*t2p)); + } + + return (err); +} diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h index 4d6dbb1fe0..7c3106612c 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h @@ -34,6 +34,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Portions Copyright (C) 2001 - 2012 Apple Inc. All rights reserved. * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ @@ -57,6 +58,10 @@ #define SMBR_NORECONNECT 0x0800 /* do not reconnect for this */ /* SMBR_VCREF 0x4000 * took vc reference (obsolete) */ #define SMBR_MOREDATA 0x8000 /* our buffer was too small */ +#define SMBR_COMPOUND_RQ 0x10000 /* SMB 2/3 compound request */ +#define SMBR_ASYNC 0x20000 /* got async response */ +#define SMBR_RECONNECTED 0x40000 /* reconnected during request */ + #define SMBT2_ALLSENT 0x0001 /* all data and params are sent */ #define SMBT2_ALLRECV 0x0002 /* all data and params are received */ @@ -92,11 +97,24 @@ struct smb_rq { uint8_t sr_rqflags; uint16_t sr_rqflags2; uint16_t sr_rqtid; - uint16_t sr_pid; + uint32_t sr_pid; uint16_t sr_rquid; uint16_t sr_mid; uchar_t *sr_wcount; uchar_t *sr_bcount; + + /* SMB 2/3 request fields */ + struct smb_rq *sr2_compound_next; + uint16_t sr2_command; + uint16_t sr2_totalcreditcharge; + uint16_t sr2_creditcharge; + uint16_t sr2_creditsrequested; + uint32_t sr2_rqflags; + uint32_t sr2_nextcmd; + uint64_t sr2_messageid; /* local copy of message id */ + uint64_t sr2_rqsessionid; + uint32_t sr2_rqtreeid; + struct mdchain sr_rp; int sr_rpgen; int sr_rplast; @@ -117,6 +135,15 @@ struct smb_rq { uint16_t sr_rppid; uint16_t sr_rpuid; uint16_t sr_rpmid; + + /* SMB2 response fields */ + uint16_t sr2_rspcreditsgranted; + uint32_t sr2_rspflags; + uint32_t sr2_rspnextcmd; + uint32_t sr2_rsppid; + uint32_t sr2_rsptreeid; + uint64_t sr2_rspasyncid; + uint64_t sr2_rspsessionid; }; typedef struct smb_rq smb_rq_t; @@ -185,17 +212,20 @@ 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); +int smb_rq_getenv(struct smb_connobj *layer, + struct smb_vc **vcpp, struct smb_share **sspp); void smb_rq_fillhdr(struct smb_rq *rqp); void smb_rq_wstart(struct smb_rq *rqp); void smb_rq_wend(struct smb_rq *rqp); void smb_rq_bstart(struct smb_rq *rqp); 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_rq_internal(struct smb_rq *rqp, int timeout); +int smb2_parse_smb1nego_resp(struct smb_rq *rqp); + 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, @@ -203,6 +233,10 @@ int smb_t2_init(struct smb_t2rq *rqp, struct smb_connobj *layer, void smb_t2_done(struct smb_t2rq *t2p); int smb_t2_request(struct smb_t2rq *t2p); +int smb_t2_xnp(struct smb_share *ssp, uint16_t fid, + struct mbchain *send_mb, struct mdchain *recv_md, + uint32_t *data_out_sz, uint32_t *more, struct smb_cred *scrp); + 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, diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c index 0d3b21a888..bec61e4392 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c @@ -59,16 +59,6 @@ int nsmb_signing_fudge = 0; #endif -/* Mechanism definitions */ -static smb_sign_mech_t smb_mech_md5; - -void -smb_crypto_mech_init(void) -{ - if (smb_md5_getmech(&smb_mech_md5) != 0) - cmn_err(CE_NOTE, "nsmb can't get md5 mech"); -} - /* * This is called just after session setup completes, * at the top of smb_iod_vc_work(). Initialize signing. @@ -76,10 +66,17 @@ smb_crypto_mech_init(void) int smb_sign_init(smb_vc_t *vcp) { + int rc; ASSERT(vcp->vc_ssnkey != NULL); ASSERT(vcp->vc_mackey == NULL); + rc = smb_md5_getmech(&vcp->vc_signmech); + if (rc != 0) { + cmn_err(CE_NOTE, "smb can't get signing mechanism"); + return (EAUTH); + } + /* * Convert the session key to the MAC key. * SMB1 uses the whole session key. @@ -134,11 +131,10 @@ smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp, } s; } smbhdr; - /* Later: check vcp->sign_mech == NULL */ if (vcp->vc_mackey == NULL) return (-1); - if ((rc = smb_md5_init(&ctx, &smb_mech_md5)) != 0) + if ((rc = smb_md5_init(&ctx, &vcp->vc_signmech)) != 0) return (rc); /* Digest the MAC Key */ @@ -146,6 +142,7 @@ smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp, if (rc != 0) return (rc); + /* Our caller should ensure mp has a contiguous header */ ASSERT(m != NULL); ASSERT(MBLKL(m) >= SMB_HDRLEN); @@ -154,8 +151,6 @@ smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp, * fill in the sequence number, and digest. */ size = SMB_HDRLEN; - if (MBLKL(m) < size) - (void) pullupmsg(m, size); bcopy(m->b_rptr, smbhdr.r.raw, size); smbhdr.s.sig[0] = htolel(seqno); smbhdr.s.sig[1] = 0; @@ -192,7 +187,7 @@ smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp, * Finally, store the signature. * (first 8 bytes of the mac) */ - if (signature) + if (signature != NULL) bcopy(digest, signature, SMBSIGLEN); return (0); @@ -210,13 +205,10 @@ smb_rq_sign(struct smb_rq *rqp) int status; /* - * Our mblk allocation ensures this, - * but just in case... + * smb_rq_new() ensures this, + * but just in case.. */ - if (MBLKL(mp) < SMB_HDRLEN) { - if (!pullupmsg(mp, SMB_HDRLEN)) - return; - } + ASSERT(MBLKL(mp) >= SMB_HDRLEN); sigloc = mp->b_rptr + SMBSIGOFF; if (vcp->vc_mackey == NULL) { @@ -269,10 +261,8 @@ smb_rq_verify(struct smb_rq *rqp) SMBSDEBUG("empty reply\n"); return (0); } - if (MBLKL(mp) < SMB_HDRLEN) { - if (!pullupmsg(mp, SMB_HDRLEN)) - return (0); - } + + ASSERT(MBLKL(mp) >= SMB_HDRLEN); sigloc = mp->b_rptr + SMBSIGOFF; /* diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c index 47f9a201cc..566f131316 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c @@ -63,32 +63,18 @@ #define STYPE_LEN 8 /* share type strings */ -/* - * 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) - struct smb_dialect { int d_id; const char *d_name; }; -static struct smb_dialect smb_dialects[] = { - {SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"}, - {SMB_DIALECT_COREPLUS, "MICROSOFT NETWORKS 1.03"}, - {SMB_DIALECT_LANMAN1_0, "MICROSOFT NETWORKS 3.0"}, - {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"}, - {SMB_DIALECT_LANMAN2_0, "LM1.2X002"}, - {SMB_DIALECT_LANMAN2_1, "LANMAN2.1"}, +static struct smb_dialect smb_dialects[3] = { {SMB_DIALECT_NTLM0_12, "NT LANMAN 1.0"}, {SMB_DIALECT_NTLM0_12, "NT LM 0.12"}, +#define NDIALECT_SMB1 2 + {SMB_DIALECT_SMB2_FF, "SMB 2.???"}, +#define NDIALECT_SMB2 3 }; -static uint_t smb_ndialect = - sizeof (smb_dialects) / sizeof (smb_dialects[0]); static const uint32_t smb_clnt_caps_mask = SMB_CAP_UNICODE | @@ -109,16 +95,6 @@ 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, uint16_t fid, - uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); -static int smb_smb_write(struct smb_share *ssp, uint16_t fid, - uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); - -static int smb_smb_readx(struct smb_share *ssp, uint16_t fid, - uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); -static int smb_smb_writex(struct smb_share *ssp, uint16_t fid, - uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); - int smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) { @@ -131,6 +107,7 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) int err, sblen, tlen; uint8_t wc, eklen; uint16_t dindex, bc; + uint16_t ndialects; boolean_t will_sign = B_FALSE; /* @@ -168,6 +145,14 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) sv->sv_maxvcs = 1; sv->sv_maxtx = 1024; + /* + * Should we offer the magic SMB2 dialect? + */ + if (vcp->vc_ssn.ssn_maxver >= SMB2_DIALECT_BASE) + ndialects = NDIALECT_SMB2; + else + ndialects = NDIALECT_SMB1; + err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp); if (err) return (err); @@ -179,7 +164,7 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) smb_rq_wstart(rqp); smb_rq_wend(rqp); smb_rq_bstart(rqp); - for (dindex = 0; dindex < smb_ndialect; dindex++) { + for (dindex = 0; dindex < ndialects; dindex++) { dp = &smb_dialects[dindex]; mb_put_uint8(mbp, SMB_DT_DIALECT); tlen = strlen(dp->d_name) + 1; @@ -191,10 +176,25 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) * Do the OTW call. */ err = smb_rq_internal(rqp, smb_timo_default); + /* + * If it's an SMB1-to-SMB2 negotiate response, + * call the special handler and then skip the + * whole rest of this function. + */ + if (err == EPROTO) { + err = smb2_parse_smb1nego_resp(rqp); + smb_rq_done(rqp); + return (err); + } if (err) { SMBSDEBUG("smb_rq_internal, err %d", err); goto errout; } + /* Should only get status success. */ + if (rqp->sr_error != NT_STATUS_SUCCESS) { + err = ENOTSUP; + goto errout; + } /* * Decode the response @@ -208,7 +208,7 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) err = md_get_uint16le(mdp, &dindex); if (err != 0) goto errout; - if (dindex >= smb_ndialect) { + if (dindex >= ndialects) { SMBERROR("Invalid dialect index from server: %s\n", vcp->vc_srvname); err = EBADRPC; @@ -299,7 +299,7 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) SMBSDEBUG("Security signatures: %d", (int)will_sign); if (will_sign) { - vcp->vc_flags |= SMBV_WILL_SIGN; + vcp->vc_flags |= SMBV_SIGNING; vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; /* @@ -321,6 +321,15 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) vcp->vc_hflags2 &= ~SMB_FLAGS2_ERR_STATUS; } + /* + * Warn if they don't support SMB_CAP_NT_SMBS + * (We'll try to use NtCreate anyway) + */ + if ((sv->sv_caps & SMB_CAP_NT_SMBS) == 0) { + cmn_err(CE_NOTE, "%s does not support SMB_CAP_NT_SMBS", + vcp->vc_srvname); + } + /* * The rest of the message varies depending on * whether we've negotiated "extended security". @@ -495,13 +504,21 @@ smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred) /* * Run the request. The return value here should be the * return from this function, unless we fail decoding. - * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK. + * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and + * the caller expects EINPROGRESS for that case. */ ret = smb_rq_internal(rqp, smb_timo_logon); - if (ret != 0 && rqp->sr_error != - NT_STATUS_MORE_PROCESSING_REQUIRED) { - /* UID no longer valid. */ - vcp->vc_smbuid = 0; + if (ret != 0) + goto out; + switch (rqp->sr_error) { + case NT_STATUS_SUCCESS: + break; + case NT_STATUS_MORE_PROCESSING_REQUIRED: + /* Keep going, but return... */ + ret = EINPROGRESS; + break; + default: + ret = EAUTH; goto out; } @@ -550,12 +567,49 @@ smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred) */ out: + if (err != 0 && err != EINPROGRESS) { + /* UID no longer valid. */ + vcp->vc_smbuid = 0; + } if (rqp) smb_rq_done(rqp); return (ret); } +int +smb_smb_logoff(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. (5 sec.) + * We don't really care about the result here. + * Also, don't reconnect for this, of course! + */ + rqp->sr_flags |= SMBR_NORECONNECT; + error = smb_rq_internal(rqp, 5); + smb_rq_done(rqp); + return (error); +} + /* * Get the string representation of a share "use" type, * as needed for the "service" in tree connect. @@ -817,7 +871,7 @@ smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred) * Modern create/open of file or directory. */ int -smb_smb_ntcreate( +smb1_smb_ntcreate( struct smb_share *ssp, struct mbchain *name_mb, uint32_t cr_flags, /* create flags */ @@ -940,7 +994,7 @@ done: } int -smb_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime, +smb1_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime, struct smb_cred *scrp) { struct smb_rq rq, *rqp = &rq; @@ -1065,101 +1119,11 @@ smb_smb_close_prjob(struct smb_share *ssp, uint16_t fid, 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, uint16_t fid, uio_rw_t rw, - uio_t *uiop, smb_cred_t *scred, int timo) -{ - struct smb_vc *vcp = SSTOVC(ssp); - ssize_t save_resid; - uint32_t len, rlen, maxlen; - int error = 0; - int (*iofun)(struct smb_share *, uint16_t, uint32_t *, - uio_t *, smb_cred_t *, int); - - /* - * Determine which function to use, - * and the transfer size per call. - */ - if (SMB_DIALECT(vcp) >= SMB_DIALECT_NTLM0_12) { - /* - * Using NT LM 0.12, so readx, writex. - * Make sure we can represent the offset. - */ - if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 && - (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX) - return (EFBIG); - - if (rw == UIO_READ) { - iofun = smb_smb_readx; - if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) - maxlen = SMB_MAX_LARGE_RW_SIZE; - else - maxlen = vcp->vc_rxmax; - } else { /* UIO_WRITE */ - iofun = smb_smb_writex; - if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) - maxlen = SMB_MAX_LARGE_RW_SIZE; - else - maxlen = vcp->vc_wxmax; - } - } else { - /* - * Using the old SMB_READ and SMB_WRITE so - * we're limited to 32-bit offsets, etc. - * XXX: Someday, punt the old dialects. - */ - if ((uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX) - return (EFBIG); - - if (rw == UIO_READ) { - iofun = smb_smb_read; - maxlen = vcp->vc_rxmax; - } else { /* UIO_WRITE */ - iofun = smb_smb_write; - maxlen = vcp->vc_wxmax; - } - } - - save_resid = uiop->uio_resid; - while (uiop->uio_resid > 0) { - /* Lint: uio_resid may be 64-bits */ - rlen = len = (uint32_t)min(maxlen, uiop->uio_resid); - error = (*iofun)(ssp, fid, &rlen, uiop, scred, timo); - - /* - * Note: the iofun called uio_update, so - * not doing that here as one might expect. - * - * Quit the loop either on error, or if we - * transferred less then requested. - */ - if (error || (rlen < len)) - break; - - timo = 0; /* only first I/O should wait */ - } - if (error && (save_resid != uiop->uio_resid)) { - /* - * Stopped on an error after having - * successfully transferred data. - * Suppress this error. - */ - SMBSDEBUG("error %d suppressed\n", error); - error = 0; - } - - return (error); -} - -static int -smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, +smb_smb_readx(smb_fh_t *fhp, uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo) { + struct smb_share *ssp = FHTOSS(fhp); struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; @@ -1181,7 +1145,7 @@ smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, mb_put_uint8(mbp, 0xff); /* no secondary command */ mb_put_uint8(mbp, 0); /* MBZ */ mb_put_uint16le(mbp, 0); /* offset to secondary */ - mb_put_uint16le(mbp, fid); + mb_put_uint16le(mbp, fhp->fh_fid1); mb_put_uint32le(mbp, offlo); /* offset (low part) */ mb_put_uint16le(mbp, lenlo); /* MaxCount */ mb_put_uint16le(mbp, 1); /* MinCount */ @@ -1251,10 +1215,11 @@ out: return (error); } -static int -smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, +int +smb_smb_writex(smb_fh_t *fhp, uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo) { + struct smb_share *ssp = FHTOSS(fhp); struct smb_rq *rqp; struct mbchain *mbp; struct mdchain *mdp; @@ -1276,7 +1241,7 @@ smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, mb_put_uint8(mbp, 0xff); /* no secondary command */ mb_put_uint8(mbp, 0); /* MBZ */ mb_put_uint16le(mbp, 0); /* offset to secondary */ - mb_put_uint16le(mbp, fid); + mb_put_uint16le(mbp, fhp->fh_fid1); mb_put_uint32le(mbp, offlo); /* offset (low part) */ mb_put_uint32le(mbp, 0); /* MBZ (timeout) */ mb_put_uint16le(mbp, 0); /* !write-thru */ @@ -1324,148 +1289,13 @@ out: return (error); } -static int -smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, - uio_t *uiop, smb_cred_t *scred, int timo) -{ - struct smb_rq *rqp; - struct mbchain *mbp; - struct mdchain *mdp; - int error; - uint32_t off32; - uint16_t bc, cnt, dlen, rcnt, todo; - uint8_t wc; - - ASSERT(uiop->uio_loffset <= UINT32_MAX); - off32 = (uint32_t)uiop->uio_loffset; - ASSERT(*lenp <= UINT16_MAX); - cnt = (uint16_t)*lenp; - /* This next is an "estimate" of planned reads. */ - todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX); - - 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_uint16le(mbp, fid); - mb_put_uint16le(mbp, cnt); - mb_put_uint32le(mbp, off32); - mb_put_uint16le(mbp, todo); - smb_rq_wend(rqp); - smb_rq_bstart(rqp); - smb_rq_bend(rqp); - - if (timo == 0) - timo = smb_timo_read; - error = smb_rq_simple_timed(rqp, timo); - if (error) - goto out; - smb_rq_getreply(rqp, &mdp); - error = md_get_uint8(mdp, &wc); - if (error) - goto out; - if (wc != 5) { - error = EBADRPC; - goto out; - } - md_get_uint16le(mdp, &rcnt); /* ret. count */ - md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); /* res. */ - md_get_uint16le(mdp, &bc); /* byte count */ - md_get_uint8(mdp, NULL); /* buffer format */ - error = md_get_uint16le(mdp, &dlen); /* data len */ - if (error) - goto out; - if (dlen < rcnt) { - SMBSDEBUG("oops: dlen=%d rcnt=%d\n", - (int)dlen, (int)rcnt); - rcnt = dlen; - } - if (rcnt == 0) { - *lenp = 0; - goto out; - } - /* paranoid */ - if (rcnt > cnt) { - SMBSDEBUG("bad server! rcnt %d, cnt %d\n", - (int)rcnt, (int)cnt); - rcnt = cnt; - } - error = md_get_uio(mdp, uiop, (int)rcnt); - if (error) - goto out; - - /* success */ - *lenp = (int)rcnt; - -out: - smb_rq_done(rqp); - return (error); -} - -static int -smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, - uio_t *uiop, smb_cred_t *scred, int timo) -{ - struct smb_rq *rqp; - struct mbchain *mbp; - struct mdchain *mdp; - int error; - uint32_t off32; - uint16_t cnt, rcnt, todo; - uint8_t wc; - - ASSERT(uiop->uio_loffset <= UINT32_MAX); - off32 = (uint32_t)uiop->uio_loffset; - ASSERT(*lenp <= UINT16_MAX); - cnt = (uint16_t)*lenp; - /* This next is an "estimate" of planned writes. */ - todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX); - - 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_uint16le(mbp, fid); - mb_put_uint16le(mbp, cnt); - mb_put_uint32le(mbp, off32); - mb_put_uint16le(mbp, todo); - smb_rq_wend(rqp); - smb_rq_bstart(rqp); - mb_put_uint8(mbp, SMB_DT_DATA); - mb_put_uint16le(mbp, cnt); - - error = mb_put_uio(mbp, uiop, *lenp); - if (error) - goto out; - smb_rq_bend(rqp); - if (timo == 0) - timo = smb_timo_write; - error = smb_rq_simple_timed(rqp, timo); - if (error) - goto out; - smb_rq_getreply(rqp, &mdp); - error = md_get_uint8(mdp, &wc); - if (error) - goto out; - if (wc != 1) { - error = EBADRPC; - goto out; - } - error = md_get_uint16le(mdp, &rcnt); - if (error) - goto out; - *lenp = rcnt; - -out: - smb_rq_done(rqp); - return (error); -} - static u_int32_t smbechoes = 0; +/* + * Note: the IOD calls this, so this request must not wait for + * connection state changes, etc. (uses smb_rq_internal) + */ int smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo) { @@ -1483,13 +1313,8 @@ smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo) 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_NORECONNECT; - error = smb_rq_simple_timed(rqp, timo); + error = smb_rq_internal(rqp, timo); SMBSDEBUG("%d\n", error); smb_rq_done(rqp); return (error); diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h index 48815ff709..b780f9b21b 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h @@ -43,8 +43,16 @@ #include #include #include +#include #include +/* + * Possible lock commands + */ +#define SMB_LOCK_EXCL 0 +#define SMB_LOCK_SHARED 1 +#define SMB_LOCK_RELEASE 2 + struct msgb; /* avoiding sys/stream.h here */ /* Helper function for SMBERROR */ @@ -120,29 +128,42 @@ extern int smb_timo_append; extern dev_t nsmb_dev_tcp; extern dev_t nsmb_dev_tcp6; -#define EMOREDATA (0x7fff) +/* + * Tunable timeout values. See: smb2_smb.c + */ +extern int smb2_timo_notice; +extern int smb2_timo_default; +extern int smb2_timo_open; +extern int smb2_timo_read; +extern int smb2_timo_write; +extern int smb2_timo_append; void smb_credinit(struct smb_cred *scred, cred_t *cr); void smb_credrele(struct smb_cred *scred); -void smb_oldlm_hash(const char *apwd, uchar_t *hash); -void smb_ntlmv1hash(const char *apwd, uchar_t *hash); -void smb_ntlmv2hash(const uchar_t *v1hash, const char *user, - const char *destination, uchar_t *v2hash); - -int smb_lmresponse(const uchar_t *hash, const uchar_t *C8, uchar_t *RN); -int smb_ntlmv2response(const uchar_t *hash, const uchar_t *C8, - const uchar_t *blob, size_t bloblen, uchar_t **RN, size_t *RNlen); int smb_maperror(int eclass, int eno); int smb_maperr32(uint32_t eno); uint_t smb_doserr2status(int, int); +int smb_get_dstring(struct mdchain *mdc, struct smb_vc *vcp, + char *outbuf, size_t *outlen, int inlen); 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_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb, + uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc, + uint32_t disp, uint32_t createopt, uint32_t impersonate, + struct smb_cred *scrp, smb_fh_t *fhp, + uint32_t *cr_act_p, struct smbfattr *fap); + +int smb_smb_close(struct smb_share *ssp, smb_fh_t *fhp, + struct smb_cred *scrp); + +int smb_rwuio(smb_fh_t *fhp, uio_rw_t rw, + uio_t *uiop, smb_cred_t *scred, int timo); int smb_cmp_sockaddr(struct sockaddr *, struct sockaddr *); struct sockaddr *smb_dup_sockaddr(struct sockaddr *sa); @@ -155,53 +176,80 @@ int smb_calcv2mackey(struct smb_vc *, const uchar_t *, const uchar_t *, size_t); int smb_calcmackey(struct smb_vc *, const uchar_t *, const uchar_t *, size_t); -void smb_crypto_mech_init(void); +int smb2_sign_init(struct smb_vc *); +void smb2_rq_sign(struct smb_rq *); +int smb2_rq_verify(struct smb_rq *); /* * 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_logoff(struct smb_vc *vcp, struct smb_cred *scred); int smb_smb_echo(smb_vc_t *vcp, smb_cred_t *scred, int timo); int smb_smb_treeconnect(smb_share_t *ssp, smb_cred_t *scred); int smb_smb_treedisconnect(smb_share_t *ssp, smb_cred_t *scred); -int -smb_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb, +int smb1_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb, uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc, uint32_t disp, uint32_t createopt, uint32_t impersonate, struct smb_cred *scrp, uint16_t *fidp, uint32_t *cr_act_p, struct smbfattr *fap); -int smb_smb_close(struct smb_share *ssp, uint16_t fid, +int smb1_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime, struct smb_cred *scrp); -int -smb_smb_open_prjob(struct smb_share *ssp, char *title, +int smb_smb_open_prjob(struct smb_share *ssp, char *title, uint16_t setuplen, uint16_t mode, struct smb_cred *scrp, uint16_t *fidp); int smb_smb_close_prjob(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp); -int smb_rwuio(smb_share_t *ssp, uint16_t fid, uio_rw_t rw, +int smb_smb_readx(smb_fh_t *fhp, uint32_t *lenp, + uio_t *uiop, smb_cred_t *scred, int timo); +int smb_smb_writex(smb_fh_t *fhp, uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); /* - * time conversions + * SMB2 protocol level functions */ +int smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred); +int smb2_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred); +int smb2_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred); +int smb2_smb_echo(smb_vc_t *vcp, smb_cred_t *scred, int timo); +int smb2_smb_treeconnect(smb_share_t *ssp, smb_cred_t *scred); +int smb2_smb_treedisconnect(smb_share_t *ssp, smb_cred_t *scred); + +int +smb2_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb, + struct mbchain *cctx_in, struct mdchain *cctx_out, + uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc, + uint32_t disp, uint32_t createopt, uint32_t impersonate, + struct smb_cred *scrp, smb2fid_t *fidp, + uint32_t *cr_act_p, struct smbfattr *fap); + +int smb2_smb_close(struct smb_share *ssp, smb2fid_t *fid, + struct smb_cred *scrp); + +int smb2_smb_ioctl(struct smb_share *ssp, smb2fid_t *fid, + struct mbchain *data_in, struct mdchain *data_out, + uint32_t *data_out_sz, /* max / returned */ + uint32_t ctl_code, struct smb_cred *scrp); + +int smb2_smb_read(smb_fh_t *fhp, uint32_t *lenp, + uio_t *uiop, smb_cred_t *scred, int timo); +int smb2_smb_write(smb_fh_t *fhp, uint32_t *lenp, + uio_t *uiop, smb_cred_t *scred, int timo); -void smb_time_init(void); -void smb_time_fini(void); +/* + * time conversions + */ 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, struct timespec *tsp); void smb_time_local2NT(struct timespec *tsp, 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); #endif /* !_NETSMB_SMB_SUBR_H_ */ diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c index dc0e824e5e..bf1e605187 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c @@ -86,6 +86,14 @@ smb_credrele(struct smb_cred *scred) } } +#ifndef _KERNEL +/* ARGSUSED */ +void +smb_debugmsg(const char *func, char *msg) +{ +} +#endif /* _KERNEL */ + /* * Helper for the SMBERROR macro, etc. * This is also a good place for a breakpoint @@ -108,6 +116,9 @@ smb_errmsg(int cel, const char *func_name, const char *fmt, ...) DTRACE_PROBE2(debugmsg2, (char *), func_name, (char *), buf); +#ifndef _KERNEL + smb_debugmsg(func_name, buf); +#endif } else { /* * This is one of our xxxERROR macros. @@ -161,6 +172,9 @@ m_dumpm(mblk_t *m) #ifndef ETIME #define ETIME ETIMEDOUT #endif +#ifndef EMOREDATA +#define EMOREDATA (0x7fff) +#endif /* * Log any un-handled NT or DOS errors we encounter. @@ -597,14 +611,6 @@ static const nt2doserr_t nt2doserr[] = { {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}, @@ -1013,13 +1019,90 @@ smb_maperror(int eclass, int eno) return (EIO); } -#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 +/* + * Decode an SMB OTW string (Unicode or OEM chars) + * converting to UTF-8 in the output buffer. + * outlen is in/out (max size on input) + * insize is the wire size (2 * chars if unicode) + * The output string is null terminated. + * Output length does not include the null. + */ +int +smb_get_dstring(struct mdchain *mdc, struct smb_vc *vcp, + char *outbuf, size_t *outlen, int insize) +{ + uint16_t convbuf[SMALL_CONV]; + uint16_t *cbuf; + size_t cbufalloc, inlen, outsize; + int error; + + if (insize <= 0) + return (0); + /* Note: inlen is UTF-16 symbols. */ + inlen = insize / 2; + + if (*outlen < 2) + return (EINVAL); + outsize = *outlen - 1; /* room for null */ + + /* + * Get a buffer for the conversion and fill it. + * Use stack buffer if the string is + * small enough, else allocate. + */ + if (insize < sizeof (convbuf)) { + cbufalloc = 0; + cbuf = convbuf; + } else { + cbufalloc = insize + 2; + cbuf = kmem_alloc(cbufalloc, KM_SLEEP); + } + error = md_get_mem(mdc, cbuf, insize, MB_MSYSTEM); + if (error != 0) + goto out; + cbuf[inlen] = 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) { + *outlen = strlcpy(outbuf, (char *)cbuf, outsize); + if (*outlen > outsize) { + *outlen = outsize; + error = E2BIG; + } + } else { + /* + * Convert from UTF-16 to UTF-8 + */ + error = uconv_u16tou8(cbuf, &inlen, + (uchar_t *)outbuf, outlen, + UCONV_IN_LITTLE_ENDIAN); + if (error == 0) { + outbuf[*outlen] = '\0'; + } + } + + ASSERT(*outlen == strlen(outbuf)); + +out: + if (cbufalloc != 0) + kmem_free(cbuf, cbufalloc); + + return (error); +} + +/* + * It's surprising that this function does utf8-ucs2 conversion. + * One would expect only smb_put_dstring to do that. + * Fixing that will require changing a bunch of callers. XXX + */ /*ARGSUSED*/ int smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src, @@ -1097,3 +1180,130 @@ smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src, return (error); } +int +smb_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb, + uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc, + uint32_t disp, uint32_t createopt, uint32_t impersonate, + struct smb_cred *scrp, smb_fh_t *fhp, + uint32_t *cr_act_p, struct smbfattr *fap) +{ + int err; + + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + err = smb2_smb_ntcreate(ssp, name_mb, NULL, NULL, + crflag, req_acc, efa, sh_acc, disp, createopt, + impersonate, scrp, &fhp->fh_fid2, cr_act_p, fap); + } else { + err = smb1_smb_ntcreate(ssp, name_mb, crflag, req_acc, + efa, sh_acc, disp, createopt, impersonate, scrp, + &fhp->fh_fid1, cr_act_p, fap); + } + return (err); +} + +int +smb_smb_close(struct smb_share *ssp, smb_fh_t *fhp, + struct smb_cred *scrp) +{ + int err; + + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + err = smb2_smb_close(ssp, &fhp->fh_fid2, scrp); + } else { + err = smb1_smb_close(ssp, fhp->fh_fid1, NULL, scrp); + } + + return (err); +} + +/* + * 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.) + */ +uint32_t smb1_large_io_max = (60*1024); + +/* + * Common function for read/write with UIO. + * Called by netsmb smb_usr_rw, + * smbfs_readvnode, smbfs_writevnode + */ +int +smb_rwuio(smb_fh_t *fhp, uio_rw_t rw, + uio_t *uiop, smb_cred_t *scred, int timo) +{ + struct smb_share *ssp = FHTOSS(fhp); + struct smb_vc *vcp = SSTOVC(ssp); + ssize_t save_resid; + uint32_t len, rlen, maxlen; + int error = 0; + int (*iofun)(smb_fh_t *, uint32_t *, + uio_t *, smb_cred_t *, int); + + /* After reconnect, the fid is invalid. */ + if (fhp->fh_vcgenid != ssp->ss_vcgenid) + return (ESTALE); + + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + if (rw == UIO_READ) { + iofun = smb2_smb_read; + maxlen = vcp->vc_sopt.sv2_maxread; + } else { /* UIO_WRITE */ + iofun = smb2_smb_write; + maxlen = vcp->vc_sopt.sv2_maxwrite; + } + } else { + /* + * Using NT LM 0.12, so readx, writex. + * Make sure we can represent the offset. + */ + if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 && + (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX) + return (EFBIG); + + if (rw == UIO_READ) { + iofun = smb_smb_readx; + if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) + maxlen = smb1_large_io_max; + else + maxlen = vcp->vc_rxmax; + } else { /* UIO_WRITE */ + iofun = smb_smb_writex; + if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) + maxlen = smb1_large_io_max; + else + maxlen = vcp->vc_wxmax; + } + } + + save_resid = uiop->uio_resid; + while (uiop->uio_resid > 0) { + /* Lint: uio_resid may be 64-bits */ + rlen = len = (uint32_t)min(maxlen, uiop->uio_resid); + error = (*iofun)(fhp, &rlen, uiop, scred, timo); + + /* + * Note: the iofun called uio_update, so + * not doing that here as one might expect. + * + * Quit the loop either on error, or if we + * transferred less then requested. + */ + if (error || (rlen < len)) + break; + + timo = 0; /* only first I/O should wait */ + } + if (error && (save_resid != uiop->uio_resid)) { + /* + * Stopped on an error after having + * successfully transferred data. + * Suppress this error. + */ + SMBSDEBUG("error %d suppressed\n", error); + error = 0; + } + + return (error); +} diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c index e984ded911..0116d6ea6e 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c @@ -35,6 +35,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -54,61 +56,6 @@ #include #include -/* - * 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; - -/* Lock for the lastxxx variables */ -static kmutex_t lastdt_lock; - /* * Number of seconds between 1970 and 1601 year * (134774 days) @@ -193,161 +140,3 @@ smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp) tsp->tv_sec = seconds + tzoff * 60; tsp->tv_nsec = 0; } - -/* - * Time conversions to/from DOS format, for old dialects. - */ - -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; - - mutex_enter(&lastdt_lock); - - /* - * 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 (dhp) - *dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000; - - *ddp = lastddate; - *dtp = lastdtime; - - mutex_exit(&lastdt_lock); -} - -/* - * 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. - */ - mutex_enter(&lastdt_lock); - 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; - mutex_exit(&lastdt_lock); -} - -void -smb_time_init(void) -{ - mutex_init(&lastdt_lock, NULL, MUTEX_DEFAULT, NULL); -} - -void -smb_time_fini(void) -{ - mutex_destroy(&lastdt_lock); -} diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h index dc44fcc755..1060139491 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h @@ -70,12 +70,12 @@ struct smb_tran_desc { int (*tr_create)(struct smb_vc *vcp, cred_t *cr); int (*tr_done)(struct smb_vc *vcp); int (*tr_bind)(struct smb_vc *vcp, struct sockaddr *sap); + int (*tr_unbind)(struct smb_vc *vcp); int (*tr_connect)(struct smb_vc *vcp, struct sockaddr *sap); int (*tr_disconnect)(struct smb_vc *vcp); int (*tr_send)(struct smb_vc *vcp, mblk_t *m); int (*tr_recv)(struct smb_vc *vcp, mblk_t **mpp); int (*tr_poll)(struct smb_vc *vcp, int ticks); - int (*tr_loan_fp)(struct smb_vc *, struct file *, cred_t *cr); int (*tr_getparam)(struct smb_vc *vcp, int param, void *data); int (*tr_setparam)(struct smb_vc *vcp, int param, void *data); int (*tr_fatal)(struct smb_vc *vcp, int error); @@ -86,12 +86,12 @@ typedef struct smb_tran_desc smb_tran_desc_t; #define SMB_TRAN_CREATE(vcp, cr) (vcp)->vc_tdesc->tr_create(vcp, cr) #define SMB_TRAN_DONE(vcp) (vcp)->vc_tdesc->tr_done(vcp) #define SMB_TRAN_BIND(vcp, sap) (vcp)->vc_tdesc->tr_bind(vcp, sap) +#define SMB_TRAN_UNBIND(vcp) (vcp)->vc_tdesc->tr_unbind(vcp) #define SMB_TRAN_CONNECT(vcp, sap) (vcp)->vc_tdesc->tr_connect(vcp, sap) #define SMB_TRAN_DISCONNECT(vcp) (vcp)->vc_tdesc->tr_disconnect(vcp) #define SMB_TRAN_SEND(vcp, m) (vcp)->vc_tdesc->tr_send(vcp, m) #define SMB_TRAN_RECV(vcp, m) (vcp)->vc_tdesc->tr_recv(vcp, m) #define SMB_TRAN_POLL(vcp, t) (vcp)->vc_tdesc->tr_poll(vcp, t) -#define SMB_TRAN_LOAN_FP(vcp, f, cr) (vcp)->vc_tdesc->tr_loan_fp(vcp, f, cr) #define SMB_TRAN_GETPARAM(vcp, par, data) \ (vcp)->vc_tdesc->tr_getparam(vcp, par, data) #define SMB_TRAN_SETPARAM(vcp, par, data) \ diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c index 733ff9d078..849e91637e 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c @@ -558,110 +558,30 @@ smb_nbst_done(struct smb_vc *vcp) return (0); } -/* - * XXX - Later, get rid of nb_loan_fp, nb_unloan_fp - * - * Loan a transport file pointer (from user space) to this - * IOD endpoint. There should be no other thread using this - * endpoint when we do this, but lock for consistency. - */ -static int -nb_loan_fp(struct nbpcb *nbp, struct file *fp, cred_t *cr) -{ - TIUSER *tiptr; - int err; - - err = t_kopen(fp, 0, 0, &tiptr, cr); - if (err != 0) - return (err); - - mutex_enter(&nbp->nbp_lock); - - nbp->nbp_tiptr = tiptr; - nbp->nbp_fmode = tiptr->fp->f_flag; - nbp->nbp_flags |= NBF_CONNECTED; - nbp->nbp_state = NBST_SESSION; - - mutex_exit(&nbp->nbp_lock); - - return (0); -} - -/* - * Take back the transport file pointer we previously loaned. - * It's possible there may be another thread in here, so let - * others get out of the way before we pull the rug out. - * - * Some notes about the locking here: The higher-level IOD code - * serializes activity such that at most one reader and writer - * thread can be active in this code (and possibly both). - * Keeping nbp_lock held during the activities of these two - * threads would lead to the possibility of nbp_lock being - * held by a blocked thread, so this instead sets one of the - * flags (NBF_SENDLOCK | NBF_RECVLOCK) when a sender or a - * receiver is active (respectively). Lastly, tear-down is - * the only tricky bit (here) where we must wait for any of - * these activities to get out of current calls so they will - * notice that we've turned off the NBF_CONNECTED flag. - */ -static void -nb_unloan_fp(struct nbpcb *nbp) -{ - - mutex_enter(&nbp->nbp_lock); - - nbp->nbp_flags &= ~NBF_CONNECTED; - while (nbp->nbp_flags & (NBF_SENDLOCK | NBF_RECVLOCK)) { - nbp->nbp_flags |= NBF_LOCKWAIT; - cv_wait(&nbp->nbp_cv, &nbp->nbp_lock); - } - if (nbp->nbp_frag != NULL) { - freemsg(nbp->nbp_frag); - nbp->nbp_frag = NULL; - } - if (nbp->nbp_tiptr != NULL) { - (void) t_kclose(nbp->nbp_tiptr, 0); - nbp->nbp_tiptr = NULL; - } - nbp->nbp_state = NBST_CLOSED; - - mutex_exit(&nbp->nbp_lock); -} - static int -smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr) +smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap) { struct nbpcb *nbp = vcp->vc_tdata; - int error = 0; + TIUSER *tiptr = nbp->nbp_tiptr; + int err; - /* - * Un-loan the existing one, if any. - */ - (void) nb_disconnect(nbp); - nb_unloan_fp(nbp); + /* Only default bind supported. */ + if (sap != NULL) + return (ENOTSUP); - /* - * Loan the new one passed in. - */ - if (fp != NULL) { - error = nb_loan_fp(nbp, fp, cr); - } + err = t_kbind(tiptr, NULL, NULL); - return (error); + return (err); } static int -smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap) +smb_nbst_unbind(struct smb_vc *vcp) { struct nbpcb *nbp = vcp->vc_tdata; TIUSER *tiptr = nbp->nbp_tiptr; int err; - /* Only default bind supported. */ - if (sap != NULL) - return (ENOTSUP); - - err = t_kbind(tiptr, NULL, NULL); + err = t_kunbind(tiptr); return (err); } @@ -956,7 +876,7 @@ smb_nbst_setparam(struct smb_vc *vcp, int param, void *data) return (EPROTO); } - if (ores.flags != T_SUCCESS) { + if ((ores.flags & T_SUCCESS) == 0) { cmn_err(CE_NOTE, "smb_nbst_setparam: " "flags 0x%x, status 0x%x", (int)ores.flags, (int)opts.oh.status); @@ -989,12 +909,12 @@ struct smb_tran_desc smb_tran_nbtcp_desc = { smb_nbst_create, smb_nbst_done, smb_nbst_bind, + smb_nbst_unbind, smb_nbst_connect, smb_nbst_disconnect, smb_nbst_send, smb_nbst_recv, smb_nbst_poll, - smb_nbst_loan_fp, smb_nbst_getparam, smb_nbst_setparam, smb_nbst_fatal, diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c index 5209732a1e..d83c3a086c 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c @@ -53,6 +53,7 @@ #include +#include #include #include #include @@ -102,96 +103,83 @@ smb_usr_xnp(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) { struct smb_cred scred; struct smb_share *ssp; + struct smb_fh *fhp; smbioc_xnp_t *ioc = NULL; - struct smb_t2rq *t2p = NULL; - struct mdchain *mdp; - int err, len, mbseg; - uint16_t setup[2]; + struct mbchain send_mb; + struct mdchain recv_md; + uint32_t rdlen; + int err, mbseg; - /* This ioctl requires a share. */ - if ((ssp = sdp->sd_share) == NULL) - return (ENOTCONN); + /* This ioctl requires a file handle. */ + if ((fhp = sdp->sd_fh) == NULL) + return (EINVAL); + ssp = FHTOSS(fhp); + + /* After reconnect, force close+reopen */ + if (fhp->fh_vcgenid != ssp->ss_vcgenid) + return (ESTALE); + + bzero(&send_mb, sizeof (send_mb)); + bzero(&recv_md, sizeof (recv_md)); - smb_credinit(&scred, cr); ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { err = EFAULT; goto out; } - /* See ddi_copyin, ddi_copyout */ - mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER; - /* - * Fill in the FID for libsmbfs transact named pipe. + * Copyin the send data, into an mbchain, + * save output buffer size. */ - if (ioc->ioc_fh == -1) { - if (sdp->sd_vcgenid != ssp->ss_vcgenid) { - err = ESTALE; - goto out; - } - ioc->ioc_fh = sdp->sd_smbfid; - } - - setup[0] = TRANS_TRANSACT_NAMED_PIPE; - setup[1] = (uint16_t)ioc->ioc_fh; - - t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP); - err = smb_t2_init(t2p, SSTOCP(ssp), setup, 2, &scred); - if (err) - goto out; - t2p->t2_setupcount = 2; - t2p->t2_setupdata = setup; - - t2p->t_name = "\\PIPE\\"; - t2p->t_name_len = 6; - - t2p->t2_maxscount = 0; - t2p->t2_maxpcount = 0; - t2p->t2_maxdcount = ioc->ioc_rdlen; - - /* Transmit parameters (none) */ - - /* Transmit data */ - err = smb_cpdatain(&t2p->t2_tdata, - ioc->ioc_tdlen, ioc->ioc_tdata, mbseg); + mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER; + err = smb_cpdatain(&send_mb, ioc->ioc_tdlen, ioc->ioc_tdata, mbseg); if (err) goto out; + rdlen = ioc->ioc_rdlen; - err = smb_t2_request(t2p); - - /* No returned parameters. */ + /* + * Run the SMB2 ioctl or SMB1 trans2 + */ + smb_credinit(&scred, cr); + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + err = smb2_smb_ioctl(ssp, &fhp->fh_fid2, + &send_mb, &recv_md, &rdlen, + FSCTL_PIPE_TRANSCEIVE, &scred); + } else { + err = smb_t2_xnp(ssp, fhp->fh_fid1, + &send_mb, &recv_md, &rdlen, + &ioc->ioc_more, &scred); + } + smb_credrele(&scred); /* Copyout returned data. */ - mdp = &t2p->t2_rdata; - if (err == 0 && mdp->md_top != NULL) { - /* User's buffer large enough? */ - len = m_fixhdr(mdp->md_top); + if (err == 0 && recv_md.md_top != NULL) { + /* User's buffer large enough for copyout? */ + size_t len = m_fixhdr(recv_md.md_top); if (len > ioc->ioc_rdlen) { err = EMSGSIZE; goto out; } - ioc->ioc_rdlen = (ushort_t)len; - err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg); + err = md_get_mem(&recv_md, ioc->ioc_rdata, len, mbseg); if (err) goto out; } else ioc->ioc_rdlen = 0; - if (t2p->t2_sr_error == NT_STATUS_BUFFER_OVERFLOW) + /* Tell caller received length */ + if (rdlen <= ioc->ioc_rdlen) { + /* Normal case */ + ioc->ioc_rdlen = rdlen; + } else { + /* Buffer overlow. Leave ioc_rdlen */ ioc->ioc_more = 1; + } (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); - out: - if (t2p != NULL) { - /* Note: t2p->t_name no longer allocated */ - smb_t2_done(t2p); - kmem_free(t2p, sizeof (*t2p)); - } kmem_free(ioc, sizeof (*ioc)); - smb_credrele(&scred); return (err); } @@ -219,22 +207,22 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) { struct smb_cred scred; struct smb_share *ssp; + struct smb_fh *fhp; smbioc_rw_t *ioc = NULL; struct iovec aiov[1]; struct uio auio; - uint16_t fh; int err; uio_rw_t rw; - /* This ioctl requires a share. */ - if ((ssp = sdp->sd_share) == NULL) - return (ENOTCONN); + /* This ioctl requires a file handle. */ + if ((fhp = sdp->sd_fh) == NULL) + return (EINVAL); + ssp = FHTOSS(fhp); /* After reconnect, force close+reopen */ - if (sdp->sd_vcgenid != ssp->ss_vcgenid) + if (fhp->fh_vcgenid != ssp->ss_vcgenid) return (ESTALE); - smb_credinit(&scred, cr); ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { err = EFAULT; @@ -253,15 +241,6 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) goto out; } - /* - * If caller passes -1 in ioc_fh, then - * use the FID from SMBIOC_NTCREATE. - */ - if (ioc->ioc_fh == -1) - fh = (uint16_t)sdp->sd_smbfid; - else - fh = (uint16_t)ioc->ioc_fh; - aiov[0].iov_base = ioc->ioc_base; aiov[0].iov_len = (size_t)ioc->ioc_cnt; @@ -273,7 +252,9 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) auio.uio_fmode = 0; auio.uio_resid = (size_t)ioc->ioc_cnt; - err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0); + smb_credinit(&scred, cr); + err = smb_rwuio(fhp, rw, &auio, &scred, 0); + smb_credrele(&scred); /* * On return ioc_cnt holds the @@ -285,7 +266,6 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) out: kmem_free(ioc, sizeof (*ioc)); - smb_credrele(&scred); return (err); } @@ -300,20 +280,20 @@ smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) struct smb_cred scred; struct mbchain name_mb; struct smb_share *ssp; + struct smb_fh *fhp = NULL; smbioc_ntcreate_t *ioc = NULL; - uint16_t fid; int err, nmlen; + mb_init(&name_mb); + /* This ioctl requires a share. */ if ((ssp = sdp->sd_share) == NULL) return (ENOTCONN); - /* Must not be already open. */ - if (sdp->sd_smbfid != -1) + /* Must not already have a file handle. */ + if (sdp->sd_fh != NULL) return (EINVAL); - mb_init(&name_mb); - smb_credinit(&scred, cr); ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { err = EFAULT; @@ -329,7 +309,14 @@ smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) if (err != 0) goto out; - /* Do the OtW open, save the FID. */ + err = smb_fh_create(ssp, &fhp); + if (err != 0) + goto out; + + /* + * Do the OtW open, save the FID. + */ + smb_credinit(&scred, cr); err = smb_smb_ntcreate(ssp, &name_mb, 0, /* create flags */ ioc->ioc_req_acc, @@ -339,18 +326,22 @@ smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) ioc->ioc_creat_opts, NTCREATEX_IMPERSONATION_IMPERSONATION, &scred, - &fid, + fhp, NULL, NULL); + smb_credrele(&scred); if (err != 0) goto out; - sdp->sd_smbfid = fid; - sdp->sd_vcgenid = ssp->ss_vcgenid; + fhp->fh_rights = ioc->ioc_req_acc; + smb_fh_opened(fhp); + sdp->sd_fh = fhp; + fhp = NULL; out: + if (fhp != NULL) + smb_fh_rele(fhp); kmem_free(ioc, sizeof (*ioc)); - smb_credrele(&scred); mb_done(&name_mb); return (err); @@ -363,11 +354,17 @@ out: int smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) { + static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS; struct smb_cred scred; + struct mbchain name_mb; struct smb_share *ssp; + struct smb_fh *fhp = NULL; smbioc_printjob_t *ioc = NULL; - uint16_t fid; - int err; + int err, cklen, nmlen; + uint32_t access = SA_RIGHT_FILE_WRITE_DATA | + SA_RIGHT_FILE_READ_ATTRIBUTES; + + mb_init(&name_mb); /* This ioctl requires a share. */ if ((ssp = sdp->sd_share) == NULL) @@ -377,8 +374,8 @@ smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) if (ssp->ss_type != STYPE_PRINTQ) return (EINVAL); - /* Must not be already open. */ - if (sdp->sd_smbfid != -1) + /* Must not already have a file handle. */ + if (sdp->sd_fh != NULL) return (EINVAL); smb_credinit(&scred, cr); @@ -387,21 +384,68 @@ smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) err = EFAULT; goto out; } + + /* + * Use the print job title as the file name to open, but + * check for invalid characters first. See the notes in + * libsmbfs/smb/print.c about job name sanitizing. + */ ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0'; + nmlen = strnlen(ioc->ioc_title, SMBIOC_MAX_NAME-1); + cklen = strcspn(ioc->ioc_title, invalid_chars); + if (cklen < nmlen) { + err = EINVAL; + goto out; + } - /* Do the OtW open, save the FID. */ - err = smb_smb_open_prjob(ssp, ioc->ioc_title, - ioc->ioc_setuplen, ioc->ioc_prmode, - &scred, &fid); + /* Build name_mb */ + err = smb_put_dmem(&name_mb, SSTOVC(ssp), + ioc->ioc_title, nmlen, + SMB_CS_NONE, NULL); if (err != 0) goto out; - sdp->sd_smbfid = fid; - sdp->sd_vcgenid = ssp->ss_vcgenid; + err = smb_fh_create(ssp, &fhp); + if (err != 0) + goto out; + + /* + * Do the OtW open, save the FID. + */ + smb_credinit(&scred, cr); + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + err = smb2_smb_ntcreate(ssp, &name_mb, + NULL, NULL, /* cctx in, out */ + 0, /* create flags */ + access, + SMB_EFA_NORMAL, + NTCREATEX_SHARE_ACCESS_NONE, + NTCREATEX_DISP_CREATE, + NTCREATEX_OPTIONS_NON_DIRECTORY_FILE, + NTCREATEX_IMPERSONATION_IMPERSONATION, + &scred, + &fhp->fh_fid2, + NULL, + NULL); + } else { + err = smb_smb_open_prjob(ssp, ioc->ioc_title, + ioc->ioc_setuplen, ioc->ioc_prmode, + &scred, &fhp->fh_fid1); + } + smb_credrele(&scred); + if (err != 0) + goto out; + + fhp->fh_rights = access; + smb_fh_opened(fhp); + sdp->sd_fh = fhp; + fhp = NULL; out: + if (fhp != NULL) + smb_fh_rele(fhp); kmem_free(ioc, sizeof (*ioc)); - smb_credrele(&scred); + mb_done(&name_mb); return (err); } @@ -410,31 +454,21 @@ out: * Helper for nsmb_ioctl case * SMBIOC_CLOSEFH */ +/*ARGSUSED*/ int smb_usr_closefh(smb_dev_t *sdp, cred_t *cr) { - struct smb_cred scred; - struct smb_share *ssp; - uint16_t fid; - int err; - - /* This ioctl requires a share. */ - if ((ssp = sdp->sd_share) == NULL) - return (ENOTCONN); + struct smb_fh *fhp; - if (sdp->sd_smbfid == -1) - return (0); - fid = (uint16_t)sdp->sd_smbfid; - sdp->sd_smbfid = -1; + /* This ioctl requires a file handle. */ + if ((fhp = sdp->sd_fh) == NULL) + return (EINVAL); + sdp->sd_fh = NULL; - smb_credinit(&scred, cr); - if (ssp->ss_type == STYPE_PRINTQ) - err = smb_smb_close_prjob(ssp, fid, &scred); - else - err = smb_smb_close(ssp, fid, NULL, &scred); - smb_credrele(&scred); + smb_fh_close(fhp); + smb_fh_rele(fhp); - return (err); + return (0); } /* @@ -732,7 +766,7 @@ smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) switch (cmd) { case SMBIOC_IOD_CONNECT: - err = nsmb_iod_connect(vcp); + err = nsmb_iod_connect(vcp, cr); break; case SMBIOC_IOD_NEGOTIATE: diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c index 47b2783c58..b7f6bd8570 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c @@ -33,9 +33,10 @@ */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -63,9 +64,9 @@ * 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 @@ -75,7 +76,7 @@ * &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. @@ -113,6 +114,9 @@ */ #define MLEN 4096 +#if (MLEN < SMB2_HDRLEN) +#error "MLEN can't fit a contiguous SMB2 header" +#endif /* * Some UIO routines. @@ -420,6 +424,22 @@ mb_put_padbyte(struct mbchain *mbp) return (0); } +/* + * Adds padding to 8 byte boundary + */ +int +mb_put_align8(struct mbchain *mbp) +{ + static const char zeros[8] = { 0 }; + int pad_len = 0; + + if ((mbp->mb_count % 8) != 0) { + pad_len = 8 - (mbp->mb_count % 8); + MB_PUT_INLINE(mbp, zeros, pad_len); + } + return (0); +} + int mb_put_uint8(struct mbchain *mbp, u_int8_t x) { @@ -537,6 +557,7 @@ mb_put_mem(struct mbchain *mbp, const void *vsrc, int size, int type) /* * Append an mblk to the chain. + * Note: The mblk_t *m is consumed. */ int mb_put_mbuf(struct mbchain *mbp, mblk_t *m) @@ -575,6 +596,29 @@ mb_put_mbuf(struct mbchain *mbp, mblk_t *m) return (0); } +/* + * Put an mbchain into another mbchain + * Leave sub_mbp untouched. + */ +int +mb_put_mbchain(struct mbchain *mbp, struct mbchain *sub_mbp) +{ + mblk_t *m; + + if (sub_mbp == NULL) + return (0); + + m = sub_mbp->mb_top; + if (m == NULL) + return (0); + + m = dupmsg(m); + if (m == NULL) + return (ENOSR); + + return (mb_put_mbuf(mbp, m)); +} + /* * copies a uio scatter/gather list to an mbuf chain. */ @@ -875,6 +919,7 @@ md_get_mem(struct mdchain *mdp, void *vdst, int size, int type) /* * Get the next SIZE bytes as a separate mblk. + * Advances position in mdp by SIZE. */ int md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret) @@ -898,6 +943,7 @@ md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret) rm = m_copym(m, off, size, M_WAITOK); if (rm == NULL) return (EBADRPC); + (void) md_get_mem(mdp, NULL, size, MB_MSYSTEM); *ret = rm; return (0); diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c index c5af3391c6..1e16e95d18 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c @@ -22,6 +22,8 @@ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -69,12 +71,12 @@ static int smbfs_getsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr) { struct smb_cred scred; - int error, cerror; smbmntinfo_t *smi; smbnode_t *np; - u_int16_t fid = SMB_FID_UNUSED; + smb_fh_t *fid = NULL; uint32_t sdlen = SMALL_SD_SIZE; uint32_t rights = STD_RIGHT_READ_CONTROL_ACCESS; + int error; if (selector & SACL_SECURITY_INFORMATION) rights |= SEC_RIGHT_SYSTEM_SECURITY; @@ -82,9 +84,6 @@ smbfs_getsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr) np = VTOSMB(vp); smi = VTOSMI(vp); - /* Shared lock for (possible) n_fid use. */ - if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) - return (EINTR); smb_credinit(&scred, cr); error = smbfs_smb_tmpopen(np, rights, &scred, &fid); @@ -95,8 +94,8 @@ again: /* * This does the OTW Get */ - error = smbfs_smb_getsec_m(smi->smi_share, fid, - &scred, selector, mp, &sdlen); + error = smbfs_smb_getsec(smi->smi_share, fid, + selector, mp, &sdlen, &scred); /* * Server may give us an error indicating that we * need a larger data buffer to receive the SD, @@ -115,14 +114,10 @@ again: sdlen <= MAX_RAW_SD_SIZE) goto again; - cerror = smbfs_smb_tmpclose(np, fid, &scred); - if (cerror) - SMBVDEBUG("error %d closing file %s\n", - cerror, np->n_rpath); + smbfs_smb_tmpclose(np, fid); out: smb_credrele(&scred); - smbfs_rw_exit(&np->r_lkserlock); return (error); } @@ -139,11 +134,11 @@ static int smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr) { struct smb_cred scred; - int error, cerror; smbmntinfo_t *smi; smbnode_t *np; uint32_t rights; - u_int16_t fid = SMB_FID_UNUSED; + smb_fh_t *fid = NULL; + int error; np = VTOSMB(vp); smi = VTOSMI(vp); @@ -164,9 +159,6 @@ smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr) if (selector & SACL_SECURITY_INFORMATION) rights |= SEC_RIGHT_SYSTEM_SECURITY; - /* Shared lock for (possible) n_fid use. */ - if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) - return (EINTR); smb_credinit(&scred, cr); error = smbfs_smb_tmpopen(np, rights, &scred, &fid); @@ -185,17 +177,13 @@ smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr) /* * This does the OTW Set */ - error = smbfs_smb_setsec_m(smi->smi_share, fid, - &scred, selector, mp); + error = smbfs_smb_setsec(smi->smi_share, fid, + selector, mp, &scred); - cerror = smbfs_smb_tmpclose(np, fid, &scred); - if (cerror) - SMBVDEBUG("error %d closing file %s\n", - cerror, np->n_rpath); + smbfs_smb_tmpclose(np, fid); out: smb_credrele(&scred); - smbfs_rw_exit(&np->r_lkserlock); return (error); } diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c index b9226e56d0..41a6f41a2b 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c @@ -25,7 +25,7 @@ * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. * All rights reserved. * - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -398,11 +398,23 @@ smbfs_getattr_cache(vnode_t *vp, struct smbfattr *fap) static int smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr) { - struct smbnode *np; struct smb_cred scred; + smbnode_t *np = VTOSMB(vp); + smb_share_t *ssp = np->n_mount->smi_share; + smb_fh_t *fhp = NULL; int error; - np = VTOSMB(vp); + bzero(fap, sizeof (*fap)); + + /* + * Special case the XATTR directory here (all fake). + * OK to leave a,c,m times zero (expected). + */ + if (vp->v_flag & V_XATTRDIR) { + fap->fa_attr = SMB_FA_DIR; + fap->fa_size = DEV_BSIZE; + return (0); + } /* * Here NFS uses the ACL RPC (if smi_flags & SMI_ACL) @@ -416,8 +428,28 @@ smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr) return (EINTR); smb_credinit(&scred, cr); - bzero(fap, sizeof (*fap)); - error = smbfs_smb_getfattr(np, fap, &scred); +// Does the attr. open code path work for streams? +// Trying that, and if it doesn't work enable this. +#if 0 // XXX + /* + * Extended attribute files + */ + if (np->n_flag & N_XATTR) { + error = smbfs_xa_getfattr(np, fap, scrp); + goto out; + } +#endif // XXX + + if (np->n_fidrefs > 0 && + (fhp = np->n_fid) != NULL && + (fhp->fh_vcgenid == ssp->ss_vcgenid)) { + /* Use the FID we have. */ + error = smbfs_smb_getfattr(np, fhp, fap, &scred); + + } else { + /* This will do an attr open */ + error = smbfs_smb_getpattr(np, fap, &scred); + } smb_credrele(&scred); smbfs_rw_exit(&np->r_lkserlock); @@ -820,9 +852,8 @@ static void smbfs_cb_nop(smb_share_t *ss) smb_fscb_t smbfs_cb = { .fscb_disconn = smbfs_dead, - .fscb_connect = smbfs_cb_nop, - .fscb_down = smbfs_cb_nop, - .fscb_up = smbfs_cb_nop }; + .fscb_connect = smbfs_cb_nop +}; #endif /* NEED_SMBFS_CALLBACKS */ diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h index 2fe7476814..62d47e9b20 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h @@ -33,9 +33,10 @@ */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _FS_SMBFS_NODE_H_ @@ -221,10 +222,8 @@ typedef struct smbnode { struct smbfs_fctx *n_dirseq; /* ff context */ int n_dirofs; /* last ff offset */ int n_fidrefs; - uint16_t n_fid; /* file handle */ + smb_fh_t *n_fid; /* file handle */ enum vtype n_ovtype; /* vnode type opened */ - uint32_t n_rights; /* granted rights */ - int n_vcgenid; /* gereration no. (reconnect) */ /* * Misc. bookkeeping diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c index b8a91ef94a..9a44867521 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c @@ -28,15 +28,13 @@ * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -50,6 +48,7 @@ #include #include +#include #include #include #include @@ -64,375 +63,70 @@ */ const uint64_t NT1980 = 11960035200ULL*10000000ULL; -/* - * Local functions. - * Not static, to aid debugging. - */ - -int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen, - struct smbfattr *fap, struct smb_cred *scrp); -int smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap, - struct smb_cred *scrp, uint16_t infolevel); - -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_setfattrNT(struct smbnode *np, int fid, - uint32_t attr, struct timespec *mtime, struct timespec *atime, - 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_setpattr1(struct smbnode *np, - const char *name, int len, uint32_t attr, - struct timespec *mtime, 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)); - - /* After reconnect, n_fid is invalid */ - if (np->n_vcgenid != ssp->ss_vcgenid) - return (ESTALE); - - if (op == SMB_LOCK_SHARED) - ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; - /* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */ - 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_uint16le(mbp, np->n_fid); - mb_put_uint8(mbp, ltype); /* locktype */ - mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ - mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */ - 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); - - /* - * XXX: compute largelock via: - * (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? - */ - 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 + * Helper for smbfs_getattr_otw + * used when we have an open FID */ int smbfs_smb_getfattr( struct smbnode *np, + smb_fh_t *fhp, struct smbfattr *fap, struct smb_cred *scrp) { + struct smb_share *ssp = np->n_mount->smi_share; int error; - /* - * This lock is necessary for FID-based calls. - * Lock may be writer (via open) or reader. - */ - ASSERT(np->r_lkserlock.count != 0); - - /* - * Extended attribute directory or file. - */ - if (np->n_flag & N_XATTR) { - error = smbfs_xa_getfattr(np, fap, scrp); - return (error); + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + error = smbfs_smb2_qfileinfo(ssp, &fhp->fh_fid2, fap, scrp); + } else { + error = smbfs_smb1_trans2_query(np, fhp->fh_fid1, fap, scrp); } - error = smbfs_smb_trans2_query(np, fap, scrp, 0); - if (error != EINVAL) - return (error); - - /* fallback */ - error = smbfs_smb_query_info(np, NULL, 0, fap, scrp); - return (error); } /* - * Common function for QueryFileInfo, QueryPathInfo. + * Helper for smbfs_getattr_otw + * used when we don't have an open FID + * + * For SMB1 we can just use the path form of trans2 query. + * For SMB2 we need to do an attribute-only open. + * See smbfs_smb2_getpattr() */ int -smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap, - struct smb_cred *scrp, uint16_t infolevel) +smbfs_smb_getpattr( + struct smbnode *np, + struct smbfattr *fap, + struct smb_cred *scrp) { 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 cmd, 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 we have a valid open FID, use it. - */ - if ((np->n_fidrefs > 0) && - (np->n_fid != SMB_FID_UNUSED) && - (np->n_vcgenid == ssp->ss_vcgenid)) - cmd = SMB_TRANS2_QUERY_FILE_INFORMATION; - else - cmd = SMB_TRANS2_QUERY_PATH_INFORMATION; - -top: - error = smb_t2_alloc(SSTOCP(ssp), cmd, 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; - } - - if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION) - mb_put_uint16le(mbp, np->n_fid); - - mb_put_uint16le(mbp, infolevel); - - if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) { - mb_put_uint32le(mbp, 0); - /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */ - error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\'); - if (error) { - smb_t2_done(t2p); - return (error); - } - } + int 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); + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + error = smbfs_smb2_getpattr(np, fap, scrp); + } else { + uint16_t fid = SMB_FID_UNUSED; + error = smbfs_smb1_trans2_query(np, fid, fap, scrp); } - mdp = &t2p->t2_rdata; - svtz = vcp->vc_sopt.sv_tz; - switch (infolevel) { - case SMB_QFILEINFO_STANDARD: - md_get_uint16le(mdp, &date); - md_get_uint16le(mdp, &time); /* creation time */ - smb_dos2unixtime(date, time, 0, svtz, &fap->fa_createtime); - md_get_uint16le(mdp, &date); - md_get_uint16le(mdp, &time); /* access time */ - smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime); - md_get_uint16le(mdp, &date); - md_get_uint16le(mdp, &time); /* modify time */ - smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime); - md_get_uint32le(mdp, &size); /* EOF position */ - fap->fa_size = size; - md_get_uint32le(mdp, &size); /* allocation size */ - fap->fa_allocsz = size; - error = md_get_uint16le(mdp, &wattr); - fap->fa_attr = wattr; - timesok = 1; - break; - case SMB_QFILEINFO_ALL_INFO: - timesok = 0; - /* creation time */ - md_get_uint64le(mdp, &llongint); - if (llongint) - timesok++; - smb_time_NT2local(llongint, &fap->fa_createtime); - - /* last access time */ - md_get_uint64le(mdp, &llongint); - if (llongint) - timesok++; - smb_time_NT2local(llongint, &fap->fa_atime); - - /* last write time */ - md_get_uint64le(mdp, &llongint); - if (llongint) - timesok++; - smb_time_NT2local(llongint, &fap->fa_mtime); - - /* last change time */ - md_get_uint64le(mdp, &llongint); - if (llongint) - timesok++; - smb_time_NT2local(llongint, &fap->fa_ctime); - - /* attributes */ - md_get_uint32le(mdp, &dattr); - fap->fa_attr = dattr; - /* - * 4-Byte alignment - discard - * Specs don't talk about this. - */ - md_get_uint32le(mdp, NULL); - /* allocation size */ - md_get_uint64le(mdp, &lsize); - fap->fa_allocsz = lsize; - /* File size */ - error = 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 - * Moved to smbfs_xattr.c + * Get and parse FileFsAttributeInformation */ - int smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa, struct smb_cred *scrp) { - struct smb_t2rq *t2p; - struct mbchain *mbp; - struct mdchain *mdp; int error; - uint32_t nlen; - - 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) - goto out; - - mdp = &t2p->t2_rdata; - md_get_uint32le(mdp, &fsa->fsa_aflags); - md_get_uint32le(mdp, &fsa->fsa_maxname); - error = md_get_uint32le(mdp, &nlen); /* fs name length */ - if (error) - goto out; - /* - * Get the FS type name. - */ - bzero(fsa->fsa_tname, FSTYPSZ); - if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) { - uint16_t tmpbuf[FSTYPSZ]; - size_t tmplen, outlen; - - if (nlen > sizeof (tmpbuf)) - nlen = sizeof (tmpbuf); - error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM); - tmplen = nlen / 2; /* UCS-2 chars */ - outlen = FSTYPSZ - 1; - (void) uconv_u16tou8(tmpbuf, &tmplen, - (uchar_t *)fsa->fsa_tname, &outlen, - UCONV_IN_LITTLE_ENDIAN); + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + error = smbfs_smb2_qfsattr(ssp, fsa, scrp); } else { - if (nlen > (FSTYPSZ - 1)) - nlen = FSTYPSZ - 1; - error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM); + error = smbfs_smb1_qfsattr(ssp, fsa, scrp); } /* @@ -444,1842 +138,446 @@ smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa, SMB_SS_UNLOCK(ssp); } -out: - smb_t2_done(t2p); - return (0); + return (error); } int smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp, struct smb_cred *scp) { + struct smb_fs_size_info info; + struct smb_vc *vcp = SSTOVC(ssp); + uint32_t bps, spu; 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); + if (vcp->vc_flags & SMBV_SMB2) { + error = smbfs_smb2_statfs(ssp, &info, scp); + } else { + error = smbfs_smb1_statfs(ssp, &info, scp); + } + if (error) + return (error); + + /* A bit of paranoia. */ + bps = info.bytes_per_sect; + if (bps < DEV_BSIZE) + bps = DEV_BSIZE; + spu = info.sect_per_unit; + if (spu == 0) + spu = 1; + + /* preferred file system block size */ + sbp->f_bsize = bps * spu; + + /* file system block size ("fragment size") */ + sbp->f_frsize = bps; + + /* total blocks of f_frsize */ + sbp->f_blocks = info.total_units * spu; + + /* free blocks of f_frsize */ + sbp->f_bfree = info.actual_avail * spu; + + /* free blocks avail to non-superuser */ + sbp->f_bavail = info.caller_avail * spu; + + sbp->f_files = (-1); /* total file nodes in file system */ + sbp->f_ffree = (-1); /* free file nodes in fs */ return (error); } int -smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp, - struct smb_cred *scrp) +smbfs_smb_setdisp(struct smb_share *ssp, smb_fh_t *fhp, + uint8_t disp, 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) - goto out; + int err; - mdp = &t2p->t2_rdata; - md_get_uint32le(mdp, NULL); /* fs id */ - md_get_uint32le(mdp, &bpu); - md_get_uint32le(mdp, &units); - md_get_uint32le(mdp, &funits); - error = md_get_uint16le(mdp, &bsize); - if (error) - goto out; - 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; + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + err = smbfs_smb2_setdisp(ssp, &fhp->fh_fid2, disp, scrp); + } else { + err = smbfs_smb1_setdisp(ssp, fhp->fh_fid1, disp, scrp); } - 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 */ -out: - smb_t2_done(t2p); - return (0); + return (err); } int -smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp, - struct smb_cred *scrp) +smbfs_smb_setfsize(struct smb_share *ssp, smb_fh_t *fhp, + uint64_t size, 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) - goto out; - - smb_rq_getreply(rqp, &mdp); - md_get_uint16le(mdp, &units); - md_get_uint16le(mdp, &bpu); - md_get_uint16le(mdp, &bsize); - error = md_get_uint16le(mdp, &funits); - if (error) - goto out; - 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; + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + error = smbfs_smb2_seteof(ssp, &fhp->fh_fid2, size, scrp); + } else { + error = smbfs_smb1_seteof(ssp, fhp->fh_fid1, size, scrp); } - 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 */ -out: - smb_rq_done(rqp); - return (0); + return (error); } + +/* + * Set file attributes (optionally: DOS attr, atime, mtime) + * Always have an open FID with set attr rights. + */ int -smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize, - struct smb_cred *scrp) +smbfs_smb_setfattr( + struct smb_share *ssp, + smb_fh_t *fhp, + uint32_t attr, + struct timespec *mtime, + struct timespec *atime, + struct smb_cred *scrp) { - struct smb_t2rq *t2p; - struct smb_vc *vcp = SSTOVC(ssp); - struct mbchain *mbp; + struct mbchain mb_info; + struct mbchain *mbp = &mb_info; + uint64_t tm; 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_uint16le(mbp, fid); - 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_uint16le(mbp, 0); /* pad */ - mbp = &t2p->t2_tdata; + /* + * Build a struct FILE_BASIC_INFORMATION in mbp + * LARGE_INTEGER CreationTime; + * LARGE_INTEGER LastAccessTime; + * LARGE_INTEGER LastWriteTime; + * LARGE_INTEGER ChangeTime; + * ULONG FileAttributes; + * Zero in times means "no change". + */ mb_init(mbp); - mb_put_uint64le(mbp, newsize); - t2p->t2_maxpcount = 2; - t2p->t2_maxdcount = 0; - error = smb_t2_request(t2p); - smb_t2_done(t2p); + mb_put_uint64le(mbp, 0); /* creation time */ + if (atime) { + smb_time_local2NT(atime, &tm); + if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) && + tm < NT1980) + tm = NT1980; + } else + tm = 0; + mb_put_uint64le(mbp, tm); /* last access time */ + if (mtime) { + smb_time_local2NT(mtime, &tm); + if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) && + tm < NT1980) + tm = NT1980; + } else + tm = 0; + mb_put_uint64le(mbp, tm); /* last write time */ + mb_put_uint64le(mbp, 0); /* change time */ + mb_put_uint32le(mbp, attr); + + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + error = smbfs_smb2_setfattr(ssp, &fhp->fh_fid2, mbp, scrp); + } else { + error = smbfs_smb1_setfattr(ssp, fhp->fh_fid1, mbp, scrp); + } + return (error); } int -smbfs_smb_setdisp(struct smbnode *np, uint16_t fid, uint8_t newdisp, +smbfs_smb_flush(struct smb_share *ssp, smb_fh_t *fhp, 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; 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_uint16le(mbp, fid); - if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) - mb_put_uint16le(mbp, SMB_SFILEINFO_DISPOSITION_INFORMATION); - else - mb_put_uint16le(mbp, SMB_SFILEINFO_DISPOSITION_INFO); - mb_put_uint16le(mbp, 0); /* pad */ - mbp = &t2p->t2_tdata; - mb_init(mbp); - mb_put_uint8(mbp, newdisp); - t2p->t2_maxpcount = 2; - t2p->t2_maxdcount = 0; - error = smb_t2_request(t2p); - smb_t2_done(t2p); + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + error = smbfs_smb2_flush(ssp, &fhp->fh_fid2, scrp); + } else { + error = smbfs_smb1_flush(ssp, fhp->fh_fid1, scrp); + } return (error); } /* - * On SMB1, the trans2 rename only allows a rename where the - * source and target are in the same directory. If you give - * the server any separators, you get "status not supported". + * Modern create/open of file or directory. + * On success, fills in fhp->fh_fid* and fhp->fh_rights */ - -/*ARGSUSED*/ int -smbfs_smb_t2rename(struct smbnode *np, - const char *tname, int tnlen, struct smb_cred *scrp, - uint16_t fid, int overwrite) +smbfs_smb_ntcreatex( + struct smbnode *np, + const char *name, + int nmlen, + int xattr, /* is named stream? */ + uint32_t req_acc, /* requested access */ + uint32_t efa, /* ext. file attrs (DOS attr +) */ + uint32_t share_acc, + uint32_t disp, /* open disposition */ + uint32_t createopt, /* NTCREATEX_OPTIONS_ */ + struct smb_cred *scrp, + smb_fh_t *fhp, /* pre-made file handle to fill in */ + uint32_t *cr_act_p, /* optional returned create action */ + struct smbfattr *fap) /* optional returned attributes */ { - struct smb_t2rq *t2p; + struct mbchain name_mb; struct smb_share *ssp = np->n_mount->smi_share; - struct smb_vc *vcp = SSTOVC(ssp); - struct mbchain *mbp; - int32_t *ucslenp; - int error; - - 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); - - mbp = &t2p->t2_tparam; - mb_init(mbp); - mb_put_uint16le(mbp, fid); - mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION); - mb_put_uint16le(mbp, 0); /* reserved, nowadays */ + int err; - mbp = &t2p->t2_tdata; - mb_init(mbp); - mb_put_uint32le(mbp, overwrite); /* one or zero */ - mb_put_uint32le(mbp, 0); /* obsolete target dir fid */ + mb_init(&name_mb); - ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t)); - mbp->mb_count = 0; - error = smb_put_dmem(mbp, vcp, tname, tnlen, SMB_CS_NONE, NULL); - if (error) + if (name == NULL) + nmlen = 0; + err = smbfs_fullpath(&name_mb, SSTOVC(ssp), + np, name, nmlen, xattr ? ':' : '\\'); + if (err) goto out; - *ucslenp = htolel(mbp->mb_count); - - t2p->t2_maxpcount = 2; - t2p->t2_maxdcount = 0; - error = smb_t2_request(t2p); -out: - 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->n_fidrefs == 0) - return (0); /* not open */ + err = smb_smb_ntcreate(ssp, &name_mb, + 0, /* NTCREATEX_FLAGS... */ + req_acc, efa, share_acc, disp, createopt, + NTCREATEX_IMPERSONATION_IMPERSONATION, + scrp, fhp, cr_act_p, fap); - /* After reconnect, n_fid is invalid */ - if (np->n_vcgenid != ssp->ss_vcgenid) - return (ESTALE); +out: + mb_done(&name_mb); - 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_uint16le(mbp, np->n_fid); - 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); + return (err); } +/* + * Get a file handle with (at least) the specified rights. + * + * We'll try to borrow the node ->n_fid if we can. When we + * borrow n_fid, just take a hold on the smb_fh_t, and don't + * bump n_fidrefs as that tracks VFS-level opens. Similarly + * in _tmpclose we just release the smb_fh_t, not n_fidrefs. + */ int -smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize, - struct smb_cred *scrp) +smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, + smb_fh_t **fhpp) { struct smb_share *ssp = np->n_mount->smi_share; - struct smb_rq rq, *rqp = &rq; - struct mbchain *mbp; + smb_fh_t *fhp = NULL; int error; - if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { - /* - * 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); - } - } - - /* - * 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_uint16le(mbp, fid); - 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); -} - -/* - * Old method for getting file attributes. - */ -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); - - error = smbfs_fullpath(mbp, SSTOVC(ssp), np, - name, nmlen, '\\'); - if (error) - goto out; - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); - if (error) - goto out; - smb_rq_getreply(rqp, &mdp); - error = md_get_uint8(mdp, &wc); - if (error) - goto out; - if (wc != 10) { - error = EBADRPC; - goto out; - } - 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 */ - smb_time_server2local(longint, - SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime); - error = md_get_uint32le(mdp, &longint); - fap->fa_size = longint; - -out: - smb_rq_done(rqp); - 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); - - error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len, '\\'); - if (error) - goto out; - 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); - -out: - 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); -} - -/* - * Set file attributes (optionally: DOS attr, atime, mtime) - * either by open FID or by path name (FID == -1). - */ -int -smbfs_smb_setfattr( - struct smbnode *np, - int 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; - - /* - * Normally can use the trans2 call. - */ - if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { - error = smbfs_smb_setfattrNT(np, fid, - attr, mtime, atime, scrp); - return (error); - } - - /* - * Fall-back for older protocols. - */ - if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { - error = smbfs_smb_setftime1(np, fid, - mtime, atime, scrp); - return (error); - } - 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_uint16le(mbp, fid); - 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, either via open FID or by path name. - * Looks like this call can be used only if CAP_NT_SMBS bit is on. - * - * When setting via path (fid == -1): - * *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_setfattrNT( - struct smbnode *np, - int fid, /* if fid == -1, set by path */ - 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; - uint16_t cmd, level; - - if (fid == -1) { - cmd = SMB_TRANS2_SET_PATH_INFORMATION; - } else { - if (fid > UINT16_MAX) - return (EINVAL); - cmd = SMB_TRANS2_SET_FILE_INFORMATION; - } - if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) - level = SMB_SFILEINFO_BASIC_INFORMATION; - else - level = SMB_SFILEINFO_BASIC_INFO; - - error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p); - if (error) - return (error); - - mbp = &t2p->t2_tparam; - mb_init(mbp); - - if (cmd == SMB_TRANS2_SET_FILE_INFORMATION) - mb_put_uint16le(mbp, fid); - - mb_put_uint16le(mbp, level); - mb_put_uint32le(mbp, 0); /* MBZ */ - - if (cmd == SMB_TRANS2_SET_PATH_INFORMATION) { - error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\'); - if (error != 0) - goto out; - } - - /* FAT file systems don't support dates earlier than 1980. */ - - mbp = &t2p->t2_tdata; - mb_init(mbp); - mb_put_uint64le(mbp, 0); /* creation time */ - if (atime) { - smb_time_local2NT(atime, &tm); - if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) && - tm < NT1980) - tm = NT1980; - } else - tm = 0; - mb_put_uint64le(mbp, tm); /* access time */ - if (mtime) { - smb_time_local2NT(mtime, &tm); - if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) && - tm < NT1980) - tm = NT1980; - } else - tm = 0; - mb_put_uint64le(mbp, tm); /* last write time */ - mb_put_uint64le(mbp, 0); /* ctime (no change) */ - mb_put_uint32le(mbp, attr); - mb_put_uint32le(mbp, 0); /* padding */ - t2p->t2_maxpcount = 2; - t2p->t2_maxdcount = 0; - error = smb_t2_request(t2p); -out: - smb_t2_done(t2p); - return (error); -} - -/* - * Modern create/open of file or directory. - */ -int -smbfs_smb_ntcreatex( - struct smbnode *np, - const char *name, - int nmlen, - int xattr, /* is named stream? */ - uint32_t req_acc, /* requested access */ - uint32_t efa, /* ext. file attrs (DOS attr +) */ - uint32_t share_acc, - uint32_t disp, /* open disposition */ - uint32_t createopt, /* NTCREATEX_OPTIONS_ */ - struct smb_cred *scrp, - uint16_t *fidp, /* returned FID */ - uint32_t *cr_act_p, /* optional returned create action */ - struct smbfattr *fap) /* optional returned attributes */ -{ - struct mbchain name_mb; - struct smb_share *ssp = np->n_mount->smi_share; - int err; - - mb_init(&name_mb); - - if (name == NULL) - nmlen = 0; - err = smbfs_fullpath(&name_mb, SSTOVC(ssp), - np, name, nmlen, xattr ? ':' : '\\'); - if (err) - goto out; - - err = smb_smb_ntcreate(ssp, &name_mb, - 0, /* NTCREATEX_FLAGS... */ - req_acc, efa, share_acc, disp, createopt, - NTCREATEX_IMPERSONATION_IMPERSONATION, - scrp, fidp, cr_act_p, fap); - -out: - mb_done(&name_mb); - - return (err); -} - -static uint32_t -smb_mode2rights(int mode) -{ - mode = mode & SMB_AM_OPENMODE; - uint32_t rights = - STD_RIGHT_SYNCHRONIZE_ACCESS | - STD_RIGHT_READ_CONTROL_ACCESS; - - if ((mode == SMB_AM_OPENREAD) || - (mode == SMB_AM_OPENRW)) { - rights |= - SA_RIGHT_FILE_READ_ATTRIBUTES | - SA_RIGHT_FILE_READ_DATA; - } - - if ((mode == SMB_AM_OPENWRITE) || - (mode == SMB_AM_OPENRW)) { - rights |= - SA_RIGHT_FILE_WRITE_ATTRIBUTES | - SA_RIGHT_FILE_APPEND_DATA | - SA_RIGHT_FILE_WRITE_DATA; - } - - if (mode == SMB_AM_OPENEXEC) { - rights |= - SA_RIGHT_FILE_READ_ATTRIBUTES | - SA_RIGHT_FILE_EXECUTE; - } - - return (rights); -} - -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)) - 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)) - accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD - : SMB_AM_OPENRW; - return (accmode); -} - -static int -smbfs_smb_oldopen( - struct smbnode *np, - const char *name, - int nmlen, - int xattr, - int accmode, - struct smb_cred *scrp, - uint16_t *fidp, - uint16_t *granted_mode_p, - smbfattr_t *fap) -{ - 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 fa; - uint8_t wc; - uint16_t wattr; - uint32_t longint; - int error; - - bzero(&fa, sizeof (fa)); - - /* - * XXX: move to callers... - * - * 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; - - 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); - - error = smbfs_fullpath(mbp, vcp, np, name, nmlen, - xattr ? ':' : '\\'); - if (error) - goto done; - 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) - goto done; - 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) - */ - error = md_get_uint8(mdp, &wc); - if (error) - goto done; - if (wc != 7 && wc != 15) { - error = EBADRPC; - goto done; - } - md_get_uint16le(mdp, fidp); - md_get_uint16le(mdp, &wattr); - fa.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 */ - smb_time_server2local(longint, vcp->vc_sopt.sv_tz, &fa.fa_mtime); - md_get_uint32le(mdp, &longint); - fa.fa_size = longint; - error = md_get_uint16le(mdp, granted_mode_p); - -done: - smb_rq_done(rqp); - if (error) - return (error); - - if (fap) - *fap = fa; /* struct copy */ - - return (0); -} - -int -smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, - uint16_t *fidp) -{ - struct smb_share *ssp = np->n_mount->smi_share; - struct smb_vc *vcp = SSTOVC(ssp); - int accmode, error; - - /* Shared lock for n_fid use below. */ - ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); - /* Can we re-use n_fid? or must we open anew? */ - mutex_enter(&np->r_statelock); - if (np->n_fidrefs > 0 && - np->n_vcgenid == ssp->ss_vcgenid && - (rights & np->n_rights) == rights) { - np->n_fidrefs++; - *fidp = np->n_fid; - mutex_exit(&np->r_statelock); - return (0); - } - mutex_exit(&np->r_statelock); - - /* re-open an existing file. */ - if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { - error = smbfs_smb_ntcreatex(np, - NULL, 0, 0, /* name nmlen xattr */ - rights, SMB_EFA_NORMAL, - NTCREATEX_SHARE_ACCESS_ALL, - NTCREATEX_DISP_OPEN, - 0, /* create options */ - scrp, fidp, - NULL, NULL); /* cr_act_p fa_p */ - return (error); - } - - accmode = smb_rights2mode(rights); - error = smbfs_smb_oldopen(np, - NULL, 0, 0, /* name nmlen xattr */ - accmode, scrp, - fidp, - NULL, /* granted mode p */ - NULL); /* fa p */ - - 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, - const char *name, - int nmlen, - int xattr, - uint32_t rights, - struct smb_cred *scrp, - uint16_t *fidp, - uint32_t *rightsp, - smbfattr_t *fap) -{ - struct smb_share *ssp = np->n_mount->smi_share; - struct smb_vc *vcp = SSTOVC(ssp); - int accmode, error; - uint16_t grantedmode; - - /* open an existing file */ - if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { - error = smbfs_smb_ntcreatex(np, - name, nmlen, xattr, - rights, SMB_EFA_NORMAL, - NTCREATEX_SHARE_ACCESS_ALL, - NTCREATEX_DISP_OPEN, - 0, /* create options */ - scrp, fidp, - NULL, fap); /* cr_act_p fa_p */ - if (error != 0) - return (error); - *rightsp = rights; - return (0); - } - - accmode = smb_rights2mode(rights); - error = smbfs_smb_oldopen(np, - name, nmlen, xattr, accmode, scrp, - fidp, &grantedmode, fap); - if (error != 0) - return (error); - *rightsp = smb_mode2rights(grantedmode); - (void) smbfs_smb_getfattr(np, fap, scrp); - - return (0); -} - -int -smbfs_smb_close(struct smb_share *ssp, uint16_t fid, - struct timespec *mtime, struct smb_cred *scrp) -{ - int error; - - error = smb_smb_close(ssp, fid, mtime, scrp); - - /* - * 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, - int xattr, struct smb_cred *scrp, uint16_t *fidp) -{ - 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) - goto out; - 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) - goto out; - - smb_rq_getreply(rqp, &mdp); - md_get_uint8(mdp, &wc); - if (wc != 1) { - error = EBADRPC; - goto out; - } - error = md_get_uint16le(mdp, fidp); - -out: - smb_rq_done(rqp); - return (error); -} - -int -smbfs_smb_create( - struct smbnode *dnp, - const char *name, - int nmlen, - int xattr, - uint32_t disp, - struct smb_cred *scrp, - uint16_t *fidp) -{ - struct smb_share *ssp = dnp->n_mount->smi_share; - struct smb_vc *vcp = SSTOVC(ssp); - uint32_t efa, rights; - int error; - - /* - * 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) { - rights = SA_RIGHT_FILE_WRITE_DATA; - efa = SMB_EFA_NORMAL; - if (!xattr && name && *name == '.') - efa = SMB_EFA_HIDDEN; - error = smbfs_smb_ntcreatex(dnp, - name, nmlen, xattr, rights, efa, - NTCREATEX_SHARE_ACCESS_ALL, - disp, /* != NTCREATEX_DISP_OPEN */ - NTCREATEX_OPTIONS_NON_DIRECTORY_FILE, - scrp, fidp, NULL, NULL); /* cr_act_p fa_p */ - return (error); - } - - error = smbfs_smb_oldcreate(dnp, name, nmlen, xattr, scrp, fidp); - return (error); -} - -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; - char sep; - - 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); - - /* - * When we're not adding any component name, the - * passed sep is ignored, so just pass sep=0. - */ - mb_put_uint8(mbp, SMB_DT_ASCII); - error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0); - if (error) - goto out; - - /* - * After XATTR directories, separator is ":" - */ - sep = (src->n_flag & N_XATTR) ? ':' : '\\'; - mb_put_uint8(mbp, SMB_DT_ASCII); - error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, sep); - if (error) - goto out; - - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); -out: - 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); - - error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, '\\'); - if (error) - goto out; - mb_put_uint8(mbp, SMB_DT_ASCII); - error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, '\\'); - if (error) - goto out; - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); - -out: - 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 nmlen, - struct smb_cred *scrp) -{ - struct smb_share *ssp = dnp->n_mount->smi_share; - struct smb_vc *vcp = SSTOVC(ssp); - uint32_t rights; - 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 (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { - rights = SA_RIGHT_FILE_READ_DATA; - error = smbfs_smb_ntcreatex(dnp, - name, nmlen, 0, /* xattr */ - rights, SMB_EFA_DIRECTORY, - NTCREATEX_SHARE_ACCESS_ALL, - NTCREATEX_DISP_CREATE, - NTCREATEX_OPTIONS_DIRECTORY, - scrp, &fid, NULL, NULL); /* cr_act_p fa_p */ - if (error) - return (error); - (void) smbfs_smb_close(ssp, fid, NULL, scrp); + mutex_enter(&np->r_statelock); + if (np->n_fidrefs > 0 && + (fhp = np->n_fid) != NULL && + fhp->fh_vcgenid == ssp->ss_vcgenid && + (fhp->fh_rights & rights) == rights) { + smb_fh_hold(fhp); + *fhpp = fhp; + mutex_exit(&np->r_statelock); return (0); } + mutex_exit(&np->r_statelock); + + error = smb_fh_create(ssp, &fhp); + if (error != 0) + goto out; + + /* re-open an existing file. */ + error = smbfs_smb_ntcreatex(np, + NULL, 0, 0, /* name nmlen xattr */ + rights, SMB_EFA_NORMAL, + NTCREATEX_SHARE_ACCESS_ALL, + NTCREATEX_DISP_OPEN, + 0, /* create options */ + scrp, fhp, + NULL, NULL); /* cr_act_p fa_p */ + if (error != 0) + goto out; + + fhp->fh_rights = rights; + smb_fh_opened(fhp); + *fhpp = fhp; + fhp = NULL; + +out: + if (fhp != NULL) + smb_fh_rele(fhp); - error = smbfs_smb_oldmkdir(dnp, name, nmlen, scrp); return (error); } +/* ARGSUSED */ +void +smbfs_smb_tmpclose(struct smbnode *np, smb_fh_t *fhp) +{ + smb_fh_rele(fhp); +} + int -smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp) +smbfs_smb_open( + struct smbnode *np, + const char *name, + int nmlen, + int xattr, + uint32_t rights, + struct smb_cred *scrp, + smb_fh_t **fhpp, + smbfattr_t *fap) { - struct smb_rq rq, *rqp = &rq; struct smb_share *ssp = np->n_mount->smi_share; - struct mbchain *mbp; + // struct smb_vc *vcp = SSTOVC(ssp); + smb_fh_t *fhp = NULL; 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, 0, '\\'); - if (!error) { - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); - } - smb_rq_done(rqp); - return (error); -} + error = smb_fh_create(ssp, &fhp); + if (error != 0) + goto out; -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 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) { - error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, - ctx->f_wildcard, ctx->f_wclen, '\\'); - 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); - error = md_get_uint8(mdp, &wc); - if (error) - return (error); - if (wc != 1) - return (iseof ? ENOENT : EBADRPC); - md_get_uint16le(mdp, &ec); - md_get_uint16le(mdp, &bc); - md_get_uint8(mdp, &bt); - error = md_get_uint16le(mdp, &dlen); - if (error) - return (error); - if (ec == 0) - return (ENOENT); - ctx->f_ecnt = ec; - if (bc < 3) - return (EBADRPC); - bc -= 3; - if (bt != SMB_DT_VARIABLE) - return (EBADRPC); - if (dlen != bc || dlen % SMB_DENTRYLEN != 0) - return (EBADRPC); - return (0); -} + /* open an existing file */ + error = smbfs_smb_ntcreatex(np, + name, nmlen, xattr, + rights, SMB_EFA_NORMAL, + NTCREATEX_SHARE_ACCESS_ALL, + NTCREATEX_DISP_OPEN, + 0, /* create options */ + scrp, fhp, NULL, fap); + if (error != 0) + goto out; + fhp->fh_rights = rights; + smb_fh_opened(fhp); + *fhpp = fhp; + fhp = NULL; -/*ARGSUSED*/ -static int -smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp, - const char *wildcard, int wclen, uint16_t attr) -{ +out: + if (fhp != NULL) + smb_fh_rele(fhp); - ctx->f_type = ft_LM1; - 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) +void +smbfs_smb_close(smb_fh_t *fhp) { - 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); - } - 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; - error = 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); + smb_fh_close(fhp); + smb_fh_rele(fhp); } -/* - * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect - */ -static int -smbfs_smb_trans2find2(struct smbfs_fctx *ctx) +int +smbfs_smb_create( + struct smbnode *dnp, + const char *name, + int nmlen, + int xattr, + uint32_t disp, + struct smb_cred *scrp, + smb_fh_t **fhpp) { - struct smb_t2rq *t2p; - struct smb_vc *vcp = SSTOVC(ctx->f_ssp); - struct mbchain *mbp; - struct mdchain *mdp; - uint16_t ecnt, eos, lno, flags; + struct smb_share *ssp = dnp->n_mount->smi_share; + // struct smb_vc *vcp = SSTOVC(ssp); + smb_fh_t *fhp = NULL; + uint32_t efa, rights; int error; - if (ctx->f_t2) { - smb_t2_done(ctx->f_t2); - ctx->f_t2 = NULL; - } - 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); - error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, - ctx->f_wildcard, ctx->f_wclen, '\\'); - 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_uint16le(mbp, ctx->f_Sid); - mb_put_uint16le(mbp, ctx->f_limit); - mb_put_uint16le(mbp, ctx->f_infolevel); - /* Send whatever resume key we received... */ - mb_put_uint32le(mbp, ctx->f_rkey); - mb_put_uint16le(mbp, flags); - /* ... and the resume name if we have one. */ - 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); - } - t2p->t2_maxpcount = 5 * 2; - t2p->t2_maxdcount = 0xF000; /* 64K less some overhead */ - error = smb_t2_request(t2p); - if (error) - return (error); - - /* - * This is the "resume name" we just sent. - * We want the new one (if any) that may be - * found in the response we just received and - * will now begin parsing. Free the old one - * now so we'll know if we found a new one. - */ - if (ctx->f_rname) { - kmem_free(ctx->f_rname, ctx->f_rnamelen); - ctx->f_rname = NULL; - ctx->f_rnamelen = 0; - } - - mdp = &t2p->t2_rparam; - if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { - if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0) - goto nodata; - ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; - } - md_get_uint16le(mdp, &ecnt); /* entry count */ - md_get_uint16le(mdp, &eos); /* end of search */ - md_get_uint16le(mdp, NULL); /* EA err. off. */ - error = md_get_uint16le(mdp, &lno); /* last name off. */ + error = smb_fh_create(ssp, &fhp); if (error != 0) - goto nodata; + goto out; /* - * The "end of search" flag from an XP server sometimes - * 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 entry count. + * 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. */ - ctx->f_ecnt = ecnt; - if (eos || ctx->f_ecnt == 0) - ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; - if (ctx->f_ecnt == 0) - return (ENOENT); - - /* Last Name Off (LNO) is the entry with the resume name. */ - ctx->f_rnameofs = lno; - ctx->f_eofs = 0; - return (0); + rights = SA_RIGHT_FILE_WRITE_DATA; + efa = SMB_EFA_NORMAL; + if (!xattr && name && *name == '.') + efa = SMB_EFA_HIDDEN; + error = smbfs_smb_ntcreatex(dnp, + name, nmlen, xattr, rights, efa, + NTCREATEX_SHARE_ACCESS_ALL, + disp, /* != NTCREATEX_DISP_OPEN */ + NTCREATEX_OPTIONS_NON_DIRECTORY_FILE, + scrp, fhp, NULL, NULL); + if (error != 0) + goto out; -nodata: - /* - * Failed parsing the FindFirst or FindNext response. - * Force this directory listing closed, otherwise the - * calling process may hang in an infinite loop. - */ - ctx->f_ecnt = 0; /* Force closed. */ - ctx->f_flags |= SMBFS_RDD_EOF; - return (EIO); -} + fhp->fh_rights = rights; + smb_fh_opened(fhp); + *fhpp = fhp; + fhp = NULL; -static int -smbfs_smb_findclose2(struct smbfs_fctx *ctx) -{ - struct smb_rq rq, *rqp = &rq; - struct mbchain *mbp; - int error; +out: + if (fhp != NULL) + smb_fh_rele(fhp); - 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_uint16le(mbp, ctx->f_Sid); - 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) -{ - - ctx->f_type = ft_LM2; - ctx->f_namesz = SMB_MAXFNAMELEN + 1; - if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) - ctx->f_namesz *= 2; - ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP); - 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) +int +smbfs_smb_rename(struct smbnode *sdnp, struct smbnode *np, + struct smbnode *tdnp, const char *tname, int tnlen, + smb_fh_t *fhp, struct smb_cred *scrp) { - 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; - 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_trans2find2(ctx); - if (error) - return (error); - ctx->f_otws++; - } - 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 */ - smb_dos2unixtime(date, time, 0, svtz, - &ctx->f_attr.fa_createtime); - 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_uint32le(mdp, &size); /* allocation size */ - ctx->f_attr.fa_allocsz = size; - md_get_uint16le(mdp, &wattr); - ctx->f_attr.fa_attr = wattr; - error = md_get_uint8(mdp, &tb); - if (error) - goto nodata; - 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_uint64le(mdp, &llongint); /* creation time */ - smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime); - md_get_uint64le(mdp, &llongint); - smb_time_NT2local(llongint, &ctx->f_attr.fa_atime); - md_get_uint64le(mdp, &llongint); - smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime); - md_get_uint64le(mdp, &llongint); - smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime); - md_get_uint64le(mdp, &llongint); /* file size */ - ctx->f_attr.fa_size = llongint; - md_get_uint64le(mdp, &llongint); /* alloc. size */ - ctx->f_attr.fa_allocsz = llongint; - md_get_uint32le(mdp, &dattr); /* ext. file attributes */ - ctx->f_attr.fa_attr = dattr; - error = md_get_uint32le(mdp, &size); /* name len */ - if (error) - goto nodata; - 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) - */ - error = md_get_mem(mdp, NULL, 30, MB_MSYSTEM); - if (error) - goto nodata; - 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); - - /* Allocated f_name in findopen */ - ASSERT(nmlen < ctx->f_namesz); - cp = ctx->f_name; + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + int err; - error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM); - if (error) - goto nodata; - if (next) { - /* How much data to skip? */ - cnt = next - nmlen - fxsz; - if (cnt < 0) { - SMBVDEBUG("out of sync\n"); - goto nodata; - } - if (cnt > 0) - md_get_mem(mdp, NULL, cnt, MB_MSYSTEM); - } - /* 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 (vcp->vc_flags & SMBV_SMB2) { + err = smbfs_smb2_rename(np, tdnp, tname, tnlen, 0, + &fhp->fh_fid2, scrp); + return (err); } - if (nmlen == 0) - goto nodata; /* - * On a find-next we expect that the server will: - * 1) if the continue bit is set, use the server's offset, - * 2) else if the resume key is non-zero, use that offset, - * 3) else if the resume name is set, use that offset, - * 4) else use the server's idea of current offset. - * - * We always set the resume key flag. If the server returns - * a resume key then we should always send it back to them. + * SMB1 -- Want to use _t2rename if we can + * (rename in same dir and cap pass-through) + * Most SMB1 servers have cap pass-through. */ - ctx->f_rkey = resumekey; - - next = ctx->f_eofs + recsz; - if (ctx->f_rnameofs && - ctx->f_rnameofs >= ctx->f_eofs && - ctx->f_rnameofs < (int)next) { - /* - * This entry is the "resume name". - * Save it for the next request. - */ - 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); + if (sdnp == tdnp && + (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) != 0) { + err = smbfs_smb1_t2rename(np, tname, tnlen, fhp->fh_fid1, scrp); + } else { + err = smbfs_smb1_oldrename(np, tdnp, tname, tnlen, scrp); } - ctx->f_nmlen = nmlen; - ctx->f_eofs = next; - ctx->f_ecnt--; - ctx->f_left--; - smbfs_fname_tolocal(ctx); - return (0); + return (err); +} + +int +smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen, + struct smb_cred *scrp) +{ + smb_fh_t tmp_fh; + struct smb_share *ssp = dnp->n_mount->smi_share; + uint32_t efa, rights; + int error; -nodata: /* - * Something bad has happened and we ran out of data - * before we could parse all f_ecnt entries expected. - * Force this directory listing closed, otherwise the - * calling process may hang in an infinite loop. + * Using a faked-up handle here to avoid the work of + * creating and destroying a real "conn obj". */ - SMBVDEBUG("ran out of data\n"); - ctx->f_ecnt = 0; /* Force closed. */ - ctx->f_flags |= SMBFS_RDD_EOF; - return (EIO); -} + bzero(&tmp_fh, sizeof (tmp_fh)); -static int -smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx) -{ - int error = 0; - if (ctx->f_name) - kmem_free(ctx->f_name, ctx->f_namesz); - if (ctx->f_t2) - smb_t2_done(ctx->f_t2); /* - * If SMBFS_RDD_FINDFIRST is still set, we were opened - * but never saw a findfirst, so we don't have any - * search handle to close. + * 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 ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0) - error = smbfs_smb_findclose2(ctx); + rights = SA_RIGHT_FILE_READ_DATA; + efa = SMB_EFA_NORMAL; + if (name && *name == '.') + efa |= SMB_EFA_HIDDEN; + error = smbfs_smb_ntcreatex(dnp, + name, nmlen, 0, /* xattr */ + rights, SMB_EFA_DIRECTORY, + NTCREATEX_SHARE_ACCESS_ALL, + NTCREATEX_DISP_CREATE, + NTCREATEX_OPTIONS_DIRECTORY, + scrp, &tmp_fh, NULL, NULL); + if (error == 0) { + (void) smb_smb_close(ssp, &tmp_fh, scrp); + } + return (error); } +/* + * Protocol-level directory open + */ int smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen, int attr, struct smb_cred *scrp, struct smbfs_fctx **ctxpp) { + struct smb_share *ssp = dnp->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); struct smbfs_fctx *ctx; int error; @@ -2288,50 +586,56 @@ smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen, ctx->f_flags = SMBFS_RDD_FINDFIRST; ctx->f_dnp = dnp; ctx->f_scred = scrp; - ctx->f_ssp = dnp->n_mount->smi_share; + ctx->f_ssp = ssp; if (dnp->n_flag & N_XATTR) { error = smbfs_xa_findopen(ctx, dnp, wild, wlen); goto out; } - if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0) { - error = smbfs_smb_findopenLM1(ctx, dnp, wild, wlen, attr); + if (vcp->vc_flags & SMBV_SMB2) { + error = smbfs_smb2_findopen(ctx, dnp, wild, wlen, attr); } else { error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr); } out: - if (error) - (void) smbfs_smb_findclose(ctx, scrp); - else + ctx->f_scred = NULL; + if (error) { + kmem_free(ctx, sizeof (*ctx)); + } else { *ctxpp = ctx; + } + return (error); } int smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp) { - int error; + int error = 0; + uint16_t lim; /* * Note: "limit" (maxcount) needs to fit in a short! */ if (limit > 0xffff) limit = 0xffff; + lim = (uint16_t)limit; ctx->f_scred = scrp; for (;;) { bzero(&ctx->f_attr, sizeof (ctx->f_attr)); switch (ctx->f_type) { - case ft_LM1: - error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit); + + case ft_SMB2: + error = smbfs_smb2_findnext(ctx, lim); break; case ft_LM2: - error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit); + error = smbfs_smb_findnextLM2(ctx, lim); break; case ft_XA: - error = smbfs_xa_findnext(ctx, (uint16_t)limit); + error = smbfs_xa_findnext(ctx, lim); break; default: ASSERT(0); @@ -2339,7 +643,7 @@ smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp) break; } if (error) - return (error); + break; /* * Skip "." or ".." - easy now that ctx->f_name * has already been converted to utf-8 format. @@ -2350,14 +654,18 @@ smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp) continue; break; } + ctx->f_scred = NULL; + if (error != 0) + return (error); - /* - * Moved the smbfs_fname_tolocal(ctx) call into - * the ..._findnext functions above. - */ + ctx->f_inum = smbfs_getino(ctx->f_dnp, + ctx->f_name, ctx->f_nmlen); - ctx->f_inum = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen); - return (0); +#ifdef DEBUG + SMBVDEBUG("findnext: (%s)\n", ctx->f_name); +#endif + + return (error); } @@ -2368,8 +676,8 @@ smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp) ctx->f_scred = scrp; switch (ctx->f_type) { - case ft_LM1: - error = smbfs_smb_findcloseLM1(ctx); + case ft_SMB2: + error = smbfs_smb2_findclose(ctx); break; case ft_LM2: error = smbfs_smb_findcloseLM2(ctx); @@ -2381,6 +689,7 @@ smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp) error = ENOSYS; break; } + ctx->f_scred = NULL; if (ctx->f_rname) kmem_free(ctx->f_rname, ctx->f_rnamelen); if (ctx->f_firstnm) @@ -2419,11 +728,6 @@ smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp, return (EINVAL); } - /* - * XXX: Should use _qpathinfo here instead. - * (if SMB_CAP_NT_SMBS) - */ - /* * Shared lock for n_fid use (smb_flush). */ @@ -2431,14 +735,6 @@ smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp, if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr)) return (EINTR); - /* - * 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) @@ -2472,147 +768,48 @@ out: * which the caller should free. */ int -smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid, - struct smb_cred *scrp, uint32_t selector, - mblk_t **res, uint32_t *reslen) +smbfs_smb_getsec(struct smb_share *ssp, smb_fh_t *fhp, + uint32_t selector, mblk_t **res, uint32_t *reslen, + struct smb_cred *scrp) { - struct smb_ntrq *ntp; - struct mbchain *mbp; - struct mdchain *mdp; + struct smb_vc *vcp = SSTOVC(ssp); int error, len; - error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC, - scrp, &ntp); - if (error) - return (error); - - /* Parameters part */ - mbp = &ntp->nt_tparam; - mb_init(mbp); - mb_put_uint16le(mbp, fid); - mb_put_uint16le(mbp, 0); /* reserved */ - mb_put_uint32le(mbp, selector); - /* Data part (none) */ - - /* Max. returned parameters and data. */ - 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); - if (error) - goto done; + if (vcp->vc_flags & SMBV_SMB2) { + error = smbfs_smb2_getsec(ssp, &fhp->fh_fid2, + selector, res, reslen, scrp); + } else { + error = smbfs_smb1_getsec(ssp, fhp->fh_fid1, + selector, res, reslen, scrp); + } /* * get the data part. */ - mdp = &ntp->nt_rdata; - if (mdp->md_top == NULL) { - SMBVDEBUG("null md_top? fid 0x%x\n", fid); + if (*res == NULL) { error = EBADRPC; goto done; } /* - * The returned parameter SD_length should match - * the length of the returned data. Unfortunately, - * we have to work around server bugs here. - */ - len = m_fixhdr(mdp->md_top); - if (len != *reslen) { - SMBVDEBUG("len %d *reslen %d fid 0x%x\n", - len, *reslen, fid); - } - - /* - * Actual data provided is < returned SD_length. - * - * 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 message length is < returned SD_length, + * correct *reslen (reduce it). It greater, + * just ignore the extra data. */ + len = m_fixhdr(*res); if (len < *reslen) *reslen = len; - /* - * Actual data provided is > returned SD_length. - * (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0) - * Narrow work-around for returned SD_length==0. - */ - if (len > *reslen) { - /* - * Increase *reslen, but carefully. - */ - if (*reslen == 0 && len <= ntp->nt_maxdcount) - *reslen = len; - } - error = md_get_mbuf(mdp, len, res); - done: if (error == 0 && *res == NULL) { ASSERT(*res); error = EBADRPC; } - smb_nt_done(ntp); - return (error); -} - -#ifdef APPLE -/* - * Wrapper for _getsd() compatible with darwin code. - */ -int -smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp, - uint32_t selector, struct ntsecdesc **res) -{ - int error; - uint32_t len, olen; - struct mdchain *mdp, md_store; - struct mbuf *m; - - bzero(mdp, sizeof (*mdp)); - len = 500; /* "overlarge" values => server errors */ -again: - olen = len; - error = smbfs_smb_getsec_m(ssp, fid, scrp, selector, &m, &len); - /* - * Server may give us an error indicating that we - * need a larger data buffer to receive the SD, - * and the size we'll need. Use the given size, - * but only after a sanity check. - * - * XXX: Check for specific error values here? - * XXX: also ... && len <= MAX_RAW_SD_SIZE - */ - if (error && len > olen) - goto again; - - if (error) - return (error); - - mdp = &md_store; - md_initm(mdp, m); - MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK); - error = md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM); - md_done(mdp); - return (error); } -#endif /* APPLE */ /* * OTW function to Set a security descriptor (SD). @@ -2621,108 +818,21 @@ again: * Note: This normally consumes mbp->mb_top, and clears * that pointer when it does. */ -int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid, - struct smb_cred *scrp, uint32_t selector, mblk_t **mp) -{ - struct smb_ntrq *ntp; - struct mbchain *mbp; - int error; - - error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC, - scrp, &ntp); - if (error) - return (error); - - /* Parameters part */ - mbp = &ntp->nt_tparam; - mb_init(mbp); - mb_put_uint16le(mbp, fid); - mb_put_uint16le(mbp, 0); /* reserved */ - mb_put_uint32le(mbp, selector); - - /* Data part */ - mbp = &ntp->nt_tdata; - mb_initm(mbp, *mp); - *mp = NULL; /* consumed */ - - /* No returned parameters or data. */ - ntp->nt_maxpcount = 0; - ntp->nt_maxdcount = 0; - - error = smb_nt_request(ntp); - smb_nt_done(ntp); - - return (error); -} - -#ifdef APPLE -/* - * This function builds the SD given the various parts. - */ 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) +smbfs_smb_setsec(struct smb_share *ssp, smb_fh_t *fhp, + uint32_t selector, mblk_t **mp, + struct smb_cred *scrp) { - struct mbchain *mbp, mb_store; - struct ntsecdesc ntsd; - int error, off; + struct smb_vc *vcp = SSTOVC(ssp); + int error; - /* - * Build the SD as its own mbuf chain and pass it to - * smbfs_smb_setsec_m() - */ - mbp = &mb_store; - 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); + if (vcp->vc_flags & SMBV_SMB2) { + error = smbfs_smb2_setsec(ssp, &fhp->fh_fid2, + selector, mp, scrp); + } else { + error = smbfs_smb1_setsec(ssp, fhp->fh_fid1, + selector, mp, scrp); } - 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); - - /* - * Just pass the mbuf to _setsec_m - * It will clear mb_top if consumed. - */ - error = smbfs_smb_setsec_m(ssp, fid, scrp, selector, &mbp->mb_top); - mb_done(mbp); return (error); } - -#endif /* APPLE */ diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c new file mode 100644 index 0000000000..6c00816133 --- /dev/null +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c @@ -0,0 +1,926 @@ +/* + * Copyright (c) 2000-2001 Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + + +/* + * Todo: locking over-the-wire + */ +#if 0 // todo + +int +smbfs_smb1_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)); + + /* After reconnect, n_fid is invalid */ + if (np->n_vcgenid != ssp->ss_vcgenid) + return (ESTALE); + + if (op == SMB_LOCK_SHARED) + ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; + /* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */ + 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_uint16le(mbp, np->n_fid); + mb_put_uint8(mbp, ltype); /* locktype */ + mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ + mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */ + 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); +} + +#endif // todo + +/* + * Common function for QueryFileInfo, QueryPathInfo. + */ +int +smbfs_smb1_trans2_query(struct smbnode *np, uint16_t fid, + struct smbfattr *fap, struct smb_cred *scrp) +{ + struct smb_share *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + struct smb_t2rq *t2p; + struct mbchain *mbp; + struct mdchain *mdp; + uint16_t cmd; + uint16_t infolevel = SMB_QFILEINFO_ALL_INFO; + int error; + + /* + * If we have a valid open FID, use it. + */ + if (fid != SMB_FID_UNUSED) + cmd = SMB_TRANS2_QUERY_FILE_INFORMATION; + else + cmd = SMB_TRANS2_QUERY_PATH_INFORMATION; + + error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p); + if (error) + return (error); + mbp = &t2p->t2_tparam; + mb_init(mbp); + + if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION) + mb_put_uint16le(mbp, fid); + + mb_put_uint16le(mbp, infolevel); + + if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) { + mb_put_uint32le(mbp, 0); + /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */ + error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\'); + if (error) + goto out; + } + + t2p->t2_maxpcount = 2; + t2p->t2_maxdcount = vcp->vc_txmax; + error = smb_t2_request(t2p); + if (error) + goto out; + + /* + * Parse the SMB_QFILEINFO_ALL_INFO + */ + mdp = &t2p->t2_rdata; + error = smbfs_decode_file_all_info(ssp, mdp, fap); + +out: + smb_t2_done(t2p); + + return (error); +} + +/* + * Get some FS information + */ +static int +smbfs_smb1_query_fs_info(struct smb_share *ssp, struct mdchain *info_mdp, + uint16_t level, struct smb_cred *scrp) +{ + struct smb_t2rq *t2p; + struct mbchain *mbp; + struct mdchain *mdp; + 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, level); + t2p->t2_maxpcount = 4; + t2p->t2_maxdcount = 1024; + error = smb_t2_request(t2p); + if (error) + goto out; + + mdp = &t2p->t2_rdata; + *info_mdp = *mdp; + bzero(mdp, sizeof (*mdp)); + +out: + smb_t2_done(t2p); + return (error); +} + +/* + * Get FILE_FS_ATTRIBUTE_INFORMATION + */ +int +smbfs_smb1_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa, + struct smb_cred *scrp) +{ + struct mdchain info_mdc, *mdp = &info_mdc; + int error; + + bzero(mdp, sizeof (*mdp)); + + error = smbfs_smb1_query_fs_info(ssp, mdp, + SMB_QFS_ATTRIBUTE_INFO, scrp); + if (error) + goto out; + error = smbfs_decode_fs_attr_info(ssp, mdp, fsa); + +out: + md_done(mdp); + + return (error); +} + +/* + * Get FileFsFullSizeInformation and + * parse into *info + */ +int +smbfs_smb1_statfs(struct smb_share *ssp, + struct smb_fs_size_info *info, + struct smb_cred *scrp) +{ + struct mdchain info_mdc, *mdp = &info_mdc; + struct smb_vc *vcp = SSTOVC(ssp); + uint16_t level; + int error; + + bzero(mdp, sizeof (*mdp)); + + if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) + level = SMB_QFS_FULL_SIZE_INFORMATION; + else + level = SMB_QFS_SIZE_INFO; + error = smbfs_smb1_query_fs_info(ssp, mdp, level, scrp); + if (error) + goto out; + + md_get_uint64le(mdp, &info->total_units); + md_get_uint64le(mdp, &info->caller_avail); + if (level == SMB_QFS_FULL_SIZE_INFORMATION) + md_get_uint64le(mdp, &info->actual_avail); + else + info->actual_avail = info->caller_avail; + + md_get_uint32le(mdp, &info->sect_per_unit); + error = md_get_uint32le(mdp, &info->bytes_per_sect); + +out: + md_done(mdp); + + return (error); +} + +int +smbfs_smb1_flush(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp) +{ + struct smb_rq rq, *rqp = &rq; + struct mbchain *mbp; + int error; + + 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_uint16le(mbp, fid); + smb_rq_wend(rqp); + smb_rq_bstart(rqp); + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + smb_rq_done(rqp); + return (error); +} + +/* + * Set file info via an open handle. + * Caller provides payload, info level. + */ +static int +smbfs_smb1_setinfo_file(struct smb_share *ssp, uint16_t fid, + struct mbchain *info_mbp, uint16_t level, struct smb_cred *scrp) +{ + struct smb_t2rq *t2p = NULL; + struct mbchain *mbp; + uint16_t cmd = SMB_TRANS2_SET_FILE_INFORMATION; + int error; + + ASSERT(fid != SMB_FID_UNUSED); + + error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p); + if (error) + return (error); + mbp = &t2p->t2_tparam; + mb_init(mbp); + mb_put_uint16le(mbp, fid); + mb_put_uint16le(mbp, level); + mb_put_uint16le(mbp, 0); /* pad */ + + /* put the payload */ + mbp = &t2p->t2_tdata; + mb_init(mbp); + error = mb_put_mbchain(mbp, info_mbp); + if (error) + goto out; + + t2p->t2_maxpcount = 2; + t2p->t2_maxdcount = 0; + error = smb_t2_request(t2p); + +out: + smb_t2_done(t2p); + + return (error); +} + +int +smbfs_smb1_seteof(struct smb_share *ssp, uint16_t fid, + uint64_t newsize, struct smb_cred *scrp) +{ + struct mbchain data_mb, *mbp = &data_mb; + uint16_t level; + int error; + + if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) + level = SMB_SFILEINFO_END_OF_FILE_INFORMATION; + else + level = SMB_SFILEINFO_END_OF_FILE_INFO; + + mb_init(mbp); + error = mb_put_uint64le(mbp, newsize); + if (error) + goto out; + error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp); + +out: + mb_done(mbp); + return (error); +} + +int +smbfs_smb1_setdisp(struct smb_share *ssp, uint16_t fid, + uint8_t newdisp, struct smb_cred *scrp) +{ + struct mbchain data_mb, *mbp = &data_mb; + uint16_t level; + int error; + + if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) + level = SMB_SFILEINFO_DISPOSITION_INFORMATION; + else + level = SMB_SFILEINFO_DISPOSITION_INFO; + + mb_init(mbp); + error = mb_put_uint8(mbp, newdisp); + if (error) + goto out; + error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp); + +out: + mb_done(mbp); + + return (error); +} + +/* + * Set FileBasicInformation on an open handle + * Caller builds the mbchain. + * Always have a FID here. + */ +int +smbfs_smb1_setfattr(struct smb_share *ssp, uint16_t fid, + struct mbchain *mbp, struct smb_cred *scrp) +{ + uint16_t level; + int error; + + if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) + level = SMB_SFILEINFO_BASIC_INFORMATION; + else + level = SMB_SFILEINFO_BASIC_INFO; + error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp); + + return (error); +} + +/* + * On SMB1, the trans2 rename only allows a rename where the + * source and target are in the same directory. If you give + * the server any separators, you get "status not supported". + * + * Why bother using this instead of smbfs_smb1_oldrename? + * Because it works with an open file, and some servers don't + * allow oldrename of a file that's currently open. We call + * this when deleting an open file in smbfsremove(), where + * the rename is always in the same directory. + */ +/*ARGSUSED*/ +int +smbfs_smb1_t2rename(struct smbnode *np, + const char *tname, int tnlen, + uint16_t fid, struct smb_cred *scrp) +{ + struct smb_share *ssp = np->n_mount->smi_share; + struct mbchain data_mb, *mbp = &data_mb; + struct smb_vc *vcp = SSTOVC(ssp); + uint32_t *name_lenp; + uint16_t level = SMB_SFILEINFO_RENAME_INFORMATION; + int base, len; + int error; + + mb_init(mbp); + mb_put_uint32le(mbp, 0); /* don't overwrite */ + mb_put_uint32le(mbp, 0); /* obsolete target dir fid */ + name_lenp = mb_reserve(mbp, 4); /* name len */ + + /* New name */ + base = mbp->mb_count; + error = smb_put_dmem(mbp, vcp, tname, tnlen, SMB_CS_NONE, NULL); + if (error) + goto out; + len = mbp->mb_count - base; + *name_lenp = htolel(len); + + error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp); + +out: + mb_done(mbp); + return (error); +} + +/* + * Do an SMB1 (old style) rename using a full dest. path. + * This is used when renaming to a different directory, + * because the (preferred) t2rename can't do that. + */ +int +smbfs_smb1_oldrename(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; + char sep; + + 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); + + /* + * When we're not adding any component name, the + * passed sep is ignored, so just pass sep=0. + */ + mb_put_uint8(mbp, SMB_DT_ASCII); + error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0); + if (error) + goto out; + + /* + * After XATTR directories, separator is ":" + */ + sep = (src->n_flag & N_XATTR) ? ':' : '\\'; + mb_put_uint8(mbp, SMB_DT_ASCII); + error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, sep); + if (error) + goto out; + + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); +out: + smb_rq_done(rqp); + return (error); +} + + +/* + * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect + */ +static int +smbfs_smb1_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 ecnt, eos, lno, flags; + uint16_t amask, limit; + int error; + + /* smbfs_smb_findnextLM2 sets this */ + limit = ctx->f_limit; + amask = (uint16_t)ctx->f_attrmask; + + if (ctx->f_t2) { + smb_t2_done(ctx->f_t2); + ctx->f_t2 = NULL; + } + 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, amask); + mb_put_uint16le(mbp, limit); + mb_put_uint16le(mbp, flags); + mb_put_uint16le(mbp, ctx->f_infolevel); + mb_put_uint32le(mbp, 0); + error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, + ctx->f_wildcard, ctx->f_wclen, '\\'); + 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_uint16le(mbp, ctx->f_Sid); + mb_put_uint16le(mbp, limit); + mb_put_uint16le(mbp, ctx->f_infolevel); + /* Send whatever resume key we received... */ + mb_put_uint32le(mbp, ctx->f_rkey); + mb_put_uint16le(mbp, flags); + /* ... and the resume name if we have one. */ + 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); + } + t2p->t2_maxpcount = 5 * 2; + t2p->t2_maxdcount = 0xF000; /* 64K less some overhead */ + error = smb_t2_request(t2p); + if (error) + return (error); + + /* + * This is the "resume name" we just sent. + * We want the new one (if any) that may be + * found in the response we just received and + * will now begin parsing. Free the old one + * now so we'll know if we found a new one. + */ + if (ctx->f_rname) { + kmem_free(ctx->f_rname, ctx->f_rnamelen); + ctx->f_rname = NULL; + ctx->f_rnamelen = 0; + } + + mdp = &t2p->t2_rparam; + if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { + if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0) + goto nodata; + ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; + } + md_get_uint16le(mdp, &ecnt); /* entry count */ + md_get_uint16le(mdp, &eos); /* end of search */ + md_get_uint16le(mdp, NULL); /* EA err. off. */ + error = md_get_uint16le(mdp, &lno); /* last name off. */ + if (error != 0) + goto nodata; + + /* + * The "end of search" flag from an XP server sometimes + * 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 entry count. + */ + ctx->f_ecnt = ecnt; + if (eos || ctx->f_ecnt == 0) + ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; + if (ctx->f_ecnt == 0) + return (ENOENT); + + /* Last Name Off (LNO) is the entry with the resume name. */ + ctx->f_rnameofs = lno; + ctx->f_eofs = 0; + + /* + * Have data. Put the payload in ctx->f_mdchain + * Note struct assignments here. + */ + mdp = &t2p->t2_rdata; + md_done(&ctx->f_mdchain); + ctx->f_mdchain = *mdp; + ctx->f_left = m_fixhdr(mdp->md_top); + bzero(mdp, sizeof (*mdp)); + + return (0); + +nodata: + /* + * Failed parsing the FindFirst or FindNext response. + * Force this directory listing closed, otherwise the + * calling process may hang in an infinite loop. + */ + ctx->f_ecnt = 0; /* Force closed. */ + ctx->f_flags |= SMBFS_RDD_EOF; + return (EIO); +} + +static int +smbfs_smb1_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_uint16le(mbp, ctx->f_Sid); + 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*/ +int +smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, + const char *wildcard, int wclen, uint32_t attr) +{ + + ctx->f_type = ft_LM2; + ctx->f_namesz = SMB_MAXFNAMELEN + 1; + ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP); + ctx->f_infolevel = SMB_FIND_FULL_DIRECTORY_INFO; + ctx->f_attrmask = attr; + ctx->f_wildcard = wildcard; + ctx->f_wclen = wclen; + return (0); +} + +int +smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx) +{ + int error = 0; + if (ctx->f_name) + kmem_free(ctx->f_name, ctx->f_namesz); + if (ctx->f_t2) + smb_t2_done(ctx->f_t2); + md_done(&ctx->f_mdchain); + + /* + * If SMBFS_RDD_FINDFIRST is still set, we were opened + * but never saw a findfirst, so we don't have any + * search handle to close. + */ + if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0) + error = smbfs_smb1_findclose2(ctx); + return (error); +} + +/* + * Get a buffer of directory entries (if we don't already have + * some remaining in the current buffer) then decode one. + */ +int +smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit) +{ + int error; + + /* + * If we've scanned to the end of the current buffer + * try to read anohther buffer of dir entries. + * Treat anything less than 8 bytes as an "empty" + * buffer to ensure we can read something. + * (There may be up to 8 bytes of padding.) + */ + if ((ctx->f_eofs + 8) > ctx->f_left) { + /* Scanned the whole buffer. */ + if (ctx->f_flags & SMBFS_RDD_EOF) + return (ENOENT); + ctx->f_limit = limit; + error = smbfs_smb1_trans2find2(ctx); + if (error) + return (error); + ctx->f_otws++; + } + + /* + * Decode one entry, advance f_eofs + */ + error = smbfs_decode_dirent(ctx); + + return (error); +} + +/* + * Helper for smbfs_xa_get_streaminfo + * Query stream info + */ +int +smbfs_smb1_get_streaminfo(smbnode_t *np, struct mdchain *mdp, + struct smb_cred *scrp) +{ + smb_share_t *ssp = np->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + struct smb_t2rq *t2p = NULL; + struct mbchain *mbp; + mblk_t *m; + uint16_t cmd = SMB_TRANS2_QUERY_PATH_INFORMATION; + int error; + + error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p); + if (error) + return (error); + + mbp = &t2p->t2_tparam; + (void) mb_init(mbp); + (void) mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO); + (void) mb_put_uint32le(mbp, 0); + error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, 0); + if (error) + goto out; + + t2p->t2_maxpcount = 2; + t2p->t2_maxdcount = INT16_MAX; + error = smb_t2_request(t2p); + if (error) { + if (t2p->t2_sr_error == NT_STATUS_INVALID_PARAMETER) + error = ENOTSUP; + goto out; + } + + /* + * Have data. Move it to *mdp + */ + m = t2p->t2_rdata.md_top; + if (m == NULL) { + error = EBADRPC; + goto out; + } + t2p->t2_rdata.md_top = NULL; + md_initm(mdp, m); + +out: + smb_t2_done(t2p); + return (error); +} + +/* + * OTW function to Get a security descriptor (SD). + * + * The *reslen param is bufsize(in) / length(out) + * Note: On success, this fills in mdp->md_top, + * which the caller should free. + */ +int +smbfs_smb1_getsec(struct smb_share *ssp, uint16_t fid, + uint32_t selector, mblk_t **res, uint32_t *reslen, + struct smb_cred *scrp) +{ + struct smb_ntrq *ntp; + struct mbchain *mbp; + struct mdchain *mdp; + uint32_t dlen; + int error; + + *res = NULL; + + error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC, + scrp, &ntp); + if (error) + return (error); + + /* Parameters part */ + mbp = &ntp->nt_tparam; + mb_init(mbp); + mb_put_uint16le(mbp, fid); + mb_put_uint16le(mbp, 0); /* reserved */ + mb_put_uint32le(mbp, selector); + /* Data part (none) */ + + /* Max. returned parameters and data. */ + ntp->nt_maxpcount = 4; + ntp->nt_maxdcount = *reslen; // out buf size + + error = smb_nt_request(ntp); + if (error && !(ntp->nt_flags & SMBT2_MOREDATA)) + goto done; + + /* Get data len */ + mdp = &ntp->nt_rparam; + error = md_get_uint32le(mdp, &dlen); + if (error) + goto done; + + /* + * if there's more data than we said we could receive, + * here is where we pick up the length of it + */ + *reslen = dlen; + if (dlen == 0) { + error = EBADRPC; + goto done; + } + + /* + * get the SD data part. + */ + mdp = &ntp->nt_rdata; + error = md_get_mbuf(mdp, dlen, res); + +done: + if (error == 0 && *res == NULL) { + ASSERT(*res); + error = EBADRPC; + } + + smb_nt_done(ntp); + return (error); +} + + +/* + * OTW function to Set a security descriptor (SD). + * Caller data are carried in an mbchain_t. + * + * Note: This normally consumes mbp->mb_top, and clears + * that pointer when it does. + */ +int +smbfs_smb1_setsec(struct smb_share *ssp, uint16_t fid, + uint32_t selector, mblk_t **mp, struct smb_cred *scrp) +{ + struct smb_ntrq *ntp; + struct mbchain *mbp; + int error; + + error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC, + scrp, &ntp); + if (error) + return (error); + + /* Parameters part */ + mbp = &ntp->nt_tparam; + mb_init(mbp); + mb_put_uint16le(mbp, fid); + mb_put_uint16le(mbp, 0); /* reserved */ + mb_put_uint32le(mbp, selector); + + /* Data part */ + mbp = &ntp->nt_tdata; + mb_initm(mbp, *mp); + *mp = NULL; /* consumed */ + + /* No returned parameters or data. */ + ntp->nt_maxpcount = 0; + ntp->nt_maxdcount = 0; + + error = smb_nt_request(ntp); + smb_nt_done(ntp); + + return (error); +} diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c new file mode 100644 index 0000000000..80afc327c3 --- /dev/null +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c @@ -0,0 +1,896 @@ +/* + * Copyright (c) 2000-2001 Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 2011 - 2013 Apple Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +/* + * Todo: locking over-the-wire + */ +#if 0 // todo + +int +smbfs_smb2_locking(struct smbnode *np, int op, uint32_t pid, + offset_t start, uint64_t len, int largelock, + struct smb_cred *scrp, uint32_t timeout) +{ + return (ENOTSUP); +} + +#endif // todo + +/* + * Helper for smbfs_getattr_otw + * used when we don't have an open FID + * + * For SMB2 we need to do an attribute-only open. The + * data returned by open gets us everything we need, so + * just close the handle and we're done. + */ +int +smbfs_smb2_getpattr( + struct smbnode *np, + struct smbfattr *fap, + struct smb_cred *scrp) +{ + smb_fh_t tmp_fh; + struct smb_share *ssp = np->n_mount->smi_share; + uint32_t rights = (STD_RIGHT_READ_CONTROL_ACCESS | + SA_RIGHT_FILE_READ_ATTRIBUTES); + int error; + + bzero(&tmp_fh, sizeof (tmp_fh)); + error = smbfs_smb_ntcreatex(np, + NULL, 0, 0, /* name nmlen xattr */ + rights, SMB_EFA_NORMAL, + NTCREATEX_SHARE_ACCESS_ALL, + NTCREATEX_DISP_OPEN, + 0, /* create options */ + scrp, &tmp_fh, + NULL, fap); + if (error == 0) { + (void) smb_smb_close(ssp, &tmp_fh, scrp); + } + + return (error); +} + +/* + * Common SMB2 query file info + */ +static int +smbfs_smb2_query_info(struct smb_share *ssp, smb2fid_t *fid, + struct mdchain *info_mdp, uint32_t *iolen, + uint8_t type, uint8_t level, uint32_t addl_info, + struct smb_cred *scrp) +{ + struct smb_rq *rqp = NULL; + struct mbchain *mbp; + struct mdchain *mdp; + uint32_t dlen = 0; + uint16_t doff = 0; + uint16_t ssize = 0; + int error; + + error = smb_rq_alloc(SSTOCP(ssp), SMB2_QUERY_INFO, scrp, &rqp); + if (error) + goto out; + + /* + * Build the SMB 2 Query Info req. + */ + smb_rq_getrequest(rqp, &mbp); + mb_put_uint16le(mbp, 41); // struct size + mb_put_uint8(mbp, type); + mb_put_uint8(mbp, level); + mb_put_uint32le(mbp, *iolen); // out buf len + mb_put_uint16le(mbp, 0); // in buf off + mb_put_uint16le(mbp, 0); // reserved + mb_put_uint32le(mbp, 0); // in buf len + mb_put_uint32le(mbp, addl_info); + mb_put_uint32le(mbp, 0); // flags + mb_put_uint64le(mbp, fid->fid_persistent); + mb_put_uint64le(mbp, fid->fid_volatile); + + error = smb2_rq_simple(rqp); + if (error) { + if (rqp->sr_error == NT_STATUS_INVALID_PARAMETER) + error = ENOTSUP; + goto out; + } + + /* + * Parse SMB 2 Query Info response + */ + smb_rq_getreply(rqp, &mdp); + + /* Check structure size is 9 */ + md_get_uint16le(mdp, &ssize); + if (ssize != 9) { + error = EBADRPC; + goto out; + } + + /* Get data off, len */ + md_get_uint16le(mdp, &doff); + md_get_uint32le(mdp, &dlen); + *iolen = dlen; + + /* + * Skip ahead to the payload, as needed. + * Current offset is SMB2_HDRLEN + 8. + */ + if (dlen != 0) { + mblk_t *m = NULL; + int skip = (int)doff - (SMB2_HDRLEN + 8); + if (skip < 0) { + error = EBADRPC; + goto out; + } + if (skip > 0) { + md_get_mem(mdp, NULL, skip, MB_MSYSTEM); + } + error = md_get_mbuf(mdp, dlen, &m); + if (error) + goto out; + md_initm(info_mdp, m); + } + +out: + smb_rq_done(rqp); + + return (error); +} + + +/* + * Get FileAllInformation for an open file + * and parse into *fap + */ +int +smbfs_smb2_qfileinfo(struct smb_share *ssp, smb2fid_t *fid, + struct smbfattr *fap, struct smb_cred *scrp) +{ + struct mdchain info_mdc, *mdp = &info_mdc; + uint32_t iolen = 1024; + int error; + + bzero(mdp, sizeof (*mdp)); + + error = smbfs_smb2_query_info(ssp, fid, mdp, &iolen, + SMB2_0_INFO_FILE, FileAllInformation, 0, scrp); + if (error) + goto out; + + error = smbfs_decode_file_all_info(ssp, mdp, fap); + +out: + md_done(mdp); + + return (error); +} + +/* + * Get some SMB2_0_INFO_FILESYSTEM info + * + * Note: This can be called during mount. We don't have any + * smbfs_node_t or pathname, so do our own attr. open on + * the root of the share to get a handle for this request. + */ +static int +smbfs_smb2_query_fs_info(struct smb_share *ssp, struct mdchain *mdp, + uint8_t level, struct smb_cred *scrp) +{ + smb2fid_t fid; + uint32_t iolen = 1024; + boolean_t opened = B_FALSE; + int error; + + /* + * Need a FID for smb2, and this is called during mount + * so "go behind" the usual open/close functions. + */ + error = smb2_smb_ntcreate( + ssp, NULL, // name + NULL, NULL, // create ctx in, out + 0, /* NTCREATEX_FLAGS... */ + SA_RIGHT_FILE_READ_ATTRIBUTES, + SMB_EFA_NORMAL, + NTCREATEX_SHARE_ACCESS_ALL, + NTCREATEX_DISP_OPEN, + 0, /* create options */ + NTCREATEX_IMPERSONATION_IMPERSONATION, + scrp, &fid, NULL, NULL); + if (error != 0) + goto out; + opened = B_TRUE; + + error = smbfs_smb2_query_info(ssp, &fid, mdp, &iolen, + SMB2_0_INFO_FILESYSTEM, level, 0, scrp); + +out: + if (opened) + (void) smb2_smb_close(ssp, &fid, scrp); + + return (error); +} + +/* + * Get FileFsAttributeInformation and + * parse into *info + */ +int +smbfs_smb2_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *info, + struct smb_cred *scrp) +{ + struct mdchain info_mdc, *mdp = &info_mdc; + int error; + + bzero(mdp, sizeof (*mdp)); + + error = smbfs_smb2_query_fs_info(ssp, mdp, + FileFsAttributeInformation, scrp); + if (error) + goto out; + error = smbfs_decode_fs_attr_info(ssp, mdp, info); + +out: + md_done(mdp); + + return (error); +} + +/* + * Get FileFsFullSizeInformation and + * parse into *info + */ +int +smbfs_smb2_statfs(struct smb_share *ssp, + struct smb_fs_size_info *info, + struct smb_cred *scrp) +{ + struct mdchain info_mdc, *mdp = &info_mdc; + int error; + + bzero(mdp, sizeof (*mdp)); + + error = smbfs_smb2_query_fs_info(ssp, mdp, + FileFsFullSizeInformation, scrp); + if (error) + goto out; + + md_get_uint64le(mdp, &info->total_units); + md_get_uint64le(mdp, &info->caller_avail); + md_get_uint64le(mdp, &info->actual_avail); + + md_get_uint32le(mdp, &info->sect_per_unit); + error = md_get_uint32le(mdp, &info->bytes_per_sect); + +out: + md_done(mdp); + + return (error); +} + +int +smbfs_smb2_flush(struct smb_share *ssp, smb2fid_t *fid, + struct smb_cred *scrp) +{ + struct smb_rq *rqp; + struct mbchain *mbp; + int error; + + error = smb_rq_alloc(SSTOCP(ssp), SMB2_FLUSH, scrp, &rqp); + if (error) + return (error); + + /* + * Build the SMB 2 Flush Request + */ + smb_rq_getrequest(rqp, &mbp); + mb_put_uint16le(mbp, 24); /* struct size */ + mb_put_uint16le(mbp, 0); /* reserved */ + mb_put_uint32le(mbp, 0); /* reserved */ + + mb_put_uint64le(mbp, fid->fid_persistent); + mb_put_uint64le(mbp, fid->fid_volatile); + + rqp->sr_flags |= SMBR_NORECONNECT; + error = smb2_rq_simple(rqp); + smb_rq_done(rqp); + + return (error); +} + +/* + * Set file info via an open handle. + * Caller provides payload, info level. + */ +static int +smbfs_smb2_set_info(struct smb_share *ssp, smb2fid_t *fid, + struct mbchain *info_mbp, uint8_t type, uint8_t level, + uint32_t addl_info, struct smb_cred *scrp) +{ + struct smb_rq *rqp = NULL; + struct mbchain *mbp; + uint32_t *buffer_lenp; + int base, len; + int error; + + error = smb_rq_alloc(SSTOCP(ssp), SMB2_SET_INFO, scrp, &rqp); + if (error) + goto out; + + /* + * Build the SMB 2 Set Info req. + */ + smb_rq_getrequest(rqp, &mbp); + mb_put_uint16le(mbp, 33); // struct size + mb_put_uint8(mbp, type); + mb_put_uint8(mbp, level); + buffer_lenp = mb_reserve(mbp, sizeof (uint32_t)); + mb_put_uint16le(mbp, SMB2_HDRLEN + 32); // Buffer Offset + mb_put_uint16le(mbp, 0); // Reserved + mb_put_uint32le(mbp, addl_info); // Additional Info + + mb_put_uint64le(mbp, fid->fid_persistent); + mb_put_uint64le(mbp, fid->fid_volatile); + + /* + * Now the payload + */ + base = mbp->mb_count; + error = mb_put_mbchain(mbp, info_mbp); + if (error) + goto out; + len = mbp->mb_count - base; + *buffer_lenp = htolel(len); + if (error) + goto out; + + /* + * Run the request. + * Don't care about the (empty) reply. + */ + error = smb2_rq_simple(rqp); + +out: + smb_rq_done(rqp); + + return (error); +} + +int +smbfs_smb2_seteof(struct smb_share *ssp, smb2fid_t *fid, + uint64_t newsize, struct smb_cred *scrp) +{ + struct mbchain data_mb, *mbp = &data_mb; + uint8_t level = FileEndOfFileInformation; + int error; + + mb_init(mbp); + mb_put_uint64le(mbp, newsize); + error = smbfs_smb2_set_info(ssp, fid, mbp, + SMB2_0_INFO_FILE, level, 0, scrp); + mb_done(mbp); + + return (error); +} + +int +smbfs_smb2_setdisp(struct smb_share *ssp, smb2fid_t *fid, + uint8_t newdisp, struct smb_cred *scrp) +{ + struct mbchain data_mb, *mbp = &data_mb; + uint8_t level = FileDispositionInformation; + int error; + + mb_init(mbp); + mb_put_uint8(mbp, newdisp); + error = smbfs_smb2_set_info(ssp, fid, mbp, + SMB2_0_INFO_FILE, level, 0, scrp); + mb_done(mbp); + + return (error); +} + +/* + * Set FileBasicInformation on an open handle + * Caller builds the mbchain. + */ +int +smbfs_smb2_setfattr(struct smb_share *ssp, smb2fid_t *fid, + struct mbchain *mbp, struct smb_cred *scrp) +{ + uint8_t level = FileBasicInformation; + int error; + + error = smbfs_smb2_set_info(ssp, fid, mbp, + SMB2_0_INFO_FILE, level, 0, scrp); + return (error); +} + +/* + * Build a FileRenameInformation and call setinfo + */ +int +smbfs_smb2_rename(struct smbnode *np, struct smbnode *tdnp, + const char *tname, int tnlen, int overwrite, + smb2fid_t *fid, struct smb_cred *scrp) +{ + struct smb_share *ssp = np->n_mount->smi_share; + struct mbchain data_mb, *mbp = &data_mb; + uint32_t *name_lenp; + uint8_t level = FileRenameInformation; + int base, len; + int error; + + mb_init(mbp); + + mb_put_uint32le(mbp, (overwrite & 1)); + mb_put_uint32le(mbp, 0); // reserved + mb_put_uint64le(mbp, 0); // Root Dir + name_lenp = mb_reserve(mbp, 4); + + /* Target name (full path) */ + base = mbp->mb_count; + if (tnlen > 0) { + error = smbfs_fullpath(mbp, SSTOVC(ssp), + tdnp, tname, tnlen, '\\'); + if (error) + goto out; + } + len = mbp->mb_count - base; + *name_lenp = htolel(len); + + error = smbfs_smb2_set_info(ssp, fid, mbp, + SMB2_0_INFO_FILE, level, 0, scrp); + +out: + mb_done(mbp); + + return (error); +} + +/* + * Later servers have maxtransact at a megabyte or more, + * but we don't want to buffer up that much data, so use + * the lesser of that or 64k. + */ +#define SMBFS_QDIR_MAX_BUF (1<<16) + +/* + * SMB2 query directory + */ +static int +smbfs_smb2_qdir(struct smbfs_fctx *ctx) +{ + smb_fh_t *fhp = ctx->f_fhp; + smb_share_t *ssp = ctx->f_ssp; + smb_vc_t *vcp = SSTOVC(ssp); + struct smb_rq *rqp; + struct mbchain *mbp; + struct mdchain *mdp; + uint16_t *name_lenp; + uint8_t level, flags; + uint16_t ssize = 0; + uint16_t obuf_off = 0; + uint32_t obuf_len = 0; + uint32_t obuf_req; + int error; + + level = (uint8_t)ctx->f_infolevel; + flags = 0; + if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) + flags |= SMB2_QDIR_FLAG_SINGLE; + if (ctx->f_flags & SMBFS_RDD_FINDFIRST) + ctx->f_rkey = 0; + else + flags |= SMB2_QDIR_FLAG_INDEX; + + obuf_req = SMBFS_QDIR_MAX_BUF; + if (obuf_req > vcp->vc_sopt.sv2_maxtransact) + obuf_req = vcp->vc_sopt.sv2_maxtransact; + + if (ctx->f_rq) { + smb_rq_done(ctx->f_rq); + ctx->f_rq = NULL; + } + error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB2_QUERY_DIRECTORY, + ctx->f_scred, &rqp); + if (error) + return (error); + ctx->f_rq = rqp; + + /* + * Build an SMB2 Query Dir req. + */ + smb_rq_getrequest(rqp, &mbp); + + mb_put_uint16le(mbp, 33); /* Struct size */ + mb_put_uint8(mbp, level); + mb_put_uint8(mbp, flags); + mb_put_uint32le(mbp, ctx->f_rkey); /* FileIndex */ + + mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent); + mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile); + + mb_put_uint16le(mbp, 96); + name_lenp = mb_reserve(mbp, sizeof (uint16_t)); /* FileNameLen */ + mb_put_uint32le(mbp, obuf_req); /* Output Buf Len */ + + /* Add in the name if any */ + if (ctx->f_wclen > 0) { + int base, len; + + /* Put the match pattern. */ + base = mbp->mb_count; + error = smb_put_dmem(mbp, vcp, + ctx->f_wildcard, ctx->f_wclen, + SMB_CS_NONE, NULL); + if (error) + return (error); + + /* Update the FileNameLen */ + len = mbp->mb_count - base; + *name_lenp = htoles(len); + } else { + /* Empty string */ + mb_put_uint16le(mbp, 0); + *name_lenp = 0; + } + + error = smb2_rq_simple(rqp); + if (error != 0) + goto out; + + /* + * Parse the SMB2 Query Dir response + */ + smb_rq_getreply(rqp, &mdp); + + /* Check structure size is 9 */ + md_get_uint16le(mdp, &ssize); + if (ssize != 9) { + error = EBADRPC; + goto out; + } + + /* Get output buffer offset, length */ + md_get_uint16le(mdp, &obuf_off); + md_get_uint32le(mdp, &obuf_len); + + /* + * After read at EOF we'll have just one word: + * NextEntryOffset == 0 Allow some padding. + */ + if (obuf_len < 8) { + error = ENOENT; + goto out; + } + + /* + * If this reply is shorter than requested by 1k + * or more, we must have reached EOF. + */ + if ((obuf_len + 1024) < obuf_req) + ctx->f_flags |= SMBFS_RDD_EOF; + + /* + * Have data. Put the payload in ctx->f_mdchain + * Current offset is SMB2_HDRLEN + 8. + */ + { + mblk_t *m = NULL; + int skip = (int)obuf_off - (SMB2_HDRLEN + 8); + if (skip < 0) { + error = EBADRPC; + goto out; + } + if (skip > 0) { + md_get_mem(mdp, NULL, skip, MB_MSYSTEM); + } + error = md_get_mbuf(mdp, obuf_len, &m); + if (error) + goto out; + md_done(&ctx->f_mdchain); + md_initm(&ctx->f_mdchain, m); + } + + /* + * SMB2 Query Directory does not provie an EntryCount. + * Instead, we'll advance f_eofs (entry offset) + * through the range [0..f_left] + */ + ctx->f_left = obuf_len; + ctx->f_eofs = 0; + return (0); + +out: + if (error != 0) { + /* + * Failed parsing the FindFirst or FindNext response. + * Force this directory listing closed, otherwise the + * calling process may hang in an infinite loop. + */ + ctx->f_left = 0; + ctx->f_eofs = 0; + ctx->f_flags |= SMBFS_RDD_EOF; + } + + return (error); +} + +int +smbfs_smb2_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp, + const char *wildcard, int wclen, uint32_t attr) +{ + smb_fh_t *fhp = NULL; + uint32_t rights = + STD_RIGHT_READ_CONTROL_ACCESS | + SA_RIGHT_FILE_READ_ATTRIBUTES | + SA_RIGHT_FILE_READ_DATA; + int error; + + /* + * Set f_type no matter what, so cleanup will call + * smbfs_smb2_findclose, error or not. + */ + ctx->f_type = ft_SMB2; + ASSERT(ctx->f_dnp == dnp); + + /* + * Get a file handle on the directory + */ + error = smb_fh_create(ctx->f_ssp, &fhp); + if (error != 0) + goto errout; + + error = smbfs_smb_ntcreatex(dnp, + NULL, 0, 0, /* name nmlen xattr */ + rights, SMB_EFA_NORMAL, + NTCREATEX_SHARE_ACCESS_ALL, + NTCREATEX_DISP_OPEN, + 0, /* create options */ + ctx->f_scred, fhp, + NULL, NULL); /* cr_act_p fa_p */ + if (error != 0) + goto errout; + + fhp->fh_rights = rights; + smb_fh_opened(fhp); + ctx->f_fhp = fhp; + + ctx->f_namesz = SMB_MAXFNAMELEN + 1; + ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP); + ctx->f_infolevel = FileFullDirectoryInformation; + ctx->f_attrmask = attr; + ctx->f_wildcard = wildcard; + ctx->f_wclen = wclen; + + return (0); + +errout: + if (fhp != NULL) + smb_fh_rele(fhp); + return (error); +} + +int +smbfs_smb2_findclose(struct smbfs_fctx *ctx) +{ + smb_fh_t *fhp = NULL; + + if ((fhp = ctx->f_fhp) != NULL) { + ctx->f_fhp = NULL; + smb_fh_rele(fhp); + } + if (ctx->f_name) + kmem_free(ctx->f_name, ctx->f_namesz); + if (ctx->f_rq) + smb_rq_done(ctx->f_rq); + md_done(&ctx->f_mdchain); + + return (0); +} + +/* + * Get a buffer of directory entries (if we don't already have + * some remaining in the current buffer) then decode one. + */ +int +smbfs_smb2_findnext(struct smbfs_fctx *ctx, uint16_t limit) +{ + int error; + + /* + * If we've scanned to the end of the current buffer + * try to read anohther buffer of dir entries. + * Treat anything less than 8 bytes as an "empty" + * buffer to ensure we can read something. + * (There may be up to 8 bytes of padding.) + */ + if ((ctx->f_eofs + 8) > ctx->f_left) { + /* Scanned the whole buffer. */ + if (ctx->f_flags & SMBFS_RDD_EOF) + return (ENOENT); + ctx->f_limit = limit; + error = smbfs_smb2_qdir(ctx); + if (error) + return (error); + ctx->f_otws++; + } + + /* + * Decode one entry + */ + error = smbfs_decode_dirent(ctx); + + return (error); +} + + +/* + * Helper for smbfs_xa_get_streaminfo + * Query stream info + */ +int +smbfs_smb2_get_streaminfo(smbnode_t *np, struct mdchain *mdp, + struct smb_cred *scrp) +{ + smb_share_t *ssp = np->n_mount->smi_share; + smb_fh_t *fhp = NULL; + uint32_t rights = + STD_RIGHT_READ_CONTROL_ACCESS | + SA_RIGHT_FILE_READ_ATTRIBUTES; + uint32_t iolen = INT16_MAX; + int error; + + /* + * Get a file handle on the object + * with read attr. rights. + */ + error = smb_fh_create(ssp, &fhp); + if (error != 0) + goto out; + error = smbfs_smb_ntcreatex(np, + NULL, 0, 0, /* name nmlen xattr */ + rights, SMB_EFA_NORMAL, + NTCREATEX_SHARE_ACCESS_ALL, + NTCREATEX_DISP_OPEN, + 0, /* create options */ + scrp, fhp, NULL, NULL); + if (error != 0) + goto out; + + smb_fh_opened(fhp); + + /* + * Query stream info + */ + error = smbfs_smb2_query_info(ssp, &fhp->fh_fid2, mdp, &iolen, + SMB2_0_INFO_FILE, FileStreamInformation, 0, scrp); + +out: + if (fhp != NULL) + smb_fh_rele(fhp); + return (error); +} + + +/* + * OTW function to Get a security descriptor (SD). + * + * The *reslen param is bufsize(in) / length(out) + * Note: On success, this fills in mdp->md_top, + * which the caller should free. + */ +int +smbfs_smb2_getsec(struct smb_share *ssp, smb2fid_t *fid, + uint32_t selector, mblk_t **res, uint32_t *reslen, + struct smb_cred *scrp) +{ + struct mdchain info_mdc, *mdp = &info_mdc; + int error; + + bzero(mdp, sizeof (*mdp)); + + error = smbfs_smb2_query_info(ssp, fid, mdp, reslen, + SMB2_0_INFO_SECURITY, 0, selector, scrp); + if (error) + goto out; + + if (mdp->md_top == NULL) { + error = EBADRPC; + goto out; + } + *res = mdp->md_top; + mdp->md_top = NULL; + +out: + md_done(mdp); + return (error); +} + + +/* + * OTW function to Set a security descriptor (SD). + * Caller data are carried in an mbchain_t. + * + * Note: This normally consumes mbp->mb_top, and clears + * that pointer when it does. + */ +int +smbfs_smb2_setsec(struct smb_share *ssp, smb2fid_t *fid, + uint32_t selector, mblk_t **mp, struct smb_cred *scrp) +{ + struct mbchain info_mbp, *mbp = &info_mbp; + int error; + + ASSERT(*mp != NULL); + mb_initm(mbp, *mp); + *mp = NULL; /* consumed */ + + error = smbfs_smb2_set_info(ssp, fid, mbp, + SMB2_0_INFO_SECURITY, 0, selector, scrp); + + mb_done(mbp); + + return (error); +} diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c index 71d49c49b4..0b5eb411f1 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c @@ -33,9 +33,10 @@ */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -47,6 +48,7 @@ #include #include +#include #include #include #include @@ -73,10 +75,11 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp, int unicode = (SMB_UNICODE_STRINGS(vcp)) ? 1 : 0; int error; - if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0) - caseopt |= SMB_CS_UPPER; - - if (unicode) { + /* + * SMB1 may need an alignment pad before (not SMB2) + */ + if (((vcp)->vc_flags & SMBV_SMB2) == 0 && + ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) != 0) { error = mb_put_padbyte(mbp); if (error) return (error); @@ -122,11 +125,14 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp, if (error) return (error); } - /* Put NULL termination. */ - if (unicode) - error = mb_put_uint16le(mbp, 0); - else - error = mb_put_uint8(mbp, 0); + + /* SMB1 wants NULL termination. */ + if (((vcp)->vc_flags & SMBV_SMB2) == 0) { + if (unicode) + error = mb_put_uint16le(mbp, 0); + else + error = mb_put_uint8(mbp, 0); + } return (error); } @@ -183,3 +189,271 @@ errout: */ (void) strlcpy(ctx->f_name, "?", ctx->f_namesz); } + +/* + * Decode a directory entry from OtW form into ctx->f_attr + * + * Caller already put some (wire-format) directory entries + * into ctx->f_mdchain and we expect to find one. + * + * Advancing correctly through the buffer can be tricky if one + * tries to add up the size of an entry as you go (which is how + * the darwin code this is derived from did it). The easiest way + * to correctly advance the position is to get a whole dirent + * into another mdchain (entry_mdc) based on NextEntryOffset, + * and then scan the data from that mdchain. On the last entry, + * we don't know the entire length, so just scan directly from + * what remains of the multi-entry buffer instead of trying to + * figure out the length to copy into a separate mdchain. + */ +int +smbfs_decode_dirent(struct smbfs_fctx *ctx) +{ + struct mdchain entry_mdc; + struct mdchain *mdp = &ctx->f_mdchain; + size_t nmlen; + uint64_t llongint; + uint32_t nmsize, dattr; + uint32_t nextoff = 0; + int error; + + /* In case we error out... */ + ctx->f_nmlen = 0; + ctx->f_rkey = (uint32_t)-1; + bzero(&entry_mdc, sizeof (entry_mdc)); + + /* + * Setup mdp to point to an mbchain holding + * what should be a single directory entry. + */ + error = md_get_uint32le(mdp, &nextoff); + if (error != 0) + goto errout; + if (nextoff >= 4) { + /* + * More entries follow. Make a new mbchain + * holding just this one entry, then advance. + */ + mblk_t *m = NULL; + error = md_get_mbuf(mdp, nextoff - 4, &m); + if (error != 0) + goto errout; + md_initm(&entry_mdc, m); + mdp = &entry_mdc; + ctx->f_eofs += nextoff; + } else { + /* Scan directly from ctx->f_mdchain */ + ctx->f_eofs = ctx->f_left; + } + + /* + * Decode the fixed-size parts + */ + switch (ctx->f_infolevel) { + case FileFullDirectoryInformation: + case SMB_FIND_FULL_DIRECTORY_INFO: + md_get_uint32le(mdp, &ctx->f_rkey); /* resume key (idx) */ + md_get_uint64le(mdp, &llongint); /* creation time */ + smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime); + md_get_uint64le(mdp, &llongint); + smb_time_NT2local(llongint, &ctx->f_attr.fa_atime); + md_get_uint64le(mdp, &llongint); + smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime); + md_get_uint64le(mdp, &llongint); + smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime); + md_get_uint64le(mdp, &llongint); /* file size */ + ctx->f_attr.fa_size = llongint; + md_get_uint64le(mdp, &llongint); /* alloc. size */ + ctx->f_attr.fa_allocsz = llongint; + md_get_uint32le(mdp, &dattr); /* ext. file attributes */ + ctx->f_attr.fa_attr = dattr; + error = md_get_uint32le(mdp, &nmsize); /* name size (otw) */ + if (error) + goto errout; + md_get_uint32le(mdp, NULL); /* Ea size */ + break; + + case FileStreamInformation: + error = md_get_uint32le(mdp, &nmsize); /* name size (otw) */ + md_get_uint64le(mdp, &llongint); /* file size */ + ctx->f_attr.fa_size = llongint; + md_get_uint64le(mdp, &llongint); /* alloc. size */ + ctx->f_attr.fa_allocsz = llongint; + /* + * Stream names start with a ':' that we want to skip. + * This is the easiest place to take care of that. + * Always unicode here. + */ + if (nmsize >= 2) { + struct mdchain save_mdc; + uint16_t wch; + save_mdc = *mdp; + md_get_uint16le(mdp, &wch); + if (wch == ':') { + /* OK, we skipped the ':' */ + nmsize -= 2; + } else { + SMBVDEBUG("No leading : in stream?\n"); + /* restore position */ + *mdp = save_mdc; + } + } + break; + + default: + SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel); + error = EINVAL; + goto errout; + } + + /* + * Get the filename, and convert to utf-8 + * Allocated f_name in findopen + */ + nmlen = ctx->f_namesz; + error = smb_get_dstring(mdp, SSTOVC(ctx->f_ssp), + ctx->f_name, &nmlen, nmsize); + if (error != 0) + goto errout; + ctx->f_nmlen = (int)nmlen; + md_done(&entry_mdc); + return (0); + +errout: + /* + * Something bad has happened and we ran out of data + * before we could parse all f_ecnt entries expected. + * Give up on the current buffer. + */ + SMBVDEBUG("ran out of data\n"); + ctx->f_eofs = ctx->f_left; + md_done(&entry_mdc); + return (error); +} + +/* + * Decode FileAllInformation + * + * The data is a concatenation of: + * FileBasicInformation + * FileStandardInformation + * FileInternalInformation + * FileEaInformation + * FilePositionInformation + * FileModeInformation + * FileAlignmentInformation + * FileNameInformation + */ +/*ARGSUSED*/ +int +smbfs_decode_file_all_info(struct smb_share *ssp, + struct mdchain *mdp, struct smbfattr *fap) +{ + uint64_t llongint, lsize; + uint32_t dattr; + int error; + + /* + * This part is: FileBasicInformation + */ + + /* creation time */ + md_get_uint64le(mdp, &llongint); + smb_time_NT2local(llongint, &fap->fa_createtime); + + /* last access time */ + md_get_uint64le(mdp, &llongint); + smb_time_NT2local(llongint, &fap->fa_atime); + + /* last write time */ + md_get_uint64le(mdp, &llongint); + smb_time_NT2local(llongint, &fap->fa_mtime); + + /* last change time */ + md_get_uint64le(mdp, &llongint); + smb_time_NT2local(llongint, &fap->fa_ctime); + + /* attributes */ + md_get_uint32le(mdp, &dattr); + fap->fa_attr = dattr; + + /* reserved */ + md_get_uint32le(mdp, NULL); + + /* + * This part is: FileStandardInformation + */ + + /* allocation size */ + md_get_uint64le(mdp, &lsize); + fap->fa_allocsz = lsize; + + /* File size */ + error = md_get_uint64le(mdp, &lsize); + fap->fa_size = lsize; + + /* + * There's more after this but we don't need it: + * Remainder of FileStandardInformation + * NumLlinks, DeletOnClose, IsDir, reserved. + * Then: + * FileInternalInformation + * FileEaInformation + * FilePositionInformation + * FileModeInformation + * FileAlignmentInformation + * FileNameInformation + */ + + return (error); +} + +/* + * Decode FileFsAttributeInformation + * + * ULONG FileSystemAttributes; + * LONG MaximumComponentNameLength; + * ULONG FileSystemNameLength; + * WCHAR FileSystemName[1]; + */ +int +smbfs_decode_fs_attr_info(struct smb_share *ssp, + struct mdchain *mdp, struct smb_fs_attr_info *fsa) +{ + struct smb_vc *vcp = SSTOVC(ssp); + uint32_t nlen; + int error; + + md_get_uint32le(mdp, &fsa->fsa_aflags); + md_get_uint32le(mdp, &fsa->fsa_maxname); + error = md_get_uint32le(mdp, &nlen); /* fs name length */ + if (error) + goto out; + + /* + * Get the FS type name. + */ + bzero(fsa->fsa_tname, FSTYPSZ); + if (SMB_UNICODE_STRINGS(vcp)) { + uint16_t tmpbuf[FSTYPSZ]; + size_t tmplen, outlen; + + if (nlen > sizeof (tmpbuf)) + nlen = sizeof (tmpbuf); + error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM); + if (error != 0) + goto out; + tmplen = nlen / 2; /* UCS-2 chars */ + outlen = FSTYPSZ - 1; + error = uconv_u16tou8(tmpbuf, &tmplen, + (uchar_t *)fsa->fsa_tname, &outlen, + UCONV_IN_LITTLE_ENDIAN); + } else { + if (nlen > (FSTYPSZ - 1)) + nlen = FSTYPSZ - 1; + error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM); + } + +out: + return (error); +} diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h index fc7a4ffa26..f8d708b5a3 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h @@ -33,9 +33,10 @@ */ /* - * Copyright 2012 Nexenta Systems, Inc. All rights reserved. * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _FS_SMBFS_SMBFS_SUBR_H_ @@ -85,6 +86,7 @@ struct timespec; typedef enum { ft_LM1 = 1, ft_LM2, + ft_SMB2, ft_XA } smbfs_fctx_type_t; @@ -120,31 +122,33 @@ struct smbfs_fctx { /* * Internal variables */ + uint16_t f_infolevel; uint16_t f_limit; /* maximum number of entries */ - uint16_t f_attrmask; /* SMB_FA_ */ + uint32_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; + struct smb_fh *f_fhp; union { struct smb_rq *uf_rq; struct smb_t2rq *uf_t2; - } f_urq; + } f_urq; // XXX remove and use... + struct mdchain f_mdchain; 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 */ + uint32_t f_rkey; /* resume key */ }; typedef struct smbfs_fctx smbfs_fctx_t; @@ -152,73 +156,163 @@ typedef struct smbfs_fctx smbfs_fctx_t; #define f_t2 f_urq.uf_t2 /* - * smb level (smbfs_smb.c) + * Internal form of FileFsFullSizeInformation + * [MS-FSCC] 2.5.4 FileFsFullSizeInformation + * for the _statfs functions. + */ +struct smb_fs_size_info { + uint64_t total_units; + uint64_t caller_avail; + uint64_t actual_avail; + uint32_t sect_per_unit; + uint32_t bytes_per_sect; +}; + +/* + * smb common functions (smbfs_smbx.c) */ 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_getfattr(struct smbnode *np, smb_fh_t *fhp, + struct smbfattr *fap, struct smb_cred *scrp); +int smbfs_smb_getpattr(struct smbnode *np, struct smbfattr *fap, + struct smb_cred *scrp); int smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *, struct smb_cred *scrp); int smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp, struct smb_cred *scrp); - -int smbfs_smb_setdisp(struct smbnode *np, uint16_t fid, uint8_t newdisp, - struct smb_cred *scrp); -int smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize, +int smbfs_smb_setdisp(struct smb_share *ssp, smb_fh_t *fid, uint8_t newdisp, struct smb_cred *scrp); - -int smbfs_smb_getfattr(struct smbnode *np, struct smbfattr *fap, +int smbfs_smb_setfsize(struct smb_share *ssp, smb_fh_t *fid, uint64_t newsize, struct smb_cred *scrp); - -int smbfs_smb_setfattr(struct smbnode *np, int fid, +int smbfs_smb_setfattr(struct smb_share *ssp, smb_fh_t *fid, uint32_t attr, struct timespec *mtime, struct timespec *atime, struct smb_cred *scrp); +int smbfs_smb_flush(struct smb_share *ssp, smb_fh_t *fid, + struct smb_cred *scrp); + +int smbfs_smb_ntcreatex( + struct smbnode *np, const char *name, int nmlen, int xattr, + uint32_t req_acc, uint32_t efa, uint32_t share_acc, + uint32_t disp, uint32_t createopt, struct smb_cred *scrp, + smb_fh_t *fhpp, uint32_t *cr_act_p, struct smbfattr *fap); +int smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, + struct smb_cred *scrp, smb_fh_t **fidpp); +void smbfs_smb_tmpclose(struct smbnode *ssp, smb_fh_t *fid); int smbfs_smb_open(struct smbnode *np, const char *name, int nmlen, int xattr, uint32_t rights, struct smb_cred *scrp, - uint16_t *fidp, uint32_t *rightsp, struct smbfattr *fap); -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); + smb_fh_t **fidpp, struct smbfattr *fap); +void smbfs_smb_close(smb_fh_t *fid); int smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, - int xattr, uint32_t disp, struct smb_cred *scrp, uint16_t *fidp); -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, const char *tname, int tnmlen, - struct smb_cred *scrp, uint16_t fid, int replace); -int smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, - const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp); + int xattr, uint32_t disp, struct smb_cred *scrp, smb_fh_t **fidpp); +int smbfs_smb_rename(struct smbnode *sdnp, struct smbnode *src, + struct smbnode *tdnp, const char *tname, int tnmlen, + smb_fh_t *fid, 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 nmlen, 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); /* get/set security descriptor */ -int smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid, - struct smb_cred *scrp, uint32_t selector, - mblk_t **res, uint32_t *reslen); -int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid, - struct smb_cred *scrp, uint32_t selector, mblk_t **mp); +int smbfs_smb_getsec(struct smb_share *ssp, smb_fh_t *fid, + uint32_t selector, mblk_t **res, uint32_t *reslen, + struct smb_cred *scrp); +int smbfs_smb_setsec(struct smb_share *ssp, smb_fh_t *fid, + uint32_t selector, mblk_t **mp, struct smb_cred *scrp); + +/* + * SMB1 functions + */ +int smbfs_smb1_trans2_query(struct smbnode *np, uint16_t fid, + struct smbfattr *fap, struct smb_cred *scrp); +int smbfs_smb1_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *, + struct smb_cred *scrp); +int smbfs_smb1_statfs(struct smb_share *ssp, + struct smb_fs_size_info *info, struct smb_cred *scrp); +int smbfs_smb1_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize, + struct smb_cred *scrp); +int smbfs_smb1_setdisp(struct smb_share *ssp, uint16_t fid, uint8_t newdisp, + struct smb_cred *scrp); +int smbfs_smb1_setfattr(struct smb_share *ssp, uint16_t fid, + struct mbchain *, struct smb_cred *); +int smbfs_smb1_flush(struct smb_share *ssp, uint16_t fid, + struct smb_cred *scrp); +int smbfs_smb1_t2rename(struct smbnode *np, const char *tname, int tnmlen, + uint16_t fid, struct smb_cred *scrp); +int smbfs_smb1_oldrename(struct smbnode *src, struct smbnode *tdnp, + const char *tname, int tnmlen, struct smb_cred *scrp); + +int smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, + const char *wildcard, int wclen, uint32_t attr); +int smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit); +int smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx); +int smbfs_smb1_get_streaminfo(smbnode_t *np, struct mdchain *mdp, + struct smb_cred *scrp); + +int smbfs_smb1_getsec(struct smb_share *ssp, uint16_t fid, + uint32_t selector, mblk_t **res, uint32_t *reslen, + struct smb_cred *scrp); +int smbfs_smb1_setsec(struct smb_share *ssp, uint16_t fid, + uint32_t selector, mblk_t **mp, + struct smb_cred *scrp); + +/* + * SMB2 functions + */ + +int smbfs_smb2_getpattr(struct smbnode *np, struct smbfattr *fap, + struct smb_cred *scrp); +int smbfs_smb2_qfileinfo(struct smb_share *ssp, smb2fid_t *fid, + struct smbfattr *fap, struct smb_cred *scrp); +int smbfs_smb2_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *, + struct smb_cred *scrp); +int smbfs_smb2_statfs(struct smb_share *ssp, + struct smb_fs_size_info *info, struct smb_cred *scrp); +int smbfs_smb2_seteof(struct smb_share *ssp, smb2fid_t *fid, uint64_t newsize, + struct smb_cred *scrp); +int smbfs_smb2_setdisp(struct smb_share *ssp, smb2fid_t *fid, uint8_t newdisp, + struct smb_cred *scrp); +int smbfs_smb2_flush(struct smb_share *ssp, smb2fid_t *fid, + struct smb_cred *scrp); +int smbfs_smb2_setfattr(struct smb_share *ssp, smb2fid_t *fid, + struct mbchain *, struct smb_cred *); +int smbfs_smb2_rename(struct smbnode *np, struct smbnode *tdnp, + const char *tname, int tnlen, int overwrite, + smb2fid_t *fid, struct smb_cred *scrp); + +int smbfs_smb2_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp, + const char *wildcard, int wclen, uint32_t attr); +int smbfs_smb2_findnext(struct smbfs_fctx *ctx, uint16_t limit); +int smbfs_smb2_findclose(struct smbfs_fctx *ctx); +int smbfs_smb2_get_streaminfo(smbnode_t *np, struct mdchain *mdp, + struct smb_cred *scrp); + +int smbfs_smb2_getsec(struct smb_share *ssp, smb2fid_t *fid, + uint32_t selector, mblk_t **res, uint32_t *reslen, + struct smb_cred *scrp); +int smbfs_smb2_setsec(struct smb_share *ssp, smb2fid_t *fid, + uint32_t selector, mblk_t **mp, + struct smb_cred *scrp); + + +/* smbfs_subr.c */ + +int smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, + struct smbnode *dnp, const char *name, int nmlen, uint8_t sep); +int smbfs_decode_dirent(struct smbfs_fctx *ctx); +int smbfs_decode_file_all_info(struct smb_share *ssp, + struct mdchain *mdp, struct smbfattr *fap); +int smbfs_decode_fs_attr_info(struct smb_share *ssp, + struct mdchain *mdp, struct smb_fs_attr_info *fsa); /* * VFS-level init, fini stuff diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c index deb8d8f182..768664b610 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c @@ -27,7 +27,7 @@ */ /* * Copyright (c) 2017 by Delphix. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -433,7 +433,7 @@ start: np->r_vnode = vp; np->n_mount = mi; - np->n_fid = SMB_FID_UNUSED; + np->n_fid = NULL; np->n_uid = mi->smi_uid; np->n_gid = mi->smi_gid; /* Leave attributes "stale." */ diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c index 707238e5ad..3fca806155 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c @@ -34,7 +34,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -144,6 +144,7 @@ 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 *); +static int smbfsflush(smbnode_t *, struct smb_cred *); static void smbfs_rele_fid(smbnode_t *, struct smb_cred *); static uint32_t xvattr_to_dosattr(smbnode_t *, struct vattr *); @@ -201,14 +202,13 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) smbnode_t *np; vnode_t *vp; smbfattr_t fa; - u_int32_t rights, rightsrcvd; - u_int16_t fid, oldfid; - int oldgenid; + smb_fh_t *fid = NULL; + smb_fh_t *oldfid; + uint32_t rights; struct smb_cred scred; smbmntinfo_t *smi; smb_share_t *ssp; cred_t *oldcr; - int tmperror; int error = 0; vp = *vpp; @@ -280,14 +280,15 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) * check whether the rights are sufficient for FID reuse. */ if (np->n_fidrefs > 0 && - np->n_vcgenid == ssp->ss_vcgenid) { + (fid = np->n_fid) != NULL && + fid->fh_vcgenid == ssp->ss_vcgenid) { int upgrade = 0; if ((flag & FWRITE) && - !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA)) + !(fid->fh_rights & SA_RIGHT_FILE_WRITE_DATA)) upgrade = 1; if ((flag & FREAD) && - !(np->n_rights & SA_RIGHT_FILE_READ_DATA)) + !(fid->fh_rights & SA_RIGHT_FILE_READ_DATA)) upgrade = 1; if (!upgrade) { /* @@ -296,8 +297,9 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) np->n_fidrefs++; goto have_fid; } + fid = NULL; } - rights = np->n_fidrefs ? np->n_rights : 0; + rights = (fid != NULL) ? fid->fh_rights : 0; /* * we always ask for READ_CONTROL so we can always get the @@ -316,7 +318,7 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) error = smbfs_smb_open(np, NULL, 0, 0, /* name nmlen xattr */ rights, &scred, - &fid, &rightsrcvd, &fa); + &fid, &fa); if (error) goto out; smbfs_attrcache_fa(vp, &fa); @@ -325,24 +327,10 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) * We have a new FID and access rights. */ oldfid = np->n_fid; - oldgenid = np->n_vcgenid; np->n_fid = fid; - np->n_vcgenid = ssp->ss_vcgenid; - np->n_rights = rightsrcvd; np->n_fidrefs++; - if (np->n_fidrefs > 1 && - oldgenid == ssp->ss_vcgenid) { - /* - * We already had it open (presumably because - * it was open with insufficient rights.) - * Close old wire-open. - */ - tmperror = smbfs_smb_close(ssp, - oldfid, NULL, &scred); - if (tmperror) - SMBVDEBUG("error %d closing %s\n", - tmperror, np->n_rpath); - } + if (oldfid != NULL) + smb_fh_rele(oldfid); /* * This thread did the open. @@ -488,13 +476,11 @@ smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr, static void smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred) { - smb_share_t *ssp; cred_t *oldcr; struct smbfs_fctx *fctx; int error; - uint16_t ofid; + smb_fh_t *ofid; - ssp = np->n_mount->smi_share; error = 0; /* Make sure we serialize for n_dirseq use. */ @@ -523,13 +509,9 @@ smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred) ASSERT(np->n_fidrefs > 0); if (--np->n_fidrefs) return; - if ((ofid = np->n_fid) != SMB_FID_UNUSED) { - np->n_fid = SMB_FID_UNUSED; - /* After reconnect, n_fid is invalid */ - if (np->n_vcgenid == ssp->ss_vcgenid) { - error = smbfs_smb_close( - ssp, ofid, NULL, scred); - } + if ((ofid = np->n_fid) != NULL) { + np->n_fid = NULL; + smb_fh_rele(ofid); } break; @@ -567,14 +549,12 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, struct vattr va; smbnode_t *np; smbmntinfo_t *smi; - smb_share_t *ssp; offset_t endoff; ssize_t past_eof; int error; np = VTOSMB(vp); smi = VTOSMI(vp); - ssp = smi->smi_share; if (curproc->p_zone != smi->smi_zone_ref.zref_zone) return (EIO); @@ -636,12 +616,8 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, return (EINTR); smb_credinit(&scred, cr); - /* After reconnect, n_fid is invalid */ - if (np->n_vcgenid != ssp->ss_vcgenid) - error = ESTALE; - else - error = smb_rwuio(ssp, np->n_fid, UIO_READ, - uiop, &scred, smb_timo_read); + error = smb_rwuio(np->n_fid, UIO_READ, + uiop, &scred, smb_timo_read); smb_credrele(&scred); smbfs_rw_exit(&np->r_lkserlock); @@ -729,7 +705,6 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, struct vattr va; smbnode_t *np; smbmntinfo_t *smi; - smb_share_t *ssp; offset_t endoff, limit; ssize_t past_limit; int error, timo; @@ -741,7 +716,6 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, np = VTOSMB(vp); smi = VTOSMI(vp); - ssp = smi->smi_share; if (curproc->p_zone != smi->smi_zone_ref.zref_zone) return (EIO); @@ -852,12 +826,8 @@ smbfs_fwrite: return (EINTR); smb_credinit(&scred, cr); - /* After reconnect, n_fid is invalid */ - if (np->n_vcgenid != ssp->ss_vcgenid) - error = ESTALE; - else - error = smb_rwuio(ssp, np->n_fid, UIO_WRITE, - uiop, &scred, timo); + error = smb_rwuio(np->n_fid, UIO_WRITE, + uiop, &scred, timo); if (error == 0) { mutex_enter(&np->r_statelock); @@ -867,7 +837,7 @@ smbfs_fwrite: mutex_exit(&np->r_statelock); if (ioflag & (FSYNC | FDSYNC)) { /* Don't error the I/O if this fails. */ - (void) smbfs_smb_flush(np, &scred); + (void) smbfsflush(np, &scred); } } @@ -1274,7 +1244,6 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr) struct smb_cred scred; smbnode_t *np = VTOSMB(bp->b_vp); smbmntinfo_t *smi = np->n_mount; - smb_share_t *ssp = smi->smi_share; offset_t offset; offset_t endoff; size_t count; @@ -1330,12 +1299,8 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr) if (bp->b_flags & B_READ) { - /* After reconnect, n_fid is invalid */ - if (np->n_vcgenid != ssp->ss_vcgenid) - error = ESTALE; - else - error = smb_rwuio(ssp, np->n_fid, UIO_READ, - &auio, &scred, smb_timo_read); + error = smb_rwuio(np->n_fid, UIO_READ, + &auio, &scred, smb_timo_read); /* Like NFS, only set b_error here. */ bp->b_error = error; @@ -1349,12 +1314,8 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr) } } else { - /* After reconnect, n_fid is invalid */ - if (np->n_vcgenid != ssp->ss_vcgenid) - error = ESTALE; - else - error = smb_rwuio(ssp, np->n_fid, UIO_WRITE, - &auio, &scred, smb_timo_write); + error = smb_rwuio(np->n_fid, UIO_WRITE, + &auio, &scred, smb_timo_write); /* Like NFS, only set b_error here. */ bp->b_error = error; @@ -1363,7 +1324,7 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr) if (!error && auio.uio_resid != 0) error = EIO; if (!error && sync) { - (void) smbfs_smb_flush(np, &scred); + (void) smbfsflush(np, &scred); } } @@ -1618,12 +1579,12 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) { int error = 0; smbnode_t *np = VTOSMB(vp); + smbmntinfo_t *smi = np->n_mount; 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; + int modified = 0; + smb_fh_t *fid = NULL; uint32_t rights = 0; uint32_t dosattr = 0; @@ -1675,9 +1636,6 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) * 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, cr); /* @@ -1715,7 +1673,7 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) error, np->n_rpath); goto out; } - have_fid = 1; + ASSERT(fid != NULL); } /* @@ -1734,8 +1692,9 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) /* * Set the file size to vap->va_size. */ - ASSERT(have_fid); - error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred); + ASSERT(fid != NULL); + error = smbfs_smb_setfsize(smi->smi_share, fid, + vap->va_size, &scred); if (error) { SMBVDEBUG("setsize error %d file %s\n", error, np->n_rpath); @@ -1747,6 +1706,7 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) */ mutex_enter(&np->r_statelock); np->r_size = vap->va_size; + np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); mutex_exit(&np->r_statelock); modified = 1; } @@ -1763,8 +1723,8 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) /* * Always use the handle-based set attr call now. */ - ASSERT(have_fid); - error = smbfs_smb_setfattr(np, fid, + ASSERT(fid != NULL); + error = smbfs_smb_setfattr(smi->smi_share, fid, dosattr, mtime, atime, &scred); if (error) { SMBVDEBUG("set times error %d file %s\n", @@ -1775,15 +1735,10 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) } out: - if (have_fid) { - cerror = smbfs_smb_tmpclose(np, fid, &scred); - if (cerror) - SMBVDEBUG("error %d closing %s\n", - cerror, np->n_rpath); - } + if (fid != NULL) + smbfs_smb_tmpclose(np, fid); smb_credrele(&scred); - smbfs_rw_exit(&np->r_lkserlock); if (modified) { /* @@ -2052,7 +2007,7 @@ smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) return (EINTR); smb_credinit(&scred, cr); - error = smbfs_smb_flush(np, &scred); + error = smbfsflush(np, &scred); smb_credrele(&scred); smbfs_rw_exit(&np->r_lkserlock); @@ -2060,6 +2015,37 @@ smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) return (error); } +static int +smbfsflush(smbnode_t *np, struct smb_cred *scrp) +{ + struct smb_share *ssp = np->n_mount->smi_share; + smb_fh_t *fhp; + 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->n_fidrefs == 0) + return (0); /* not open */ + if ((fhp = np->n_fid) == NULL) + return (0); + + /* After reconnect, n_fid is invalid */ + if (fhp->fh_vcgenid != ssp->ss_vcgenid) + return (ESTALE); + + error = smbfs_smb_flush(ssp, fhp, scrp); + + if (!error) { + mutex_enter(&np->r_statelock); + np->n_flag &= ~NFLUSHWIRE; + mutex_exit(&np->r_statelock); + } + return (error); +} + /* * Last reference to vnode went away. */ @@ -2149,8 +2135,8 @@ smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) case VREG: if (np->n_fidrefs == 0) break; - SMBVDEBUG("open file: refs %d id 0x%x path %s\n", - np->n_fidrefs, np->n_fid, np->n_rpath); + SMBVDEBUG("open file: refs %d path %s\n", + np->n_fidrefs, np->n_rpath); /* Force last close. */ np->n_fidrefs = 1; smbfs_rele_fid(np, &scred); @@ -2228,6 +2214,14 @@ smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, smbfs_rw_exit(&dnp->r_rwlock); + /* + * If the caller passes an invalid name here, we'll have + * error == EINVAL but want to return ENOENT. This is + * common with things like "ls foo*" with no matches. + */ + if (error == EINVAL) + error = ENOENT; + return (error); } @@ -2255,14 +2249,7 @@ smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_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. @@ -2549,7 +2536,6 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, vsecattr_t *vsecp) { int error; - int cerror; vfs_t *vfsp; vnode_t *vp; smbnode_t *np; @@ -2561,7 +2547,7 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, const char *name = (const char *)nm; int nmlen = strlen(nm); uint32_t disp; - uint16_t fid; + smb_fh_t *fid = NULL; int xattr; vfsp = dvp->v_vfsp; @@ -2723,11 +2709,7 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, * 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) - SMBVDEBUG("error %d closing %s\\%s\n", - cerror, dnp->n_rpath, name); + smbfs_smb_close(fid); /* * In the open case, the name may differ a little @@ -2796,14 +2778,30 @@ smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, /* Lookup the file to remove. */ error = smbfslookup(dvp, nm, &vp, cr, 0, ct); - if (error == 0) { - /* - * Do the real remove work - */ - error = smbfsremove(dvp, vp, &scred, flags); - VN_RELE(vp); + if (error != 0) + goto out; + + /* Don't allow unlink of a directory. */ + if (vp->v_type == VDIR) { + error = EPERM; + goto out; } + /* + * Do the real remove work + */ + error = smbfsremove(dvp, vp, &scred, flags); + if (error != 0) + goto out; + +#ifdef SMBFS_VNEVENT + vnevent_remove(vp, dvp, nm, ct); +#endif + +out: + if (vp != NULL) + VN_RELE(vp); + smb_credrele(&scred); smbfs_rw_exit(&dnp->r_rwlock); @@ -2838,11 +2836,11 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred, { smbnode_t *dnp = VTOSMB(dvp); smbnode_t *np = VTOSMB(vp); + smbmntinfo_t *smi = np->n_mount; char *tmpname = NULL; int tnlen; int error; - unsigned short fid; - boolean_t have_fid = B_FALSE; + smb_fh_t *fid = NULL; boolean_t renamed = B_FALSE; /* @@ -2850,10 +2848,6 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred, */ ASSERT(dnp->r_rwlock.owner == curthread); - /* Never allow link/unlink directories on SMB. */ - if (vp->v_type == VDIR) - return (EPERM); - /* * We need to flush any dirty pages which happen to * be hanging around before removing the file. This @@ -2872,10 +2866,6 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred, } } - /* Shared lock for n_fid use in smbfs_smb_setdisp etc. */ - if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) - return (EINTR); - /* * Get a file handle with delete access. * Close this FID before return. @@ -2887,16 +2877,18 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred, error, np->n_rpath); goto out; } - have_fid = B_TRUE; + ASSERT(fid != NULL); /* * If we have the file open, try to rename it to a temporary name. * If we can't rename, continue on and try setting DoC anyway. + * Unnecessary for directories. */ - if ((vp->v_count > 1) && (np->n_fidrefs > 0)) { + if (vp->v_type != VDIR && vp->v_count > 1 && np->n_fidrefs > 0) { tmpname = kmem_alloc(MAXNAMELEN, KM_SLEEP); tnlen = smbfs_newname(tmpname, MAXNAMELEN); - error = smbfs_smb_t2rename(np, tmpname, tnlen, scred, fid, 0); + error = smbfs_smb_rename(dnp, np, dnp, tmpname, tnlen, + fid, scred); if (error != 0) { SMBVDEBUG("error %d renaming %s -> %s\n", error, np->n_rpath, tmpname); @@ -2910,7 +2902,7 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred, * Mark the file as delete-on-close. If we can't, * undo what we did and err out. */ - error = smbfs_smb_setdisp(np, fid, 1, scred); + error = smbfs_smb_setdisp(smi->smi_share, fid, 1, scred); if (error != 0) { SMBVDEBUG("error %d setting DoC on %s\n", error, np->n_rpath); @@ -2927,8 +2919,8 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred, oldname = np->n_rpath + (dnp->n_rplen + 1); oldnlen = np->n_rplen - (dnp->n_rplen + 1); - err2 = smbfs_smb_t2rename(np, oldname, oldnlen, - scred, fid, 0); + err2 = smbfs_smb_rename(dnp, np, dnp, oldname, oldnlen, + fid, scred); SMBVDEBUG("error %d un-renaming %s -> %s\n", err2, tmpname, np->n_rpath); } @@ -2936,19 +2928,14 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred, goto out; } /* Done! */ + smbfs_attrcache_remove(np); smbfs_attrcache_prune(np); -#ifdef SMBFS_VNEVENT - vnevent_remove(vp, dvp, nm, ct); -#endif - out: if (tmpname != NULL) kmem_free(tmpname, MAXNAMELEN); - - if (have_fid) - (void) smbfs_smb_tmpclose(np, fid, scred); - smbfs_rw_exit(&np->r_lkserlock); + if (fid != NULL) + smbfs_smb_tmpclose(np, fid); if (error == 0) { /* Keep lookup from finding this node anymore. */ @@ -3080,6 +3067,7 @@ smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp, char *nnm, vnode_t *nvp = NULL; int error; int nvp_locked = 0; + smb_fh_t *fid = NULL; /* Things our caller should have checked. */ ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone); @@ -3160,8 +3148,23 @@ smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp, char *nnm, nvp = NULL; } /* nvp */ + /* + * Get a file handle with delete access. + * Close this FID before return. + */ + error = smbfs_smb_tmpopen(onp, STD_RIGHT_DELETE_ACCESS, + scred, &fid); + if (error) { + SMBVDEBUG("error %d opening %s\n", + error, onp->n_rpath); + goto out; + } + smbfs_attrcache_remove(onp); - error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), scred); + error = smbfs_smb_rename(odnp, onp, ndnp, nnm, strlen(nnm), + fid, scred); + + smbfs_smb_tmpclose(onp, fid); /* * If the old name should no longer exist, @@ -3202,7 +3205,7 @@ smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, struct smbfattr fattr; const char *name = (const char *) nm; int nmlen = strlen(name); - int error, hiderr; + int error; if (curproc->p_zone != smi->smi_zone_ref.zref_zone) return (EPERM); @@ -3243,10 +3246,6 @@ smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, if (error) goto out; - if (name[0] == '.') - if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred))) - SMBVDEBUG("hide failure %d\n", hiderr); - /* Success! */ *vpp = vp; error = 0; @@ -3270,12 +3269,12 @@ static int smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr, caller_context_t *ct, int flags) { + struct smb_cred scred; 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_ref.zref_zone) @@ -3284,17 +3283,16 @@ smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr, 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, cr); - /* - * Require w/x access in the containing directory. - * Server handles all other access checks. + * Verify access to the dirctory. */ - error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct); + error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct); if (error) - goto out; + return (error); + + if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) + return (EINTR); + smb_credinit(&scred, cr); /* * First lookup the entry to be removed. @@ -3327,23 +3325,17 @@ smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr, goto out; } - smbfs_attrcache_remove(np); - error = smbfs_smb_rmdir(np, &scred); - /* - * Similar to smbfs_remove + * Do the real rmdir work */ - switch (error) { - case 0: - case ENOENT: - case ENOTDIR: - smbfs_attrcache_prune(np); - break; - } - + error = smbfsremove(dvp, vp, &scred, flags); if (error) goto out; +#ifdef SMBFS_VNEVENT + vnevent_rmdir(vp, dvp, nm, ct); +#endif + mutex_enter(&np->r_statelock); dnp->n_flag |= NMODIFIED; mutex_exit(&np->r_statelock); diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c index 5a36306283..323b8c8d10 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -45,7 +45,9 @@ #include #include + #include +#include #include #include #include @@ -291,32 +293,20 @@ smbfs_xa_getfattr(struct smbnode *xnp, struct smbfattr *fap, } /* - * Fetch the entire attribute list here in findopen. - * Will parse the results in findnext. + * Actually go OtW to get the list of "streams". * * This is called on the XATTR directory, so we * have to get the (real) parent object first. */ -/* ARGSUSED */ -int -smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp, - const char *wildcard, int wclen) +static int +smbfs_xa_get_streaminfo(struct smbfs_fctx *ctx) { vnode_t *pvp; /* parent */ smbnode_t *pnp; - struct smb_t2rq *t2p; - struct smb_vc *vcp = SSTOVC(ctx->f_ssp); - struct mbchain *mbp; + smbnode_t *dnp = ctx->f_dnp; + struct mdchain *mdp; int error; - ASSERT(dnp->n_flag & N_XATTR); - - ctx->f_type = ft_XA; - ctx->f_namesz = SMB_MAXFNAMELEN + 1; - if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) - ctx->f_namesz *= 2; - ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP); - error = smbfs_xa_parent(SMBTOV(dnp), &pvp); if (error) return (error); @@ -324,40 +314,31 @@ smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp, /* Note: pvp has a VN_HOLD */ pnp = VTOSMB(pvp); - if (ctx->f_t2) { - smb_t2_done(ctx->f_t2); - ctx->f_t2 = NULL; - } + /* + * Get stream info into f_mdchain + */ + mdp = &ctx->f_mdchain; + md_done(mdp); - error = smb_t2_alloc(SSTOCP(ctx->f_ssp), - SMB_TRANS2_QUERY_PATH_INFORMATION, - ctx->f_scred, &t2p); + if (SSTOVC(ctx->f_ssp)->vc_flags & SMBV_SMB2) { + error = smbfs_smb2_get_streaminfo(pnp, mdp, ctx->f_scred); + } else { + error = smbfs_smb1_get_streaminfo(pnp, mdp, ctx->f_scred); + } if (error) goto out; - ctx->f_t2 = t2p; - mbp = &t2p->t2_tparam; - (void) mb_init(mbp); - (void) mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO); - (void) mb_put_uint32le(mbp, 0); - error = smbfs_fullpath(mbp, vcp, pnp, NULL, NULL, 0); - if (error) - goto out; - t2p->t2_maxpcount = 2; - t2p->t2_maxdcount = INT16_MAX; - error = smb_t2_request(t2p); - if (error) { - if (t2p->t2_sr_error == NT_STATUS_INVALID_PARAMETER) - error = ENOTSUP; - } /* - * No returned parameters to parse. - * Returned data are in t2_rdata, - * which we'll parse in _findnext. - * However, save the wildcard. + * Have stream info in ctx->f_mdchain + * Initialize buffer length, position. */ - ctx->f_wildcard = wildcard; - ctx->f_wclen = wclen; + ctx->f_left = m_fixhdr(mdp->md_top); + ctx->f_eofs = 0; + + /* + * After one successful call, we're at EOF. + */ + ctx->f_flags |= SMBFS_RDD_EOF; out: VN_RELE(pvp); @@ -365,83 +346,62 @@ out: } /* - * Get the next name in an XATTR directory into f_name + * Get a buffer of directory entries (if we don't already have + * some remaining in the current buffer) then decode one. */ -/* ARGSUSED */ int -smbfs_xa_findnext(struct smbfs_fctx *ctx, uint16_t limit) +smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp, + const char *wildcard, int wclen) { - struct mdchain *mdp; - struct smb_t2rq *t2p; - uint32_t size, next; - uint64_t llongint; - int error, skip, used, nmlen; - t2p = ctx->f_t2; - mdp = &t2p->t2_rdata; + ASSERT(dnp->n_flag & N_XATTR); - if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { - ASSERT(ctx->f_wildcard); - SMBVDEBUG("wildcard: %s\n", ctx->f_wildcard); - } + ctx->f_type = ft_XA; + ctx->f_namesz = SMB_MAXFNAMELEN + 1; + ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP); + ctx->f_infolevel = FileStreamInformation; + ctx->f_wildcard = wildcard; + ctx->f_wclen = wclen; -again: - if (ctx->f_flags & SMBFS_RDD_EOF) - return (ENOENT); - - /* Parse FILE_STREAM_INFORMATION */ - if ((error = md_get_uint32le(mdp, &next)) != 0) /* offset to */ - return (ENOENT); - if ((error = md_get_uint32le(mdp, &size)) != 0) /* name len */ - return (ENOENT); - (void) md_get_uint64le(mdp, &llongint); /* file size */ - ctx->f_attr.fa_size = llongint; - (void) md_get_uint64le(mdp, NULL); /* alloc. size */ - used = 4 + 4 + 8 + 8; /* how much we consumed */ + return (0); +} - /* - * Copy the string, but skip the first char (":") - * Watch out for zero-length strings here. - */ - if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { - if (size >= 2) { - size -= 2; used += 2; - (void) md_get_uint16le(mdp, NULL); - } - nmlen = min(size, SMB_MAXFNAMELEN * 2); - } else { - if (size >= 1) { - size -= 1; used += 1; - (void) md_get_uint8(mdp, NULL); - } - nmlen = min(size, SMB_MAXFNAMELEN); - } - ASSERT(nmlen < ctx->f_namesz); - ctx->f_nmlen = nmlen; - error = md_get_mem(mdp, ctx->f_name, nmlen, MB_MSYSTEM); - if (error) - return (error); - used += nmlen; +/* + * Get the next name in an XATTR directory + */ +/* ARGSUSED */ +int +smbfs_xa_findnext(struct smbfs_fctx *ctx, uint16_t limit) +{ + int error; /* - * Convert UCS-2 to UTF-8 + * If we've scanned to the end of the current buffer + * try to read anohther buffer of dir entries. + * Treat anything less than 8 bytes as an "empty" + * buffer to ensure we can read something. + * (There may be up to 8 bytes of padding.) */ - smbfs_fname_tolocal(ctx); - if (nmlen) - SMBVDEBUG("name: %s\n", ctx->f_name); - else - SMBVDEBUG("null name!\n"); +again: + if ((ctx->f_eofs + 8) > ctx->f_left) { + /* Scanned the whole buffer. */ + if (ctx->f_flags & SMBFS_RDD_EOF) + return (ENOENT); + ctx->f_limit = limit; + error = smbfs_xa_get_streaminfo(ctx); + if (error) + return (error); + ctx->f_otws++; + } /* - * Skip padding until next offset + * Decode one entry, advance f_eofs */ - if (next > used) { - skip = next - used; - (void) md_get_mem(mdp, NULL, skip, MB_MSYSTEM); - } - if (next == 0) - ctx->f_flags |= SMBFS_RDD_EOF; + error = smbfs_decode_dirent(ctx); + if (error) + return (error); + SMBVDEBUG("name: %s\n", ctx->f_name); /* * Chop off the trailing ":$DATA" @@ -464,8 +424,10 @@ again: goto again; /* - * If this is a lookup of a specific name, - * skip past any non-matching names. + * When called by lookup, we'll have the "single" flag, + * and a name with no wildcards. We need to filter here + * because smbfs_xa_get_streaminfo() gets ALL the names + * (not just those matching our pattern). */ if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { if (ctx->f_wclen != ctx->f_nmlen) @@ -490,8 +452,6 @@ smbfs_xa_findclose(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); return (0); } diff --git a/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c b/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c index f4a9f9a948..4ed5cba79c 100644 --- a/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c +++ b/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c @@ -22,7 +22,7 @@ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -31,7 +31,7 @@ */ #include -#include +#include struct smb2_ioctbl_ent { uint32_t te_code; diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c index ffe230f888..6176a8b002 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c +++ b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include @@ -30,7 +30,7 @@ #include #include #include -#include +#include /* * count of bytes in server response packet @@ -943,7 +943,7 @@ smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa) data_off, /* Data offset from header start */ data_disp, /* Data displacement */ n_setup, /* suwcnt */ - &xa->rep_setup_mb, /* setup[] */ + &xa->rep_setup_mb, /* setup[] */ tot_packet_bytes, /* Total data bytes */ param_pad, &xa->rep_param_mb, diff --git a/usr/src/uts/common/fs/smbsrv/smb_dfs.c b/usr/src/uts/common/fs/smbsrv/smb_dfs.c index 495965859b..03c565e9e4 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_dfs.c +++ b/usr/src/uts/common/fs/smbsrv/smb_dfs.c @@ -22,13 +22,13 @@ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include #include #include -#include +#include /* * Get Referral response header flags diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c index c0ab285bd5..f355e314bc 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c +++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c @@ -20,11 +20,11 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include -#include +#include static uint32_t smb_nt_trans_ioctl_noop(smb_request_t *, smb_xa_t *); diff --git a/usr/src/uts/common/fs/smbsrv/smb_opipe.c b/usr/src/uts/common/fs/smbsrv/smb_opipe.c index 273a2f7297..c08cba0ac6 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_opipe.c +++ b/usr/src/uts/common/fs/smbsrv/smb_opipe.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -35,7 +35,7 @@ #include #include #include -#include +#include static uint32_t smb_opipe_transceive(smb_request_t *, smb_fsctl_t *); diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c index df874ffe1d..918bf78727 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c +++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c @@ -22,11 +22,11 @@ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include -#include +#include /* * [MS-CIFS] diff --git a/usr/src/uts/common/fs/smbsrv/smb_vss.c b/usr/src/uts/common/fs/smbsrv/smb_vss.c index 211bc467a8..72657ae3be 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_vss.c +++ b/usr/src/uts/common/fs/smbsrv/smb_vss.c @@ -41,7 +41,7 @@ #include #include -#include +#include #include /* Size of the token on the wire due to encoding */ diff --git a/usr/src/uts/common/netsmb/mchain.h b/usr/src/uts/common/netsmb/mchain.h index 4f236d6b52..156671999b 100644 --- a/usr/src/uts/common/netsmb/mchain.h +++ b/usr/src/uts/common/netsmb/mchain.h @@ -36,7 +36,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _MCHAIN_H_ @@ -105,6 +105,7 @@ */ #include /* mblk_t */ +#include /* MBLKL */ typedef mblk_t mbuf_t; /* BEGIN CSTYLED */ @@ -226,6 +227,7 @@ void mb_initm(mbchain_t *, mbuf_t *); void mb_done(mbchain_t *); void *mb_reserve(mbchain_t *, int size); +int mb_put_align8(mbchain_t *mbp); int mb_put_padbyte(mbchain_t *mbp); int mb_put_uint8(mbchain_t *, uint8_t); int mb_put_uint16be(mbchain_t *, uint16_t); @@ -236,6 +238,7 @@ int mb_put_uint64be(mbchain_t *, uint64_t); int mb_put_uint64le(mbchain_t *, uint64_t); int mb_put_mem(mbchain_t *, const void *, int, int); int mb_put_mbuf(mbchain_t *, mbuf_t *); +int mb_put_mbchain(mbchain_t *, mbchain_t *); int md_init(mdchain_t *mdp); void md_initm(mdchain_t *mbp, mbuf_t *m); @@ -250,5 +253,7 @@ int md_get_uint64be(mdchain_t *, uint64_t *); int md_get_uint64le(mdchain_t *, uint64_t *); int md_get_mem(mdchain_t *, void *, int, int); int md_get_mbuf(mdchain_t *, int, mbuf_t **); +int md_seek(mdchain_t *, uint32_t); +uint32_t md_tell(mdchain_t *); #endif /* !_MCHAIN_H_ */ diff --git a/usr/src/uts/common/netsmb/smb.h b/usr/src/uts/common/netsmb/smb.h index e3bfc5144c..b57be5bbfe 100644 --- a/usr/src/uts/common/netsmb/smb.h +++ b/usr/src/uts/common/netsmb/smb.h @@ -40,6 +40,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _NETSMB_SMB_H_ @@ -66,8 +67,8 @@ enum smb_dialects { 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 */ + SMB_DIALECT_NTLM0_12, /* NT LM 0.12, etc. */ + SMB_DIALECT_SMB2_FF /* SMB1 negotiate to SMB2 */ }; /* @@ -82,11 +83,18 @@ enum smb_dialects { /* * SMB header */ + #define SMB_SIGNATURE "\xFFSMB" #define SMB_SIGLEN 4 #define SMB_HDRCMD(p) (*((uchar_t *)(p) + SMB_SIGLEN)) #define SMB_HDRMID(p) (*(ushort_t *)((uchar_t *)(p) + 30)) +#define SMB_HDR_OFF_MID 30 #define SMB_HDRLEN 32 + +#define SMB_HDR_V1 0xFF +#define SMB_HDR_V2 0xFE +#define SMB_HDR_V3E 0xFD /* SMB3 encrypted */ + /* * bits in the smb_flags field */ @@ -151,6 +159,25 @@ enum smb_dialects { #define SMB_CAP_COMPRESSED_DATA 0x40000000 #define SMB_CAP_EXT_SECURITY 0x80000000 +/* SMB_COM_TREE_CONNECT_ANDX flags. See [MS-SMB] for a complete description. */ +#define TREE_CONNECT_ANDX_DISCONNECT_TID 0x0001 +#define TREE_CONNECT_ANDX_EXTENDED_SIGNATURES 0x0004 +#define TREE_CONNECT_ANDX_EXTENDED_RESPONSE 0x0008 + +/* + * SMB_COM_TREE_CONNECT_ANDX optional support flags. See [MS-SMB] for a + * complete description. + */ +#define SMB_SUPPORT_SEARCH_BITS 0x0001 /* supports SearchAttributes */ +#define SMB_SHARE_IS_IN_DFS 0x0002 /* share is managed by DFS */ +#define SMB_CSC_MASK 0x000C /* Offline-caching bits. */ +#define SMB_UNIQUE_FILE_NAME 0x0010 /* Long file names only */ +#define SMB_EXTENDED_SIGNATURES 0x0020 /* Signing key protection. */ +/* See [MS-SMB] for a complete description of SMB_CSC_MASK bits. */ +#define SMB_CSC_CACHE_MANUAL_REINT 0x0000 +#define SMB_CSC_CACHE_AUTO_REINT 0x0004 +#define SMB_CSC_CACHE_VDO 0x0008 + /* * File attributes */ @@ -372,6 +399,7 @@ enum smb_dialects { #define SMB_QFS_DEVICE_INFO 0x104 #define SMB_QFS_ATTRIBUTE_INFO 0x105 #define SMB_QFS_UNIX_INFO 0x200 +#define SMB_QFS_POSIX_WHOAMI 0x202 #define SMB_QFS_MAC_FS_INFO 0x301 #define SMB_QFS_VOLUME_INFORMATION 1001 #define SMB_QFS_SIZE_INFORMATION 1003 @@ -381,6 +409,11 @@ enum smb_dialects { #define SMB_QFS_FULL_SIZE_INFORMATION 1007 #define SMB_QFS_OBJECTID_INFORMATION 1008 +/* + * NT Notify Change Compeletion Filter + * NT Notify Actions + * (We don't use these.) + */ /* * SMB_QFS_ATTRIBUTE_INFO bits. @@ -403,6 +436,7 @@ enum smb_dialects { #define FILE_SUPPORTS_OBJECT_IDS 0x00010000 #define FILE_SUPPORTS_ENCRYPTION 0x00020000 #define FILE_NAMED_STREAMS 0x00040000 +#define FILE_READ_ONLY_VOLUME 0x00080000 /* * SMB_TRANS2_QUERY_PATH levels @@ -424,9 +458,12 @@ enum smb_dialects { #define SMB_QFILEINFO_COMPRESSION_INFO 0x10b #define SMB_QFILEINFO_UNIX_BASIC 0x200 #define SMB_QFILEINFO_UNIX_LINK 0x201 +#define SMB_QFILEINFO_POSIX_ACL 0x204 +#define SMB_QFILEINFO_UNIX_INFO2 0x20B #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_MAC_SPOTLIGHT 0x310 #define SMB_QFILEINFO_BASIC_INFORMATION 1004 #define SMB_QFILEINFO_STANDARD_INFORMATION 1005 #define SMB_QFILEINFO_INTERNAL_INFORMATION 1006 @@ -454,6 +491,9 @@ enum smb_dialects { #define SMB_FIND_NAME_INFO 0x103 #define SMB_FIND_BOTH_DIRECTORY_INFO 0x104 #define SMB_FIND_UNIX_INFO 0x200 +/* Transact 2 Find First levels */ +#define SMB_FIND_FILE_UNIX 0x202 +#define SMB_FIND_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */ /* * Selectors for NT_TRANSACT_QUERY_SECURITY_DESC and @@ -707,6 +747,9 @@ typedef struct ntsid ntsid_t; #define SMB_SFILEINFO_UNIX_BASIC 0x200 #define SMB_SFILEINFO_UNIX_LINK 0x201 #define SMB_SFILEINFO_UNIX_HLINK 0x203 +#define SMB_SFILEINFO_POSIX_ACL 0x204 +#define SMB_SFILEINFO_POSIX_UNLINK 0x20A +#define SMB_SFILEINFO_UNIX_INFO2 0x20B #define SMB_SFILEINFO_DIRECTORY_INFORMATION 1001 #define SMB_SFILEINFO_FULL_DIRECTORY_INFORMATION 1002 #define SMB_SFILEINFO_BOTH_DIRECTORY_INFORMATION 1003 @@ -816,4 +859,19 @@ typedef struct ntlmv2_namehdr ntlmv2_namehdr_t; #define STYPE_TEMPORARY 0x40000000 #define STYPE_HIDDEN 0x80000000 +/* + * Characters that are not allowed in an SMB file name component. + * From MSDN: Naming Files, Paths, ... + * < (less than) + * > (greater than) + * : (colon) + * " (double quote) + * / (forward slash) + * \ (backslash) + * | (vertical bar or pipe) + * ? (question mark) + * * (asterisk) + */ +#define SMB_FILENAME_INVALID_CHARS "<>:\"/\\|?*" + #endif /* _NETSMB_SMB_H_ */ diff --git a/usr/src/uts/common/netsmb/smb2.h b/usr/src/uts/common/netsmb/smb2.h new file mode 100644 index 0000000000..abae5e8063 --- /dev/null +++ b/usr/src/uts/common/netsmb/smb2.h @@ -0,0 +1,465 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + +#ifndef _NETSMB_SMB2_H +#define _NETSMB_SMB2_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SMB2_PROTOCOL_ID { 0xFE, 'S', 'M', 'B' } +#define SMB2_HDR_SIZE 64 +#define SMB2_HDRLEN SMB2_HDR_SIZE + +/* + * SMB2 header command codes. + * These are uint16_t on the wire. + */ +typedef enum { + SMB2_NEGOTIATE = 0, + SMB2_SESSION_SETUP, + SMB2_LOGOFF, + SMB2_TREE_CONNECT, + SMB2_TREE_DISCONNECT, + SMB2_CREATE, + SMB2_CLOSE, + SMB2_FLUSH, + SMB2_READ, + SMB2_WRITE, + SMB2_LOCK, + SMB2_IOCTL, + SMB2_CANCEL, + SMB2_ECHO, + SMB2_QUERY_DIRECTORY, + SMB2_CHANGE_NOTIFY, + SMB2_QUERY_INFO, + SMB2_SET_INFO, + SMB2_OPLOCK_BREAK, + /* + * The above (oplock break) is the last real SMB2 op-code. + * We use one more slot to represent invalid commands, and + * the final enum value is used for array sizes. Keep last! + */ + SMB2_INVALID_CMD, + SMB2__NCMDS +} SMB2_cmd_code; + +/* + * SMB2 header flags. + */ + +/* + * SERVER_TO_REDIR + * When set, indicates the message is a response rather than + * a request. This MUST be set on responses sent from the + * server to the client, and MUST NOT be set on requests + * sent from the client to the server. + */ +#define SMB2_FLAGS_SERVER_TO_REDIR 0x00000001 + +/* + * ASYNC_COMMAND + * When set, indicates that this is an ASYNC SMB2 header. + * Always set for headers of the form described in this + * section. + */ +#define SMB2_FLAGS_ASYNC_COMMAND 0x00000002 + +/* + * RELATED_OPERATIONS + * When set in an SMB2 request, indicates that this request + * is a related operation in a compounded request chain. + * [MS-SMB2 sec. 3.2.4.1.4] + * + * When set in an SMB2 compound response, indicates that + * the request corresponding to this response was part of a + * related operation in a compounded request chain. + * [MS-SMB2 sec. 3.3.5.2.7.2] + */ +#define SMB2_FLAGS_RELATED_OPERATIONS 0x00000004 + +/* + * SIGNED + * When set, indicates that this packet has been signed. + * [MS-SMB2 3.1.5.1] + */ +#define SMB2_FLAGS_SIGNED 0x00000008 + +/* + * [MS-SMB2] 3.2.5.3.1 The SessionKey MUST be set to the + * first 16 bytes of the cryptographic key from GSSAPI. + * (Padded with zeros if the GSSAPI key is shorter.) + */ +#define SMB2_SESSION_KEY_LEN 16 + +/* + * DFS_OPERATIONS + * When set, indicates that this command is a Distributed + * File System (DFS) operation. [MS-SMB2 3.3.5.9] + */ +#define SMB2_FLAGS_DFS_OPERATIONS 0x10000000 + +/* + * REPLAY_OPERATION + * This flag is only valid for the SMB 3.0 dialect. When set, + * it indicates that this command is a replay operation. + * The client MUST ignore this bit on receipt. + */ +#define SMB2_FLAGS_REPLAY_OPERATION 0x20000000 + +/* + * SMB2 Netgotiate [MS-SMB2 2.2.3] + */ + +#define SMB2_NEGOTIATE_SIGNING_ENABLED 0x01 +#define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x02 + +#define SMB2_CAP_DFS 0x00000001 + +/* Added with SMB2.1 */ +#define SMB2_CAP_DFS 0x00000001 +#define SMB2_CAP_LEASING 0x00000002 +/* + * LARGE_MTU: + * When set, indicates that the client supports multi-credit operations. + */ +#define SMB2_CAP_LARGE_MTU 0x00000004 + +/* Added with SMB3.0 */ +#define SMB2_CAP_MULTI_CHANNEL 0x00000008 +#define SMB2_CAP_PERSISTENT_HANDLES 0x00000010 +#define SMB2_CAP_DIRECTORY_LEASING 0x00000020 +#define SMB2_CAP_ENCRYPTION 0x00000040 + +/* SMB2 session flags */ +#define SMB2_SESSION_FLAG_IS_GUEST 0x0001 +#define SMB2_SESSION_FLAG_IS_NULL 0x0002 +#define SMB2_SESSION_FLAG_ENCRYPT_DATA 0x0004 + +/* + * SMB2 Tree connect, disconnect + */ + +/* SMB2 sharetype flags */ +#define SMB2_SHARE_TYPE_DISK 0x1 +#define SMB2_SHARE_TYPE_PIPE 0x2 +#define SMB2_SHARE_TYPE_PRINT 0x3 + +/* SMB2 share flags */ +#define SMB2_SHAREFLAG_MANUAL_CACHING 0x00000000 +#define SMB2_SHAREFLAG_AUTO_CACHING 0x00000010 +#define SMB2_SHAREFLAG_VDO_CACHING 0x00000020 +#define SMB2_SHAREFLAG_NO_CACHING 0x00000030 +#define SMB2_SHAREFLAG_DFS 0x00000001 +#define SMB2_SHAREFLAG_DFS_ROOT 0x00000002 +#define SMB2_SHAREFLAG_RESTRICT_EXCLUSIVE_OPENS 0x00000100 +#define SMB2_SHAREFLAG_FORCE_SHARED_DELETE 0x00000200 +#define SMB2_SHAREFLAG_ALLOW_NAMESPACE_CACHING 0x00000400 +#define SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM 0x00000800 +#define SMB2_SHAREFLAG_FORCE_LEVELII_OPLOCK 0x00001000 +/* SMB 3.0 */ +#define SMB2_SHAREFLAG_ENABLE_HASH_V1 0x00002000 +#define SMB2_SHAREFLAG_ENABLE_HASH_V2 0x00004000 +#define SMB2_SHAREFLAG_ENCRYPT_DATA 0x00008000 + +/* SMB2 share capabilities */ +#define SMB2_SHARE_CAP_DFS 0x00000008 +/* SMB 3.0 */ +#define SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY 0x00000010 +#define SMB2_SHARE_CAP_SCALEOUT 0x00000020 +#define SMB2_SHARE_CAP_CLUSTER 0x00000040 + +/* + * SMB2 Create (open) + */ + +/* SMB2 requested oplock levels */ +#define SMB2_OPLOCK_LEVEL_NONE 0x00 +#define SMB2_OPLOCK_LEVEL_II 0x01 +#define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08 +#define SMB2_OPLOCK_LEVEL_BATCH 0x09 +#define SMB2_OPLOCK_LEVEL_LEASE 0xFF + +/* SMB2 impersonation levels */ +#define SMB2_IMPERSONATION_ANONYMOUS 0x00 +#define SMB2_IMPERSONATION_IDENTIFICATION 0x01 +#define SMB2_IMPERSONATION_IMPERSONATION 0x02 +#define SMB2_IMPERSONATION_DELEGATE 0x03 + +/* + * Note: ShareAccess, CreateDispositon, CreateOptions, + * all use the same definitions as SMB1 (from MS-FSA). + * Ditto FileAccess flags (as with ACLs) + */ + +/* SMB2 Create Context tags */ + +#define SMB2_CREATE_EA_BUFFER 0x45787441 /* ("ExtA") */ +/* + * The data contains the extended attributes + * that MUST be stored on the created file. + * This value MUST NOT be set for named + * pipes and print files. + */ + +#define SMB2_CREATE_SD_BUFFER 0x53656344 /* ("SecD") */ +/* + * The data contains a security descriptor that + * MUST be stored on the created file. + * This value MUST NOT be set for named + * pipes and print files. + */ + +#define SMB2_CREATE_DURABLE_HANDLE_REQUEST 0x44486e51 /* ("DHnQ") */ +/* The client is requesting the open to be durable */ + +#define SMB2_CREATE_DURABLE_HANDLE_RECONNECT 0x44486e43 /* ("DHnC") */ +/* + * The client is requesting to reconnect to a + * durable open after being disconnected + */ + +#define SMB2_CREATE_ALLOCATION_SIZE 0x416c5369 /* ("AISi") */ +/* + * The data contains the required allocation + * size of the newly created file. + */ + +#define SMB2_CREATE_QUERY_MAXIMAL_ACCESS 0x4d784163 /* ("MxAc") */ +/* + * The client is requesting that the server + * return maximal access information. + */ + +#define SMB2_CREATE_TIMEWARP_TOKEN 0x54577270 /* ("TWrp") */ +/* + * The client is requesting that the server + * open an earlier version of the file identified + * by the provided time stamp. + */ + +#define SMB2_CREATE_QUERY_ON_DISK_ID 0x51466964 /* ("QFid") */ +/* + * The client is requesting that the server return a 32-byte + * opaque BLOB that uniquely identifies the file being opened + * on disk. No data is passed to the server by the client. + */ + +#define SMB2_CREATE_REQUEST_LEASE 0x52714c73 /* ("RqLs") */ +/* + * The client is requesting that the server return a lease. + * This value is only supported for the SMB 2.1 and 3.0 dialects. + */ + +/* SMB2 create request lease */ +#define SMB2_LEASE_NONE 0x00 +#define SMB2_LEASE_READ_CACHING 0x01 +#define SMB2_LEASE_HANDLE_CACHING 0x02 +#define SMB2_LEASE_WRITE_CACHING 0x04 + +/* SMB2 lease break notification flags */ +#define SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED 0x01 + +/* + * SMB2 Close + */ +#define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB 0x0001 + +/* + * SMB2 Write + */ +#define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001 + +/* + * SMB2 Lock Request + */ + +/* SMB2 lock flags */ + +/* + * SMB2_LOCKFLAG_SHARED_LOCK + * The range MUST be locked shared, allowing other opens + * to read from or take a shared lock on the range. All opens + * MUST NOT be allowed to write within the range. Other + * locks can be requested and taken on this range. + */ +#define SMB2_LOCKFLAG_SHARED_LOCK 0x00000001 + +/* + * SMB2_LOCKFLAG_EXCLUSIVE_LOCK + * The range MUST be locked exclusive, not allowing other + * opens to read, write, or lock within the range. + */ +#define SMB2_LOCKFLAG_EXCLUSIVE_LOCK 0x00000002 + +/* + * SMB2_LOCKFLAG_UNLOCK + * The range MUST be unlocked from a previous lock taken + * on this range. The unlock range MUST be identical to the + * lock range. Sub-ranges cannot be unlocked. + */ +#define SMB2_LOCKFLAG_UNLOCK 0x00000004 + +/* + * SMB2_LOCKFLAG_FAIL_IMMEDIATELY + * The lock operation MUST fail immediately if it conflicts + * with an existing lock, instead of waiting for the range to + * become available. This can be OR'ed with either of + * shared_lock, exclusive_lock (nothing else). + */ +#define SMB2_LOCKFLAG_FAIL_IMMEDIATELY 0x00000010 + +/* + * SMB2 Ioctl Request + */ +#define SMB2_IOCTL_IS_FSCTL 0x00000001 + + +/* + * SMB2 Query Directory + */ + +/* + * SMB2 query directory info levels + * Same as SMB1 (see ntifs.h) + */ + +/* + * SMB2 Query Directory Flags + * (our own names for these - spec. used poor names) + */ +#define SMB2_QDIR_FLAG_RESTART 0x01 /* SMB2_RESTART_SCANS */ +#define SMB2_QDIR_FLAG_SINGLE 0x02 /* SMB2_RETURN_SINGLE_ENTRY */ +#define SMB2_QDIR_FLAG_INDEX 0x04 /* SMB2_INDEX_SPECIFIED */ +#define SMB2_QDIR_FLAG_REOPEN 0x10 /* SMB2_REOPEN */ + +/* + * SMB2 Query Info Request + */ + +/* info type */ +#define SMB2_0_INFO_FILE 0x01 +/* The file information is requested. */ +#define SMB2_0_INFO_FILESYSTEM 0x02 +/* The underlying object store information is requested. */ +#define SMB2_0_INFO_SECURITY 0x03 +/* The security information is requested. */ +#define SMB2_0_INFO_QUOTA 0x04 +/* The underlying object store quota information is requested. */ + +/* + * MS-FSCC 2.5 FileSystem Information Classes. + * Also see MSDN for ZwQueryVolumeInformationFile. + */ +typedef enum _FS_INFORMATION_CLASS +{ + FileFsVolumeInformation = 1, /* Query */ + FileFsLabelInformation = 2, /* Set */ + FileFsSizeInformation = 3, /* Query */ + FileFsDeviceInformation = 4, /* Query */ + FileFsAttributeInformation = 5, /* Query */ + FileFsControlInformation = 6, /* Query, Set */ + FileFsFullSizeInformation = 7, /* Query */ + FileFsObjectIdInformation = 8, /* Query, Set */ + FileFsDriverPathInformation = 9 /* Query */ +} FS_INFORMATION_CLASS; + +/* + * MS-FSCC 2.4 File Information Classes + */ +typedef enum _FILE_INFORMATION_CLASS +{ + FileDirectoryInformation = 1, + FileFullDirectoryInformation = 2, + FileBothDirectoryInformation = 3, + FileBasicInformation = 4, + FileStandardInformation = 5, + FileInternalInformation = 6, + FileEaInformation = 7, + FileAccessInformation = 8, + FileNameInformation = 9, + FileRenameInformation = 10, + FileLinkInformation = 11, + FileNamesInformation = 12, + FileDispositionInformation = 13, + FilePositionInformation = 14, + FileFullEaInformation = 15, + FileModeInformation = 16, + FileAlignmentInformation = 17, + FileAllInformation = 18, + FileAllocationInformation = 19, + FileEndOfFileInformation = 20, + FileAlternateNameInformation = 21, + FileStreamInformation = 22, + FilePipeInformation = 23, + FilePipeLocalInformation = 24, + FilePipeRemoteInformation = 25, + FileMailslotQueryInformation = 26, + FileMailslotSetInformation = 27, + FileCompressionInformation = 28, + FileObjectIdInformation = 29, + FileMoveClusterInformation = 31, + FileQuotaInformation = 32, + FileReparsePointInformation = 33, + FileNetworkOpenInformation = 34, + FileAttributeTagInformation = 35, + FileTrackingInformation = 36, + FileIdBothDirectoryInformation = 37, + FileIdFullDirectoryInformation = 38, + FileValidDataLengthInformation = 39, + FileShortNameInformation = 40, + FileSfioReserveInformation = 44, + FileSfioVolumeInformation = 45, + FileHardLinkInformation = 46, + FileNormalizedNameInformation = 48, + FileIdGlobalTxDirectoryInformation = 50, + FileStandardLinkInformation = 54 +} FILE_INFORMATION_CLASS; + +/* + * SMB2 Change Nofity Request + */ +#define SMB2_WATCH_TREE 0x00000001 + +/* + * After here, added stuff from darwin + */ +#define SMB2_TID_UNKNOWN 0 +#define SMB2_FID_UNUSED 0xffffffffffffffff + +/* smb2_durable_handle flags */ +typedef enum _SMB2_DURABLE_HANDLE_FLAGS +{ + SMB2_DURABLE_HANDLE_REQUEST = 0x0001, + SMB2_DURABLE_HANDLE_RECONNECT = 0x0002, + SMB2_DURABLE_HANDLE_GRANTED = 0x0004, + SMB2_LEASE_GRANTED = 0x0008 +} _SMB2_DURABLE_HANDLE_FLAGS; + +struct smb2_durable_handle { + uint64_t fid; /* SMBFID to reconnect in durable handle reconnect */ + uint64_t flags; + uint64_t lease_key_hi; /* atomic increment number */ + uint64_t lease_key_low; /* node hash value */ + uint32_t lease_state; + uint32_t pad; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _NETSMB_SMB2_H */ diff --git a/usr/src/uts/common/netsmb/smb_dev.h b/usr/src/uts/common/netsmb/smb_dev.h index fb20b9c753..817d214b3e 100644 --- a/usr/src/uts/common/netsmb/smb_dev.h +++ b/usr/src/uts/common/netsmb/smb_dev.h @@ -114,9 +114,19 @@ #define SMBVOPT_PERMANENT 0x0010 /* object will keep last reference */ #define SMBVOPT_ANONYMOUS 0x0020 /* using a NULL session */ -#define SMBVOPT_SIGNING_ENABLED 0x0100 /* sign if server agrees */ -#define SMBVOPT_SIGNING_REQUIRED 0x0200 /* signing required */ -#define SMBVOPT_SIGNING_MASK 0x0300 /* all signing bits */ +#define SMBVOPT_SIGNING_ENABLED 0x10000 /* sign if server agrees */ +#define SMBVOPT_SIGNING_REQUIRED 0x20000 /* signing required */ +#define SMBVOPT_SIGNING_MASK 0x30000 /* all signing bits */ + +#define SMB2_DIALECT_BASE 0x0200 +#define SMB2_DIALECT_0202 0x0202 +#define SMB2_DIALECT_02ff 0x02ff +#define SMB2_DIALECT_0210 0x0210 +#define SMB2_DIALECT_0300 0x0300 +#define SMB2_DIALECT_0302 0x0302 + +/* Maximum supported dialect (for ssn_maxver) */ +#define SMB2_DIALECT_MAX SMB2_DIALECT_0210 /* * Option flags in smbioc_oshare.ioc_opt @@ -208,8 +218,10 @@ typedef struct smbioc_ssn_ident smbioc_ssn_ident_t; * Structure used with SMBIOC_SSN_FIND, _CREATE */ struct smbioc_ossn { - uint32_t ssn_vopt; /* i.e. SMBVOPT_CREATE */ uint32_t ssn_owner; /* Unix owner (UID) */ + uint32_t ssn_vopt; /* i.e. SMBVOPT_CREATE */ + uint16_t ssn_minver; /* Min SMB version. */ + uint16_t ssn_maxver; /* Max SMB version. */ smbioc_ssn_ident_t ssn_id; char ssn_srvname[SMBIOC_MAX_NAME]; }; @@ -248,7 +260,7 @@ struct smbioc_ssn_work { uint32_t wk_u_auth_wlen; /* send auth tok len */ lptr_t wk_u_auth_rbuf; /* recv auth tok buf */ lptr_t wk_u_auth_wbuf; /* send auth tok buf */ - uint8_t wk_ssn_key[SMBIOC_HASH_SZ]; /* session key */ + uint8_t wk_cl_guid[16]; /* client GUID */ }; typedef struct smbioc_ssn_work smbioc_ssn_work_t; @@ -257,8 +269,8 @@ typedef struct smbioc_ssn_work smbioc_ssn_work_t; */ typedef struct smbioc_rw { - int32_t ioc_fh; uint32_t ioc_cnt; + uint32_t ioc_flags; lloff_t _ioc_offset; lptr_t _ioc_base; } smbioc_rw_t; @@ -267,10 +279,10 @@ typedef struct smbioc_rw { /* Transact on named pipe (send/recv) */ typedef struct smbioc_xnp { - int32_t ioc_fh; uint32_t ioc_tdlen; /* transmit len */ uint32_t ioc_rdlen; /* recv maxlen */ uint32_t ioc_more; /* more data to read */ + uint32_t ioc_pad1; lptr_t _ioc_tdata; lptr_t _ioc_rdata; } smbioc_xnp_t; diff --git a/usr/src/uts/common/smb/Makefile b/usr/src/uts/common/smb/Makefile index 74ac618565..afa0837b2b 100644 --- a/usr/src/uts/common/smb/Makefile +++ b/usr/src/uts/common/smb/Makefile @@ -21,7 +21,7 @@ # # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. -# Copyright 2013 Nexenta Systems, Inc. All rights reserved. +# Copyright 2018 Nexenta Systems, Inc. All rights reserved. # include ../../../Makefile.master @@ -29,8 +29,10 @@ include ../../../Makefile.master HDRS= \ doserror.h \ lmerr.h \ + ntaccess.h \ nterror.h \ ntstatus.h \ + winioctl.h \ wintypes.h diff --git a/usr/src/uts/common/smb/ntaccess.h b/usr/src/uts/common/smb/ntaccess.h new file mode 100644 index 0000000000..77d48b48ad --- /dev/null +++ b/usr/src/uts/common/smb/ntaccess.h @@ -0,0 +1,237 @@ +/* + * 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. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + +#ifndef _SMBSRV_NTACCESS_H +#define _SMBSRV_NTACCESS_H + +/* + * This file defines the NT compatible access control masks and values. + * An access mask as a 32-bit value arranged as shown below. + * + * 31-28 Generic bits, interpreted per object type + * 27-26 Reserved, must-be-zero + * 25 Maximum allowed + * 24 System Security rights (SACL is SD) + * 23-16 Standard access rights, generic to all object types + * 15-0 Specific access rights, object specific + * + * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +---------------+---------------+-------------------------------+ + * |G|G|G|G|Res'd|A| StandardRights| SpecificRights | + * |R|W|E|A| |S| | | + * +-+-------------+---------------+-------------------------------+ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Specific rights for files, pipes and directories. + */ +#define FILE_READ_DATA (0x0001) /* file & pipe */ +#define FILE_LIST_DIRECTORY (0x0001) /* directory */ +#define FILE_WRITE_DATA (0x0002) /* file & pipe */ +#define FILE_ADD_FILE (0x0002) /* directory */ +#define FILE_APPEND_DATA (0x0004) /* file */ +#define FILE_ADD_SUBDIRECTORY (0x0004) /* directory */ +#define FILE_CREATE_PIPE_INSTANCE (0x0004) /* named pipe */ +#define FILE_READ_EA (0x0008) /* file & directory */ +#define FILE_READ_PROPERTIES (0x0008) /* pipe */ +#define FILE_WRITE_EA (0x0010) /* file & directory */ +#define FILE_WRITE_PROPERTIES (0x0010) /* pipe */ +#define FILE_EXECUTE (0x0020) /* file */ +#define FILE_TRAVERSE (0x0020) /* directory */ +#define FILE_DELETE_CHILD (0x0040) /* directory */ +#define FILE_READ_ATTRIBUTES (0x0080) /* all */ +#define FILE_WRITE_ATTRIBUTES (0x0100) /* all */ +#define FILE_SPECIFIC_ALL (0x000001FFL) +#define SPECIFIC_RIGHTS_ALL (0x0000FFFFL) + + +/* + * Standard rights: + * + * DELETE The right to delete the object. + * + * READ_CONTROL The right to read the information in the object's security + * descriptor, not including the information in the SACL. + * + * WRITE_DAC The right to modify the DACL in the object's security + * descriptor. + * + * WRITE_OWNER The right to change the owner in the object's security + * descriptor. + * + * SYNCHRONIZE The right to use the object for synchronization. This enables + * a thread to wait until the object is in the signaled state. + */ +#define DELETE (0x00010000L) +#define READ_CONTROL (0x00020000L) +#define WRITE_DAC (0x00040000L) +#define WRITE_OWNER (0x00080000L) /* take ownership */ +#define SYNCHRONIZE (0x00100000L) +#define STANDARD_RIGHTS_REQUIRED (0x000F0000L) +#define STANDARD_RIGHTS_ALL (0x001F0000L) + + +#define STANDARD_RIGHTS_READ (READ_CONTROL) +#define STANDARD_RIGHTS_WRITE (READ_CONTROL) +#define STANDARD_RIGHTS_EXECUTE (READ_CONTROL) + +#define FILE_METADATA_ALL (FILE_READ_EA |\ + FILE_READ_ATTRIBUTES |\ + READ_CONTROL |\ + FILE_WRITE_EA |\ + FILE_WRITE_ATTRIBUTES |\ + WRITE_DAC |\ + WRITE_OWNER |\ + SYNCHRONIZE) + +#define FILE_DATA_ALL (FILE_READ_DATA |\ + FILE_WRITE_DATA |\ + FILE_APPEND_DATA |\ + FILE_EXECUTE |\ + DELETE) + +#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF) + + +/* + * Miscellaneous bits: SACL access and maximum allowed access. + */ +#define ACCESS_SYSTEM_SECURITY (0x01000000L) +#define MAXIMUM_ALLOWED (0x02000000L) + + +/* + * Generic rights. These are shorthands that are interpreted as + * appropriate for the type of secured object being accessed. + */ +#define GENERIC_ALL (0x10000000UL) +#define GENERIC_EXECUTE (0x20000000UL) +#define GENERIC_WRITE (0x40000000UL) +#define GENERIC_READ (0x80000000UL) + +#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | \ + FILE_READ_DATA | \ + FILE_READ_ATTRIBUTES | \ + FILE_READ_EA | \ + SYNCHRONIZE) + +#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | \ + FILE_WRITE_DATA | \ + FILE_WRITE_ATTRIBUTES | \ + FILE_WRITE_EA | \ + FILE_APPEND_DATA | \ + SYNCHRONIZE) + +#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | \ + FILE_READ_ATTRIBUTES | \ + FILE_EXECUTE | \ + SYNCHRONIZE) + +#define FILE_GENERIC_ALL (FILE_GENERIC_READ | \ + FILE_GENERIC_WRITE | \ + FILE_GENERIC_EXECUTE) + + +/* + * LSA policy desired access masks. + */ +#define POLICY_VIEW_LOCAL_INFORMATION 0x00000001L +#define POLICY_VIEW_AUDIT_INFORMATION 0x00000002L +#define POLICY_GET_PRIVATE_INFORMATION 0x00000004L +#define POLICY_TRUST_ADMIN 0x00000008L +#define POLICY_CREATE_ACCOUNT 0x00000010L +#define POLICY_CREATE_SECRET 0x00000020L +#define POLICY_CREATE_PRIVILEGE 0x00000040L +#define POLICY_SET_DEFAULT_QUOTA_LIMITS 0x00000080L +#define POLICY_SET_AUDIT_REQUIREMENTS 0x00000100L +#define POLICY_AUDIT_LOG_ADMIN 0x00000200L +#define POLICY_SERVER_ADMIN 0x00000400L +#define POLICY_LOOKUP_NAMES 0x00000800L + + +/* + * SAM specific rights desired access masks. These definitions are listed + * mostly as a convenience; they don't seem to be documented. Setting the + * desired access mask to GENERIC_EXECUTE and STANDARD_RIGHTS_EXECUTE + * seems to work when just looking up information. + */ +#define SAM_LOOKUP_INFORMATION (GENERIC_EXECUTE \ + | STANDARD_RIGHTS_EXECUTE) + +#define SAM_ACCESS_USER_READ 0x0000031BL +#define SAM_ACCESS_USER_UPDATE 0x0000031FL +#define SAM_ACCESS_USER_SETPWD 0x0000037FL +#define SAM_CONNECT_CREATE_ACCOUNT 0x00000020L +#define SAM_ENUM_LOCAL_DOMAIN 0x00000030L +#define SAM_DOMAIN_CREATE_ACCOUNT 0x00000211L + + +/* + * File attributes + * + * Note: 0x00000008 is reserved for use for the old DOS VOLID (volume ID) + * and is therefore not considered valid in NT. + * + * Note: 0x00000010 is reserved for use for the old DOS SUBDIRECTORY flag + * and is therefore not considered valid in NT. This flag has + * been disassociated with file attributes since the other flags are + * protected with READ_ and WRITE_ATTRIBUTES access to the file. + * + * Note: Note also that the order of these flags is set to allow both the + * FAT and the Pinball File Systems to directly set the attributes + * flags in attributes words without having to pick each flag out + * individually. The order of these flags should not be changed! + * + * The file attributes are defined in smbsrv/smb_vops.h + */ + +/* Filesystem Attributes */ +#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_VOLUME_IS_COMPRESSED 0x00008000 +#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 +#define FILE_SUPPORTS_ENCRYPTION 0x00020000 +#define FILE_NAMED_STREAMS 0x00040000 +#define FILE_READ_ONLY_VOLUME 0x00080000 + +#ifdef __cplusplus +} +#endif + +#endif /* _SMBSRV_NTACCESS_H */ diff --git a/usr/src/uts/common/smb/winioctl.h b/usr/src/uts/common/smb/winioctl.h new file mode 100644 index 0000000000..a18d7853ce --- /dev/null +++ b/usr/src/uts/common/smb/winioctl.h @@ -0,0 +1,547 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ +#ifndef _SMB_WINIOCTL_H +#define _SMB_WINIOCTL_H + +/* + * Standard Windows NT IOCTL/FSCTL definitions (derived from the VC++ + * include file of the same name). + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _DEVIOCTL_ +#define _DEVIOCTL_ + +/* + * begin_ntddk begin_wdm begin_nthal begin_ntifs + * + * Define the various device type values. Note that values used by Microsoft + * Corporation are in the range 0-32767, and 32768-65535 are reserved for use + * by customers. + */ + +#define DEVICE_TYPE DWORD + +#define FILE_DEVICE_BEEP 0x00000001 +#define FILE_DEVICE_CD_ROM 0x00000002 +#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 +#define FILE_DEVICE_CONTROLLER 0x00000004 +#define FILE_DEVICE_DATALINK 0x00000005 +#define FILE_DEVICE_DFS 0x00000006 +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 +#define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#define FILE_DEVICE_INPORT_PORT 0x0000000a +#define FILE_DEVICE_KEYBOARD 0x0000000b +#define FILE_DEVICE_MAILSLOT 0x0000000c +#define FILE_DEVICE_MIDI_IN 0x0000000d +#define FILE_DEVICE_MIDI_OUT 0x0000000e +#define FILE_DEVICE_MOUSE 0x0000000f +#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 +#define FILE_DEVICE_NAMED_PIPE 0x00000011 +#define FILE_DEVICE_NETWORK 0x00000012 +#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 +#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 +#define FILE_DEVICE_NULL 0x00000015 +#define FILE_DEVICE_PARALLEL_PORT 0x00000016 +#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 +#define FILE_DEVICE_PRINTER 0x00000018 +#define FILE_DEVICE_SCANNER 0x00000019 +#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a +#define FILE_DEVICE_SERIAL_PORT 0x0000001b +#define FILE_DEVICE_SCREEN 0x0000001c +#define FILE_DEVICE_SOUND 0x0000001d +#define FILE_DEVICE_STREAMS 0x0000001e +#define FILE_DEVICE_TAPE 0x0000001f +#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 +#define FILE_DEVICE_TRANSPORT 0x00000021 +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define FILE_DEVICE_VIDEO 0x00000023 +#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 +#define FILE_DEVICE_WAVE_IN 0x00000025 +#define FILE_DEVICE_WAVE_OUT 0x00000026 +#define FILE_DEVICE_8042_PORT 0x00000027 +#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 +#define FILE_DEVICE_BATTERY 0x00000029 +#define FILE_DEVICE_BUS_EXTENDER 0x0000002a +#define FILE_DEVICE_MODEM 0x0000002b +#define FILE_DEVICE_VDM 0x0000002c +#define FILE_DEVICE_MASS_STORAGE 0x0000002d +#define FILE_DEVICE_SMB 0x0000002e +#define FILE_DEVICE_KS 0x0000002f +#define FILE_DEVICE_CHANGER 0x00000030 +#define FILE_DEVICE_SMARTCARD 0x00000031 +#define FILE_DEVICE_ACPI 0x00000032 +#define FILE_DEVICE_DVD 0x00000033 +#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 +#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035 +#define FILE_DEVICE_DFS_VOLUME 0x00000036 + +/* + * Macro definition for defining IOCTL and FSCTL function control codes. Note + * that function codes 0-2047 are reserved for Microsoft Corporation, and + * 2048-4095 are reserved for customers. + */ + +#define CTL_CODE(DeviceType, Function, Method, Access) \ + (((DeviceType) << 16) | ((Access) << 14) | \ + ((Function) << 2) | (Method)) + +/* + * Define the method codes for how buffers are passed for I/O and FS controls + */ + +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +/* + * Define the access check value for any access + */ + +#define FILE_ANY_ACCESS 0 +#define FILE_READ_ACCESS 0x0001 /* file & pipe */ +#define FILE_WRITE_ACCESS 0x0002 /* file & pipe */ + +/* end_ntddk end_wdm end_nthal end_ntifs */ + +#endif /* _DEVIOCTL_ */ + + +#ifndef _NTDDSTOR_H_ +#define _NTDDSTOR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * IoControlCode values for storage devices + */ + +#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE + +/* + * The following device control codes are common for all class drivers. They + * should be used in place of the older IOCTL_DISK, IOCTL_CDROM and IOCTL_TAPE + * common codes + */ + +#define IOCTL_STORAGE_CHECK_VERIFY \ + CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_MEDIA_REMOVAL \ + CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_EJECT_MEDIA \ + CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_LOAD_MEDIA \ + CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_RESERVE \ + CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_RELEASE \ + CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_FIND_NEW_DEVICES \ + CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_STORAGE_GET_MEDIA_TYPES \ + CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX \ + CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_STORAGE_RESET_BUS \ + CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_RESET_DEVICE \ + CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_STORAGE_GET_DEVICE_NUMBER \ + CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS) + + +#ifdef __cplusplus +} +#endif +#endif /* _NTDDSTOR_H_ */ + +/* + * IoControlCode values for disk devices. + */ + +#define IOCTL_DISK_BASE FILE_DEVICE_DISK +#define IOCTL_DISK_GET_DRIVE_GEOMETRY \ + CTL_CODE(IOCTL_DISK_BASE, 0x0000, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_GET_PARTITION_INFO \ + CTL_CODE(IOCTL_DISK_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_PARTITION_INFO \ + CTL_CODE(IOCTL_DISK_BASE, 0x0002, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_GET_DRIVE_LAYOUT \ + CTL_CODE(IOCTL_DISK_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_DRIVE_LAYOUT \ + CTL_CODE(IOCTL_DISK_BASE, 0x0004, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_VERIFY \ + CTL_CODE(IOCTL_DISK_BASE, 0x0005, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_FORMAT_TRACKS \ + CTL_CODE(IOCTL_DISK_BASE, 0x0006, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_REASSIGN_BLOCKS \ + CTL_CODE(IOCTL_DISK_BASE, 0x0007, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_PERFORMANCE \ + CTL_CODE(IOCTL_DISK_BASE, 0x0008, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_IS_WRITABLE \ + CTL_CODE(IOCTL_DISK_BASE, 0x0009, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_LOGGING \ + CTL_CODE(IOCTL_DISK_BASE, 0x000a, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_FORMAT_TRACKS_EX \ + CTL_CODE(IOCTL_DISK_BASE, 0x000b, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_HISTOGRAM_STRUCTURE \ + CTL_CODE(IOCTL_DISK_BASE, 0x000c, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_HISTOGRAM_DATA \ + CTL_CODE(IOCTL_DISK_BASE, 0x000d, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_HISTOGRAM_RESET \ + CTL_CODE(IOCTL_DISK_BASE, 0x000e, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_REQUEST_STRUCTURE \ + CTL_CODE(IOCTL_DISK_BASE, 0x000f, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_REQUEST_DATA \ + CTL_CODE(IOCTL_DISK_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_CONTROLLER_NUMBER \ + CTL_CODE(IOCTL_DISK_BASE, 0x0011, METHOD_BUFFERED, FILE_ANY_ACCESS) + +/* + * IOCTL support for SMART drive fault prediction. + */ + +#define SMART_GET_VERSION \ + CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS) +#define SMART_SEND_DRIVE_COMMAND \ + CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define SMART_RCV_DRIVE_DATA \ + CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) + + +/* + * The following device control codes are common for all class drivers. The + * functions codes defined here must match all of the other class drivers. + * + * Warning: these codes will be replaced in the future by equivalent + * IOCTL_STORAGE codes + */ + +#define IOCTL_DISK_CHECK_VERIFY \ + CTL_CODE(IOCTL_DISK_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_MEDIA_REMOVAL \ + CTL_CODE(IOCTL_DISK_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_EJECT_MEDIA \ + CTL_CODE(IOCTL_DISK_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_LOAD_MEDIA \ + CTL_CODE(IOCTL_DISK_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_RESERVE \ + CTL_CODE(IOCTL_DISK_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_RELEASE \ + CTL_CODE(IOCTL_DISK_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_FIND_NEW_DEVICES \ + CTL_CODE(IOCTL_DISK_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_GET_MEDIA_TYPES \ + CTL_CODE(IOCTL_DISK_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_CHANGER_BASE FILE_DEVICE_CHANGER + +#define IOCTL_CHANGER_GET_PARAMETERS \ + CTL_CODE(IOCTL_CHANGER_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CHANGER_GET_STATUS \ + CTL_CODE(IOCTL_CHANGER_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CHANGER_GET_PRODUCT_DATA \ + CTL_CODE(IOCTL_CHANGER_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CHANGER_SET_ACCESS \ + CTL_CODE(IOCTL_CHANGER_BASE, 0x0004, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_CHANGER_GET_ELEMENT_STATUS \ + CTL_CODE(IOCTL_CHANGER_BASE, 0x0005, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS \ + CTL_CODE(IOCTL_CHANGER_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CHANGER_SET_POSITION \ + CTL_CODE(IOCTL_CHANGER_BASE, 0x0007, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CHANGER_EXCHANGE_MEDIUM \ + CTL_CODE(IOCTL_CHANGER_BASE, 0x0008, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CHANGER_MOVE_MEDIUM \ + CTL_CODE(IOCTL_CHANGER_BASE, 0x0009, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CHANGER_REINITIALIZE_TRANSPORT \ + CTL_CODE(IOCTL_CHANGER_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CHANGER_QUERY_VOLUME_TAGS \ + CTL_CODE(IOCTL_CHANGER_BASE, 0x000B, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#ifndef _FILESYSTEMFSCTL_ +#define _FILESYSTEMFSCTL_ +/* + * The following is a list of the native file system fsctls followed by + * additional network file system fsctls, DFS fsctls and Named Pipe fsctls. + * Some values have been decommissioned. + */ + +/* FILE_DEVICE_FILE_SYSTEM */ +#define FSCTL_REQUEST_OPLOCK_LEVEL_1 \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_REQUEST_OPLOCK_LEVEL_2 \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 1, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_REQUEST_BATCH_OPLOCK \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_OPLOCK_BREAK_ACKNOWLEDGE \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 3, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_OPBATCH_ACK_CLOSE_PENDING \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 4, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_OPLOCK_BREAK_NOTIFY \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 5, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_LOCK_VOLUME \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_UNLOCK_VOLUME \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_DISMOUNT_VOLUME \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* decommissioned fsctl value 9 */ +#define FSCTL_IS_VOLUME_MOUNTED \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 10, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* PATHNAME_BUFFER, */ +#define FSCTL_IS_PATHNAME_VALID \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 11, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_MARK_VOLUME_DIRTY \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 12, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* decommissioned fsctl value 13 */ +#define FSCTL_QUERY_RETRIEVAL_POINTERS \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 14, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_GET_COMPRESSION \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 15, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_SET_COMPRESSION \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 16, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +/* decommissioned fsctl value 17 */ +/* decommissioned fsctl value 18 */ +#define FSCTL_MARK_AS_SYSTEM_HIVE \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 19, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_OPLOCK_BREAK_ACK_NO_2 \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 20, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_INVALIDATE_VOLUMES \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 21, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* FSCTL_QUERY_FAT_BPB_BUFFER */ +#define FSCTL_QUERY_FAT_BPB \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 22, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_REQUEST_FILTER_OPLOCK \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 23, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* FILESYSTEM_STATISTICS */ +#define FSCTL_FILESYSTEM_GET_STATISTICS \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 24, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* NTFS_VOLUME_DATA_BUFFER */ +#define FSCTL_GET_NTFS_VOLUME_DATA \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 25, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* NTFS_FILE_RECORD_INPUT_BUFFER, NTFS_FILE_RECORD_OUTPUT_BUFFER */ +#define FSCTL_GET_NTFS_FILE_RECORD \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 26, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* STARTING_LCN_INPUT_BUFFER, VOLUME_BITMAP_BUFFER */ +#define FSCTL_GET_VOLUME_BITMAP \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 27, METHOD_NEITHER, FILE_ANY_ACCESS) +/* STARTING_VCN_INPUT_BUFFER, RETRIEVAL_POINTERS_BUFFER */ +#define FSCTL_GET_RETRIEVAL_POINTERS \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 28, METHOD_NEITHER, FILE_ANY_ACCESS) +/* MOVE_FILE_DATA, */ +#define FSCTL_MOVE_FILE \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 29, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_IS_VOLUME_DIRTY \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 30, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_GET_HFS_INFORMATION \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 31, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_ALLOW_EXTENDED_DASD_IO \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 32, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_READ_PROPERTY_DATA \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 33, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_WRITE_PROPERTY_DATA \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 34, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_FIND_FILES_BY_SID \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 35, METHOD_NEITHER, FILE_ANY_ACCESS) +/* decommissioned fsctl value 36 */ +#define FSCTL_DUMP_PROPERTY_DATA \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 37, METHOD_NEITHER, FILE_ANY_ACCESS) +/* FILE_OBJECTID_BUFFER */ +#define FSCTL_SET_OBJECT_ID \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 38, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* FILE_OBJECTID_BUFFER */ +#define FSCTL_GET_OBJECT_ID \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 39, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_DELETE_OBJECT_ID \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 40, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* REPARSE_DATA_BUFFER, */ +#define FSCTL_SET_REPARSE_POINT \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* REPARSE_DATA_BUFFER */ +#define FSCTL_GET_REPARSE_POINT \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* REPARSE_DATA_BUFFER, */ +#define FSCTL_DELETE_REPARSE_POINT \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* MFT_ENUM_DATA, */ +#define FSCTL_ENUM_USN_DATA \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 44, METHOD_NEITHER, FILE_READ_ACCESS) +/* BULK_SECURITY_TEST_DATA, */ +#define FSCTL_SECURITY_ID_CHECK \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 45, METHOD_NEITHER, FILE_READ_ACCESS) +/* READ_USN_JOURNAL_DATA, USN */ +#define FSCTL_READ_USN_JOURNAL \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 46, METHOD_NEITHER, FILE_READ_ACCESS) +#define FSCTL_SET_OBJECT_ID_EXTENDED \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 47, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* FILE_OBJECTID_BUFFER */ +#define FSCTL_CREATE_OR_GET_OBJECT_ID \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 48, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_SET_SPARSE \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* FILE_ZERO_DATA_INFORMATION, */ +#define FSCTL_SET_ZERO_DATA \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 50, METHOD_BUFFERED, FILE_WRITE_ACCESS) +/* FILE_ALLOCATED_RANGE_BUFFER, FILE_ALLOCATED_RANGE_BUFFER */ +#define FSCTL_QUERY_ALLOCATED_RANGES \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 51, METHOD_NEITHER, FILE_READ_ACCESS) +#define FSCTL_ENABLE_UPGRADE \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 52, METHOD_BUFFERED, FILE_WRITE_ACCESS) +/* ENCRYPTION_BUFFER, */ +#define FSCTL_SET_ENCRYPTION \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 53, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_ENCRYPTION_FSCTL_IO \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 54, METHOD_NEITHER, FILE_ANY_ACCESS) +/* ENCRYPTED_DATA_INFO, */ +#define FSCTL_WRITE_RAW_ENCRYPTED \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 55, METHOD_NEITHER, FILE_ANY_ACCESS) +/* REQUEST_RAW_ENCRYPTED_DATA, ENCRYPTED_DATA_INFO */ +#define FSCTL_READ_RAW_ENCRYPTED \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 56, METHOD_NEITHER, FILE_ANY_ACCESS) +/* CREATE_USN_JOUNRAL_DATA, */ +#define FSCTL_CREATE_USN_JOURNAL \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 57, METHOD_NEITHER, FILE_READ_ACCESS) +/* Read the Usn Record for a file */ +#define FSCTL_READ_FILE_USN_DATA \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 58, METHOD_NEITHER, FILE_ANY_ACCESS) +/* Generate Close Usn Record */ +#define FSCTL_WRITE_USN_CLOSE_RECORD \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 59, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_EXTEND_VOLUME \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 60, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_SIS_COPYFILE \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 64, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_RECALL_FILE \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 69, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_SET_DEFECT_MANAGEMENT \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 77, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define FSCTL_QUERY_SPARING_INFO \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 78, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_QUERY_ON_DISK_VOLUME_INFO \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 79, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_SET_ZERO_ON_DEALLOCATION \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 101, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_SET_SHORT_NAME_BEHAVIOR \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 109, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_FILE_LEVEL_TRIM \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 130, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define FSCTL_OFFLOAD_READ \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 153, METHOD_BUFFERED, FILE_READ_ACCESS) +#define FSCTL_OFFLOAD_WRITE \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 154, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define FSCTL_GET_INTEGRITY_INFORMATION \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 159, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_SET_INTEGRITY_INFORMATION \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 160, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +/* FILE_DEVICE_NETWORK_FILE_SYSTEM */ +/* Read the snapshot info for Volume Shadow Copy Services */ +#define FSCTL_SRV_ENUMERATE_SNAPSHOTS \ + CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x19, \ + METHOD_BUFFERED, FILE_READ_ACCESS) +/* Retrieve an opaque file reference for server-side data movement */ +#define FSCTL_SRV_REQUEST_RESUME_KEY \ + CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x1e, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_LMR_GET_LINK_TRACKING_INFORMATION \ + CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x3a, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_LMR_SET_LINK_TRACKING_INFORMATION \ + CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x3b, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +/* server-side data movement */ +#define FSCTL_SRV_COPYCHUNK \ + CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x3c, \ + METHOD_OUT_DIRECT, FILE_READ_ACCESS) +/* server-side data movement */ +#define FSCTL_SRV_COPYCHUNK_WRITE \ + CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x3c, \ + METHOD_OUT_DIRECT, FILE_WRITE_ACCESS) +#define FSCTL_SRV_NOTIFY_TRANSACTION \ + CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x46, \ + METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define FSCTL_SRV_READ_HASH \ + CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x6e, \ + METHOD_NEITHER, FILE_READ_ACCESS) +#define FSCTL_SRV_UNKNOWN_x71 \ + CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x71, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_LMR_REQUEST_RESILIENCY \ + CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x75, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_QUERY_NETWORK_INTERFACE_INFO \ + CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x7f, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_VALIDATE_NEGOTIATE_INFO \ + CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x81, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) + +/* FILE_DEVICE_DFS */ +#define FSCTL_DFS_GET_REFERRALS \ + CTL_CODE(FILE_DEVICE_DFS, 0x65, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_DFS_GET_REFERRALS_EX \ + CTL_CODE(FILE_DEVICE_DFS, 0x6c, METHOD_BUFFERED, FILE_ANY_ACCESS) + +/* FILE_DEVICE_NAMED_PIPE */ +#define FSCTL_PIPE_PEEK \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 3, METHOD_BUFFERED, FILE_READ_ACCESS) +#define FSCTL_PIPE_TRANSCEIVE \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 5, METHOD_NEITHER, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define FSCTL_PIPE_WAIT \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 6, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#endif /* _FILESYSTEMFSCTL_ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SMB_WINIOCTL_H */ diff --git a/usr/src/uts/common/smbsrv/Makefile b/usr/src/uts/common/smbsrv/Makefile index 4664c09cfb..a80be7497f 100644 --- a/usr/src/uts/common/smbsrv/Makefile +++ b/usr/src/uts/common/smbsrv/Makefile @@ -20,7 +20,7 @@ # # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. -# Copyright 2015 Nexenta Systems, Inc. All rights reserved. +# Copyright 2018 Nexenta Systems, Inc. All rights reserved. # include ../../../Makefile.master @@ -36,7 +36,6 @@ HDRS= alloc.h \ netbios.h \ netrauth.h \ nmpipes.h \ - ntaccess.h \ ntifs.h \ ntlocale.h \ smb_sid.h \ @@ -61,7 +60,6 @@ HDRS= alloc.h \ smb2_kproto.h \ string.h \ svrapi.h \ - winioctl.h \ winsvc.h NDLHDRS= dssetup.ndl \ diff --git a/usr/src/uts/common/smbsrv/ntaccess.h b/usr/src/uts/common/smbsrv/ntaccess.h deleted file mode 100644 index 114150baa9..0000000000 --- a/usr/src/uts/common/smbsrv/ntaccess.h +++ /dev/null @@ -1,237 +0,0 @@ -/* - * 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 _SMBSRV_NTACCESS_H -#define _SMBSRV_NTACCESS_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * This file defines the NT compatible access control masks and values. - * An access mask as a 32-bit value arranged as shown below. - * - * 31-28 Generic bits, interpreted per object type - * 27-26 Reserved, must-be-zero - * 25 Maximum allowed - * 24 System Security rights (SACL is SD) - * 23-16 Standard access rights, generic to all object types - * 15-0 Specific access rights, object specific - * - * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +---------------+---------------+-------------------------------+ - * |G|G|G|G|Res'd|A| StandardRights| SpecificRights | - * |R|W|E|A| |S| | | - * +-+-------------+---------------+-------------------------------+ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Specific rights for files, pipes and directories. - */ -#define FILE_READ_DATA (0x0001) /* file & pipe */ -#define FILE_LIST_DIRECTORY (0x0001) /* directory */ -#define FILE_WRITE_DATA (0x0002) /* file & pipe */ -#define FILE_ADD_FILE (0x0002) /* directory */ -#define FILE_APPEND_DATA (0x0004) /* file */ -#define FILE_ADD_SUBDIRECTORY (0x0004) /* directory */ -#define FILE_CREATE_PIPE_INSTANCE (0x0004) /* named pipe */ -#define FILE_READ_EA (0x0008) /* file & directory */ -#define FILE_READ_PROPERTIES (0x0008) /* pipe */ -#define FILE_WRITE_EA (0x0010) /* file & directory */ -#define FILE_WRITE_PROPERTIES (0x0010) /* pipe */ -#define FILE_EXECUTE (0x0020) /* file */ -#define FILE_TRAVERSE (0x0020) /* directory */ -#define FILE_DELETE_CHILD (0x0040) /* directory */ -#define FILE_READ_ATTRIBUTES (0x0080) /* all */ -#define FILE_WRITE_ATTRIBUTES (0x0100) /* all */ -#define FILE_SPECIFIC_ALL (0x000001FFL) -#define SPECIFIC_RIGHTS_ALL (0x0000FFFFL) - - -/* - * Standard rights: - * - * DELETE The right to delete the object. - * - * READ_CONTROL The right to read the information in the object's security - * descriptor, not including the information in the SACL. - * - * WRITE_DAC The right to modify the DACL in the object's security - * descriptor. - * - * WRITE_OWNER The right to change the owner in the object's security - * descriptor. - * - * SYNCHRONIZE The right to use the object for synchronization. This enables - * a thread to wait until the object is in the signaled state. - */ -#define DELETE (0x00010000L) -#define READ_CONTROL (0x00020000L) -#define WRITE_DAC (0x00040000L) -#define WRITE_OWNER (0x00080000L) /* take ownership */ -#define SYNCHRONIZE (0x00100000L) -#define STANDARD_RIGHTS_REQUIRED (0x000F0000L) -#define STANDARD_RIGHTS_ALL (0x001F0000L) - - -#define STANDARD_RIGHTS_READ (READ_CONTROL) -#define STANDARD_RIGHTS_WRITE (READ_CONTROL) -#define STANDARD_RIGHTS_EXECUTE (READ_CONTROL) - -#define FILE_METADATA_ALL (FILE_READ_EA |\ - FILE_READ_ATTRIBUTES |\ - READ_CONTROL |\ - FILE_WRITE_EA |\ - FILE_WRITE_ATTRIBUTES |\ - WRITE_DAC |\ - WRITE_OWNER |\ - SYNCHRONIZE) - -#define FILE_DATA_ALL (FILE_READ_DATA |\ - FILE_WRITE_DATA |\ - FILE_APPEND_DATA |\ - FILE_EXECUTE |\ - DELETE) - -#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF) - - -/* - * Miscellaneous bits: SACL access and maximum allowed access. - */ -#define ACCESS_SYSTEM_SECURITY (0x01000000L) -#define MAXIMUM_ALLOWED (0x02000000L) - - -/* - * Generic rights. These are shorthands that are interpreted as - * appropriate for the type of secured object being accessed. - */ -#define GENERIC_ALL (0x10000000UL) -#define GENERIC_EXECUTE (0x20000000UL) -#define GENERIC_WRITE (0x40000000UL) -#define GENERIC_READ (0x80000000UL) - -#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | \ - FILE_READ_DATA | \ - FILE_READ_ATTRIBUTES | \ - FILE_READ_EA | \ - SYNCHRONIZE) - -#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | \ - FILE_WRITE_DATA | \ - FILE_WRITE_ATTRIBUTES | \ - FILE_WRITE_EA | \ - FILE_APPEND_DATA | \ - SYNCHRONIZE) - -#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | \ - FILE_READ_ATTRIBUTES | \ - FILE_EXECUTE | \ - SYNCHRONIZE) - -#define FILE_GENERIC_ALL (FILE_GENERIC_READ | \ - FILE_GENERIC_WRITE | \ - FILE_GENERIC_EXECUTE) - - -/* - * LSA policy desired access masks. - */ -#define POLICY_VIEW_LOCAL_INFORMATION 0x00000001L -#define POLICY_VIEW_AUDIT_INFORMATION 0x00000002L -#define POLICY_GET_PRIVATE_INFORMATION 0x00000004L -#define POLICY_TRUST_ADMIN 0x00000008L -#define POLICY_CREATE_ACCOUNT 0x00000010L -#define POLICY_CREATE_SECRET 0x00000020L -#define POLICY_CREATE_PRIVILEGE 0x00000040L -#define POLICY_SET_DEFAULT_QUOTA_LIMITS 0x00000080L -#define POLICY_SET_AUDIT_REQUIREMENTS 0x00000100L -#define POLICY_AUDIT_LOG_ADMIN 0x00000200L -#define POLICY_SERVER_ADMIN 0x00000400L -#define POLICY_LOOKUP_NAMES 0x00000800L - - -/* - * SAM specific rights desired access masks. These definitions are listed - * mostly as a convenience; they don't seem to be documented. Setting the - * desired access mask to GENERIC_EXECUTE and STANDARD_RIGHTS_EXECUTE - * seems to work when just looking up information. - */ -#define SAM_LOOKUP_INFORMATION (GENERIC_EXECUTE \ - | STANDARD_RIGHTS_EXECUTE) - -#define SAM_ACCESS_USER_READ 0x0000031BL -#define SAM_ACCESS_USER_UPDATE 0x0000031FL -#define SAM_ACCESS_USER_SETPWD 0x0000037FL -#define SAM_CONNECT_CREATE_ACCOUNT 0x00000020L -#define SAM_ENUM_LOCAL_DOMAIN 0x00000030L -#define SAM_DOMAIN_CREATE_ACCOUNT 0x00000211L - - -/* - * File attributes - * - * Note: 0x00000008 is reserved for use for the old DOS VOLID (volume ID) - * and is therefore not considered valid in NT. - * - * Note: 0x00000010 is reserved for use for the old DOS SUBDIRECTORY flag - * and is therefore not considered valid in NT. This flag has - * been disassociated with file attributes since the other flags are - * protected with READ_ and WRITE_ATTRIBUTES access to the file. - * - * Note: Note also that the order of these flags is set to allow both the - * FAT and the Pinball File Systems to directly set the attributes - * flags in attributes words without having to pick each flag out - * individually. The order of these flags should not be changed! - * - * The file attributes are defined in smbsrv/smb_vops.h - */ - -/* Filesystem Attributes */ -#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_VOLUME_IS_COMPRESSED 0x00008000 -#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 -#define FILE_SUPPORTS_ENCRYPTION 0x00020000 -#define FILE_NAMED_STREAMS 0x00040000 -#define FILE_READ_ONLY_VOLUME 0x00080000 - -#ifdef __cplusplus -} -#endif - -#endif /* _SMBSRV_NTACCESS_H */ diff --git a/usr/src/uts/common/smbsrv/smb.h b/usr/src/uts/common/smbsrv/smb.h index a4986bea78..65e2708569 100644 --- a/usr/src/uts/common/smbsrv/smb.h +++ b/usr/src/uts/common/smbsrv/smb.h @@ -21,7 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _SMBSRV_SMB_H @@ -39,7 +39,7 @@ #include #include #include -#include +#include /* * Macintosh Extensions for CIFS diff --git a/usr/src/uts/common/smbsrv/winioctl.h b/usr/src/uts/common/smbsrv/winioctl.h deleted file mode 100644 index bbde2e4a6f..0000000000 --- a/usr/src/uts/common/smbsrv/winioctl.h +++ /dev/null @@ -1,547 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. - */ -#ifndef _SMBSRV_WINIOCTL_H -#define _SMBSRV_WINIOCTL_H - -/* - * Standard Windows NT IOCTL/FSCTL definitions (derived from the VC++ - * include file of the same name). - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _DEVIOCTL_ -#define _DEVIOCTL_ - -/* - * begin_ntddk begin_wdm begin_nthal begin_ntifs - * - * Define the various device type values. Note that values used by Microsoft - * Corporation are in the range 0-32767, and 32768-65535 are reserved for use - * by customers. - */ - -#define DEVICE_TYPE DWORD - -#define FILE_DEVICE_BEEP 0x00000001 -#define FILE_DEVICE_CD_ROM 0x00000002 -#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 -#define FILE_DEVICE_CONTROLLER 0x00000004 -#define FILE_DEVICE_DATALINK 0x00000005 -#define FILE_DEVICE_DFS 0x00000006 -#define FILE_DEVICE_DISK 0x00000007 -#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 -#define FILE_DEVICE_FILE_SYSTEM 0x00000009 -#define FILE_DEVICE_INPORT_PORT 0x0000000a -#define FILE_DEVICE_KEYBOARD 0x0000000b -#define FILE_DEVICE_MAILSLOT 0x0000000c -#define FILE_DEVICE_MIDI_IN 0x0000000d -#define FILE_DEVICE_MIDI_OUT 0x0000000e -#define FILE_DEVICE_MOUSE 0x0000000f -#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 -#define FILE_DEVICE_NAMED_PIPE 0x00000011 -#define FILE_DEVICE_NETWORK 0x00000012 -#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 -#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 -#define FILE_DEVICE_NULL 0x00000015 -#define FILE_DEVICE_PARALLEL_PORT 0x00000016 -#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 -#define FILE_DEVICE_PRINTER 0x00000018 -#define FILE_DEVICE_SCANNER 0x00000019 -#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a -#define FILE_DEVICE_SERIAL_PORT 0x0000001b -#define FILE_DEVICE_SCREEN 0x0000001c -#define FILE_DEVICE_SOUND 0x0000001d -#define FILE_DEVICE_STREAMS 0x0000001e -#define FILE_DEVICE_TAPE 0x0000001f -#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 -#define FILE_DEVICE_TRANSPORT 0x00000021 -#define FILE_DEVICE_UNKNOWN 0x00000022 -#define FILE_DEVICE_VIDEO 0x00000023 -#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 -#define FILE_DEVICE_WAVE_IN 0x00000025 -#define FILE_DEVICE_WAVE_OUT 0x00000026 -#define FILE_DEVICE_8042_PORT 0x00000027 -#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 -#define FILE_DEVICE_BATTERY 0x00000029 -#define FILE_DEVICE_BUS_EXTENDER 0x0000002a -#define FILE_DEVICE_MODEM 0x0000002b -#define FILE_DEVICE_VDM 0x0000002c -#define FILE_DEVICE_MASS_STORAGE 0x0000002d -#define FILE_DEVICE_SMB 0x0000002e -#define FILE_DEVICE_KS 0x0000002f -#define FILE_DEVICE_CHANGER 0x00000030 -#define FILE_DEVICE_SMARTCARD 0x00000031 -#define FILE_DEVICE_ACPI 0x00000032 -#define FILE_DEVICE_DVD 0x00000033 -#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 -#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035 -#define FILE_DEVICE_DFS_VOLUME 0x00000036 - -/* - * Macro definition for defining IOCTL and FSCTL function control codes. Note - * that function codes 0-2047 are reserved for Microsoft Corporation, and - * 2048-4095 are reserved for customers. - */ - -#define CTL_CODE(DeviceType, Function, Method, Access) \ - (((DeviceType) << 16) | ((Access) << 14) | \ - ((Function) << 2) | (Method)) - -/* - * Define the method codes for how buffers are passed for I/O and FS controls - */ - -#define METHOD_BUFFERED 0 -#define METHOD_IN_DIRECT 1 -#define METHOD_OUT_DIRECT 2 -#define METHOD_NEITHER 3 - -/* - * Define the access check value for any access - */ - -#define FILE_ANY_ACCESS 0 -#define FILE_READ_ACCESS 0x0001 /* file & pipe */ -#define FILE_WRITE_ACCESS 0x0002 /* file & pipe */ - -/* end_ntddk end_wdm end_nthal end_ntifs */ - -#endif /* _DEVIOCTL_ */ - - -#ifndef _NTDDSTOR_H_ -#define _NTDDSTOR_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * IoControlCode values for storage devices - */ - -#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE - -/* - * The following device control codes are common for all class drivers. They - * should be used in place of the older IOCTL_DISK, IOCTL_CDROM and IOCTL_TAPE - * common codes - */ - -#define IOCTL_STORAGE_CHECK_VERIFY \ - CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_MEDIA_REMOVAL \ - CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_EJECT_MEDIA \ - CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_LOAD_MEDIA \ - CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_RESERVE \ - CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_RELEASE \ - CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_FIND_NEW_DEVICES \ - CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_STORAGE_GET_MEDIA_TYPES \ - CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX \ - CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_STORAGE_RESET_BUS \ - CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_RESET_DEVICE \ - CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_STORAGE_GET_DEVICE_NUMBER \ - CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS) - - -#ifdef __cplusplus -} -#endif -#endif /* _NTDDSTOR_H_ */ - -/* - * IoControlCode values for disk devices. - */ - -#define IOCTL_DISK_BASE FILE_DEVICE_DISK -#define IOCTL_DISK_GET_DRIVE_GEOMETRY \ - CTL_CODE(IOCTL_DISK_BASE, 0x0000, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_GET_PARTITION_INFO \ - CTL_CODE(IOCTL_DISK_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_PARTITION_INFO \ - CTL_CODE(IOCTL_DISK_BASE, 0x0002, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_GET_DRIVE_LAYOUT \ - CTL_CODE(IOCTL_DISK_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_DRIVE_LAYOUT \ - CTL_CODE(IOCTL_DISK_BASE, 0x0004, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_VERIFY \ - CTL_CODE(IOCTL_DISK_BASE, 0x0005, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_FORMAT_TRACKS \ - CTL_CODE(IOCTL_DISK_BASE, 0x0006, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_REASSIGN_BLOCKS \ - CTL_CODE(IOCTL_DISK_BASE, 0x0007, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_PERFORMANCE \ - CTL_CODE(IOCTL_DISK_BASE, 0x0008, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_IS_WRITABLE \ - CTL_CODE(IOCTL_DISK_BASE, 0x0009, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_LOGGING \ - CTL_CODE(IOCTL_DISK_BASE, 0x000a, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_FORMAT_TRACKS_EX \ - CTL_CODE(IOCTL_DISK_BASE, 0x000b, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_HISTOGRAM_STRUCTURE \ - CTL_CODE(IOCTL_DISK_BASE, 0x000c, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_HISTOGRAM_DATA \ - CTL_CODE(IOCTL_DISK_BASE, 0x000d, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_HISTOGRAM_RESET \ - CTL_CODE(IOCTL_DISK_BASE, 0x000e, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_REQUEST_STRUCTURE \ - CTL_CODE(IOCTL_DISK_BASE, 0x000f, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_REQUEST_DATA \ - CTL_CODE(IOCTL_DISK_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_CONTROLLER_NUMBER \ - CTL_CODE(IOCTL_DISK_BASE, 0x0011, METHOD_BUFFERED, FILE_ANY_ACCESS) - -/* - * IOCTL support for SMART drive fault prediction. - */ - -#define SMART_GET_VERSION \ - CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS) -#define SMART_SEND_DRIVE_COMMAND \ - CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define SMART_RCV_DRIVE_DATA \ - CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) - - -/* - * The following device control codes are common for all class drivers. The - * functions codes defined here must match all of the other class drivers. - * - * Warning: these codes will be replaced in the future by equivalent - * IOCTL_STORAGE codes - */ - -#define IOCTL_DISK_CHECK_VERIFY \ - CTL_CODE(IOCTL_DISK_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_MEDIA_REMOVAL \ - CTL_CODE(IOCTL_DISK_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_EJECT_MEDIA \ - CTL_CODE(IOCTL_DISK_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_LOAD_MEDIA \ - CTL_CODE(IOCTL_DISK_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_RESERVE \ - CTL_CODE(IOCTL_DISK_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_RELEASE \ - CTL_CODE(IOCTL_DISK_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_FIND_NEW_DEVICES \ - CTL_CODE(IOCTL_DISK_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_GET_MEDIA_TYPES \ - CTL_CODE(IOCTL_DISK_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_CHANGER_BASE FILE_DEVICE_CHANGER - -#define IOCTL_CHANGER_GET_PARAMETERS \ - CTL_CODE(IOCTL_CHANGER_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CHANGER_GET_STATUS \ - CTL_CODE(IOCTL_CHANGER_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CHANGER_GET_PRODUCT_DATA \ - CTL_CODE(IOCTL_CHANGER_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CHANGER_SET_ACCESS \ - CTL_CODE(IOCTL_CHANGER_BASE, 0x0004, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_CHANGER_GET_ELEMENT_STATUS \ - CTL_CODE(IOCTL_CHANGER_BASE, 0x0005, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS \ - CTL_CODE(IOCTL_CHANGER_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CHANGER_SET_POSITION \ - CTL_CODE(IOCTL_CHANGER_BASE, 0x0007, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CHANGER_EXCHANGE_MEDIUM \ - CTL_CODE(IOCTL_CHANGER_BASE, 0x0008, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CHANGER_MOVE_MEDIUM \ - CTL_CODE(IOCTL_CHANGER_BASE, 0x0009, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CHANGER_REINITIALIZE_TRANSPORT \ - CTL_CODE(IOCTL_CHANGER_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CHANGER_QUERY_VOLUME_TAGS \ - CTL_CODE(IOCTL_CHANGER_BASE, 0x000B, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#ifndef _FILESYSTEMFSCTL_ -#define _FILESYSTEMFSCTL_ -/* - * The following is a list of the native file system fsctls followed by - * additional network file system fsctls, DFS fsctls and Named Pipe fsctls. - * Some values have been decommissioned. - */ - -/* FILE_DEVICE_FILE_SYSTEM */ -#define FSCTL_REQUEST_OPLOCK_LEVEL_1 \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_REQUEST_OPLOCK_LEVEL_2 \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 1, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_REQUEST_BATCH_OPLOCK \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_OPLOCK_BREAK_ACKNOWLEDGE \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 3, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_OPBATCH_ACK_CLOSE_PENDING \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 4, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_OPLOCK_BREAK_NOTIFY \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 5, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_LOCK_VOLUME \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_UNLOCK_VOLUME \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_DISMOUNT_VOLUME \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* decommissioned fsctl value 9 */ -#define FSCTL_IS_VOLUME_MOUNTED \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 10, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* PATHNAME_BUFFER, */ -#define FSCTL_IS_PATHNAME_VALID \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 11, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_MARK_VOLUME_DIRTY \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 12, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* decommissioned fsctl value 13 */ -#define FSCTL_QUERY_RETRIEVAL_POINTERS \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 14, METHOD_NEITHER, FILE_ANY_ACCESS) -#define FSCTL_GET_COMPRESSION \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 15, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_SET_COMPRESSION \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 16, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) -/* decommissioned fsctl value 17 */ -/* decommissioned fsctl value 18 */ -#define FSCTL_MARK_AS_SYSTEM_HIVE \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 19, METHOD_NEITHER, FILE_ANY_ACCESS) -#define FSCTL_OPLOCK_BREAK_ACK_NO_2 \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 20, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_INVALIDATE_VOLUMES \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 21, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* FSCTL_QUERY_FAT_BPB_BUFFER */ -#define FSCTL_QUERY_FAT_BPB \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 22, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_REQUEST_FILTER_OPLOCK \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 23, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* FILESYSTEM_STATISTICS */ -#define FSCTL_FILESYSTEM_GET_STATISTICS \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 24, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* NTFS_VOLUME_DATA_BUFFER */ -#define FSCTL_GET_NTFS_VOLUME_DATA \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 25, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* NTFS_FILE_RECORD_INPUT_BUFFER, NTFS_FILE_RECORD_OUTPUT_BUFFER */ -#define FSCTL_GET_NTFS_FILE_RECORD \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 26, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* STARTING_LCN_INPUT_BUFFER, VOLUME_BITMAP_BUFFER */ -#define FSCTL_GET_VOLUME_BITMAP \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 27, METHOD_NEITHER, FILE_ANY_ACCESS) -/* STARTING_VCN_INPUT_BUFFER, RETRIEVAL_POINTERS_BUFFER */ -#define FSCTL_GET_RETRIEVAL_POINTERS \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 28, METHOD_NEITHER, FILE_ANY_ACCESS) -/* MOVE_FILE_DATA, */ -#define FSCTL_MOVE_FILE \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 29, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_IS_VOLUME_DIRTY \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 30, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_GET_HFS_INFORMATION \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 31, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_ALLOW_EXTENDED_DASD_IO \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 32, METHOD_NEITHER, FILE_ANY_ACCESS) -#define FSCTL_READ_PROPERTY_DATA \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 33, METHOD_NEITHER, FILE_ANY_ACCESS) -#define FSCTL_WRITE_PROPERTY_DATA \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 34, METHOD_NEITHER, FILE_ANY_ACCESS) -#define FSCTL_FIND_FILES_BY_SID \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 35, METHOD_NEITHER, FILE_ANY_ACCESS) -/* decommissioned fsctl value 36 */ -#define FSCTL_DUMP_PROPERTY_DATA \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 37, METHOD_NEITHER, FILE_ANY_ACCESS) -/* FILE_OBJECTID_BUFFER */ -#define FSCTL_SET_OBJECT_ID \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 38, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* FILE_OBJECTID_BUFFER */ -#define FSCTL_GET_OBJECT_ID \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 39, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_DELETE_OBJECT_ID \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 40, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* REPARSE_DATA_BUFFER, */ -#define FSCTL_SET_REPARSE_POINT \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* REPARSE_DATA_BUFFER */ -#define FSCTL_GET_REPARSE_POINT \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* REPARSE_DATA_BUFFER, */ -#define FSCTL_DELETE_REPARSE_POINT \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* MFT_ENUM_DATA, */ -#define FSCTL_ENUM_USN_DATA \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 44, METHOD_NEITHER, FILE_READ_ACCESS) -/* BULK_SECURITY_TEST_DATA, */ -#define FSCTL_SECURITY_ID_CHECK \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 45, METHOD_NEITHER, FILE_READ_ACCESS) -/* READ_USN_JOURNAL_DATA, USN */ -#define FSCTL_READ_USN_JOURNAL \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 46, METHOD_NEITHER, FILE_READ_ACCESS) -#define FSCTL_SET_OBJECT_ID_EXTENDED \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 47, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* FILE_OBJECTID_BUFFER */ -#define FSCTL_CREATE_OR_GET_OBJECT_ID \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 48, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_SET_SPARSE \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_ANY_ACCESS) -/* FILE_ZERO_DATA_INFORMATION, */ -#define FSCTL_SET_ZERO_DATA \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 50, METHOD_BUFFERED, FILE_WRITE_ACCESS) -/* FILE_ALLOCATED_RANGE_BUFFER, FILE_ALLOCATED_RANGE_BUFFER */ -#define FSCTL_QUERY_ALLOCATED_RANGES \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 51, METHOD_NEITHER, FILE_READ_ACCESS) -#define FSCTL_ENABLE_UPGRADE \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 52, METHOD_BUFFERED, FILE_WRITE_ACCESS) -/* ENCRYPTION_BUFFER, */ -#define FSCTL_SET_ENCRYPTION \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 53, METHOD_NEITHER, FILE_ANY_ACCESS) -#define FSCTL_ENCRYPTION_FSCTL_IO \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 54, METHOD_NEITHER, FILE_ANY_ACCESS) -/* ENCRYPTED_DATA_INFO, */ -#define FSCTL_WRITE_RAW_ENCRYPTED \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 55, METHOD_NEITHER, FILE_ANY_ACCESS) -/* REQUEST_RAW_ENCRYPTED_DATA, ENCRYPTED_DATA_INFO */ -#define FSCTL_READ_RAW_ENCRYPTED \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 56, METHOD_NEITHER, FILE_ANY_ACCESS) -/* CREATE_USN_JOUNRAL_DATA, */ -#define FSCTL_CREATE_USN_JOURNAL \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 57, METHOD_NEITHER, FILE_READ_ACCESS) -/* Read the Usn Record for a file */ -#define FSCTL_READ_FILE_USN_DATA \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 58, METHOD_NEITHER, FILE_ANY_ACCESS) -/* Generate Close Usn Record */ -#define FSCTL_WRITE_USN_CLOSE_RECORD \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 59, METHOD_NEITHER, FILE_ANY_ACCESS) -#define FSCTL_EXTEND_VOLUME \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 60, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_SIS_COPYFILE \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 64, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_RECALL_FILE \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 69, METHOD_NEITHER, FILE_ANY_ACCESS) -#define FSCTL_SET_DEFECT_MANAGEMENT \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 77, METHOD_BUFFERED, FILE_WRITE_ACCESS) -#define FSCTL_QUERY_SPARING_INFO \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 78, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_QUERY_ON_DISK_VOLUME_INFO \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 79, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_SET_ZERO_ON_DEALLOCATION \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 101, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_SET_SHORT_NAME_BEHAVIOR \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 109, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_FILE_LEVEL_TRIM \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 130, METHOD_BUFFERED, FILE_WRITE_ACCESS) -#define FSCTL_OFFLOAD_READ \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 153, METHOD_BUFFERED, FILE_READ_ACCESS) -#define FSCTL_OFFLOAD_WRITE \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 154, METHOD_BUFFERED, FILE_WRITE_ACCESS) -#define FSCTL_GET_INTEGRITY_INFORMATION \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 159, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_SET_INTEGRITY_INFORMATION \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 160, METHOD_BUFFERED, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -/* FILE_DEVICE_NETWORK_FILE_SYSTEM */ -/* Read the snapshot info for Volume Shadow Copy Services */ -#define FSCTL_SRV_ENUMERATE_SNAPSHOTS \ - CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x19, \ - METHOD_BUFFERED, FILE_READ_ACCESS) -/* Retrieve an opaque file reference for server-side data movement */ -#define FSCTL_SRV_REQUEST_RESUME_KEY \ - CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x1e, \ - METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_LMR_GET_LINK_TRACKING_INFORMATION \ - CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x3a, \ - METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_LMR_SET_LINK_TRACKING_INFORMATION \ - CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x3b, \ - METHOD_BUFFERED, FILE_ANY_ACCESS) -/* server-side data movement */ -#define FSCTL_SRV_COPYCHUNK \ - CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x3c, \ - METHOD_OUT_DIRECT, FILE_READ_ACCESS) -/* server-side data movement */ -#define FSCTL_SRV_COPYCHUNK_WRITE \ - CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x3c, \ - METHOD_OUT_DIRECT, FILE_WRITE_ACCESS) -#define FSCTL_SRV_NOTIFY_TRANSACTION \ - CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x46, \ - METHOD_BUFFERED, FILE_WRITE_ACCESS) -#define FSCTL_SRV_READ_HASH \ - CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x6e, \ - METHOD_NEITHER, FILE_READ_ACCESS) -#define FSCTL_SRV_UNKNOWN_x71 \ - CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x71, \ - METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_LMR_REQUEST_RESILIENCY \ - CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x75, \ - METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_QUERY_NETWORK_INTERFACE_INFO \ - CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x7f, \ - METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_VALIDATE_NEGOTIATE_INFO \ - CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x81, \ - METHOD_BUFFERED, FILE_ANY_ACCESS) - -/* FILE_DEVICE_DFS */ -#define FSCTL_DFS_GET_REFERRALS \ - CTL_CODE(FILE_DEVICE_DFS, 0x65, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_DFS_GET_REFERRALS_EX \ - CTL_CODE(FILE_DEVICE_DFS, 0x6c, METHOD_BUFFERED, FILE_ANY_ACCESS) - -/* FILE_DEVICE_NAMED_PIPE */ -#define FSCTL_PIPE_PEEK \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 3, METHOD_BUFFERED, FILE_READ_ACCESS) -#define FSCTL_PIPE_TRANSCEIVE \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 5, METHOD_NEITHER, \ - FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define FSCTL_PIPE_WAIT \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 6, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#endif /* _FILESYSTEMFSCTL_ */ - -#ifdef __cplusplus -} -#endif - -#endif /* _SMBSRV_WINIOCTL_H */ diff --git a/usr/src/uts/intel/nsmb/ioc_check.ref b/usr/src/uts/intel/nsmb/ioc_check.ref index e966bfdef5..7476bc696d 100644 --- a/usr/src/uts/intel/nsmb/ioc_check.ref +++ b/usr/src/uts/intel/nsmb/ioc_check.ref @@ -3,10 +3,12 @@ #define ID_DOMAIN_INCR 0x1 #define ID_USER 0x120 #define ID_USER_INCR 0x1 -#define SSN_VOPT 0x0 -#define SSN_OWNER 0x4 -#define SSN_ID 0x8 -#define SSN_SRVNAME 0x228 +#define SSN_OWNER 0x0 +#define SSN_VOPT 0x4 +#define SSN_MINVER 0x8 +#define SSN_MAXVER 0xa +#define SSN_ID 0xc +#define SSN_SRVNAME 0x22c #define SSN_SRVNAME_INCR 0x1 #define SH_USE 0x0 #define SH_TYPE 0x4 @@ -24,20 +26,20 @@ #define WK_U_AUTH_WLEN 0x14 #define WK_U_AUTH_RBUF 0x18 #define WK_U_AUTH_WBUF 0x20 -#define WK_SSN_KEY 0x28 -#define WK_SSN_KEY_INCR 0x1 -#define SIZEOF_SMBIOC_XNP 0x20 -#define IOC_FH 0x0 -#define IOC_TDLEN 0x4 -#define IOC_RDLEN 0x8 -#define IOC_MORE 0xc -#define _IOC_TDATA 0x10 -#define _IOC_RDATA 0x18 +#define WK_CL_GUID 0x28 +#define WK_CL_GUID_INCR 0x1 #define SIZEOF_SMBIOC_RW 0x18 -#define IOC_FH 0x0 -#define IOC_CNT 0x4 +#define IOC_CNT 0x0 +#define IOC_FLAGS 0x4 #define _IOC_OFFSET 0x8 #define _IOC_BASE 0x10 +#define SIZEOF_SMBIOC_XNP 0x20 +#define IOC_TDLEN 0x0 +#define IOC_RDLEN 0x4 +#define IOC_MORE 0x8 +#define IOC_PAD1 0xc +#define _IOC_TDATA 0x10 +#define _IOC_RDATA 0x18 #define SIZEOF_NTCREATE 0x114 #define IOC_REQ_ACC 0x0 #define IOC_EFATTR 0x4 diff --git a/usr/src/uts/sparc/nsmb/ioc_check.ref b/usr/src/uts/sparc/nsmb/ioc_check.ref index e966bfdef5..7476bc696d 100644 --- a/usr/src/uts/sparc/nsmb/ioc_check.ref +++ b/usr/src/uts/sparc/nsmb/ioc_check.ref @@ -3,10 +3,12 @@ #define ID_DOMAIN_INCR 0x1 #define ID_USER 0x120 #define ID_USER_INCR 0x1 -#define SSN_VOPT 0x0 -#define SSN_OWNER 0x4 -#define SSN_ID 0x8 -#define SSN_SRVNAME 0x228 +#define SSN_OWNER 0x0 +#define SSN_VOPT 0x4 +#define SSN_MINVER 0x8 +#define SSN_MAXVER 0xa +#define SSN_ID 0xc +#define SSN_SRVNAME 0x22c #define SSN_SRVNAME_INCR 0x1 #define SH_USE 0x0 #define SH_TYPE 0x4 @@ -24,20 +26,20 @@ #define WK_U_AUTH_WLEN 0x14 #define WK_U_AUTH_RBUF 0x18 #define WK_U_AUTH_WBUF 0x20 -#define WK_SSN_KEY 0x28 -#define WK_SSN_KEY_INCR 0x1 -#define SIZEOF_SMBIOC_XNP 0x20 -#define IOC_FH 0x0 -#define IOC_TDLEN 0x4 -#define IOC_RDLEN 0x8 -#define IOC_MORE 0xc -#define _IOC_TDATA 0x10 -#define _IOC_RDATA 0x18 +#define WK_CL_GUID 0x28 +#define WK_CL_GUID_INCR 0x1 #define SIZEOF_SMBIOC_RW 0x18 -#define IOC_FH 0x0 -#define IOC_CNT 0x4 +#define IOC_CNT 0x0 +#define IOC_FLAGS 0x4 #define _IOC_OFFSET 0x8 #define _IOC_BASE 0x10 +#define SIZEOF_SMBIOC_XNP 0x20 +#define IOC_TDLEN 0x0 +#define IOC_RDLEN 0x4 +#define IOC_MORE 0x8 +#define IOC_PAD1 0xc +#define _IOC_TDATA 0x10 +#define _IOC_RDATA 0x18 #define SIZEOF_NTCREATE 0x114 #define IOC_REQ_ACC 0x0 #define IOC_EFATTR 0x4 -- cgit v1.2.3