diff options
author | Gordon Ross <gwr@nexenta.com> | 2018-01-20 12:23:17 -0500 |
---|---|---|
committer | Gordon Ross <gwr@nexenta.com> | 2019-03-14 10:38:30 -0400 |
commit | 40c0e2317898b8c774791bdc2b30bd50111ab1fa (patch) | |
tree | f19033aaf4c50e0e14c5b4a0b826616bea923534 /usr/src | |
parent | 8329232e00f1048795bae53acb230316243aadb5 (diff) | |
download | illumos-gate-40c0e2317898b8c774791bdc2b30bd50111ab1fa.tar.gz |
9875 SMB client connection setup rework
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Approved by: Joshua M. Clulow <josh@sysmgr.org>
Diffstat (limited to 'usr/src')
43 files changed, 1848 insertions, 4207 deletions
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 <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <netsmb/mchain.h> /* letohs, etc. */ -#include <netsmb/smb.h> -#include <netsmb/smb_lib.h> -#include <netsmb/smb_rap.h> - -#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 <sys/types.h> @@ -51,8 +51,6 @@ #include <netsmb/smb_lib.h> #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 <ikozhukhov@gmail.com> # -# 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 <netsmb/smb.h> #include <netsmb/smb_lib.h> +#include <netsmb/mchain.h> #include <netsmb/netbios.h> #include <netsmb/nb_lib.h> #include <netsmb/smb_dev.h> #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)); @@ -393,15 +138,6 @@ smb_iod_connect(smb_ctx_t *ctx) 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 <sys/param.h> @@ -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); @@ -1122,6 +1097,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. * XXX: Only for auth NTLM? @@ -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 <sys/param.h> @@ -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 <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <libintl.h> -#include <xti.h> -#include <assert.h> - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/poll.h> - -#include <netsmb/netbios.h> -#include <netsmb/smb_lib.h> -#include <netsmb/nb_lib.h> -#include <netsmb/mchain.h> - -#include "private.h" -#include "charsets.h" - -static int nb_ssn_send(struct smb_ctx *, struct mbdata *, int, int); -static int nb_ssn_recv(struct smb_ctx *, struct mbdata *, int *, int *); -static int nb_ssn_pollin(struct smb_ctx *, int); - -/* - * Send a data message. - */ -int -smb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp) -{ - return (nb_ssn_send(ctx, mbp, 0, mbp->mb_count)); -} - -/* - * Send a NetBIOS message, after - * prepending the 4-byte header. - */ -static int -nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp, - int mtype, int mlen) -{ - mbuf_t *m; - 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 <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <strings.h> -#include <netdb.h> -#include <libintl.h> -#include <xti.h> -#include <assert.h> - -#include <sys/types.h> -#include <sys/time.h> -#include <sys/byteorder.h> -#include <sys/socket.h> -#include <sys/fcntl.h> - -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> - -#include <netsmb/smb.h> -#include <netsmb/smb_lib.h> -#include <netsmb/netbios.h> -#include <netsmb/nb_lib.h> -#include <netsmb/smb_dev.h> - -#include "charsets.h" -#include "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) { @@ -650,37 +653,13 @@ out: } /* - * 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 @@ -61,60 +62,6 @@ extern void dprint(const char *, const char *, ...) #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. */ int m_getm(struct mbuf *, int, struct mbuf **); @@ -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 <sys/param.h> -#include <sys/errno.h> -#include <sys/stat.h> -#include <sys/isa_defs.h> - -#include <ctype.h> -#include <stdio.h> -#include <unistd.h> -#include <strings.h> -#include <stdlib.h> -#include <libintl.h> -#include <sysexits.h> - -#include <netsmb/mchain.h> -#include <netsmb/smb_lib.h> -#include <netsmb/smb_rap.h> -#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 <sys/types.h> -#include <sys/param.h> -#include <sys/ioctl.h> -#include <sys/errno.h> -#include <sys/stat.h> - -#include <ctype.h> -#include <errno.h> -#include <stdio.h> -#include <unistd.h> -#include <strings.h> -#include <stdlib.h> -#include <sysexits.h> -#include <libintl.h> - -#include <netsmb/smb.h> -#include <netsmb/smb_lib.h> -#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 <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <strings.h> - -#include <sys/types.h> -#include <sys/md5.h> - -#include <netsmb/mchain.h> -#include <netsmb/smb.h> -#include <netsmb/smb_lib.h> - -#include "private.h" - -#define SMBSIGOFF 14 /* SMB signature offset */ -#define SMBSIGLEN 8 /* SMB signature length */ - -/* - * Set this to a small number to debug sequence numbers - * that seem to get out of step. - */ -#ifdef DEBUG -int nsmb_signing_fudge = 4; -#endif - -/* - * Compute MD5 digest of packet data, using the stored MAC key. - * - * See similar code in the driver: - * uts/common/fs/smbclnt/netsmb/smb_signing.c - * and on the server side: - * uts/common/fs/smbsrv/smb_signing.c - */ -static int -smb_compute_MAC(struct smb_ctx *ctx, mbuf_t *m, - uint32_t seqno, uchar_t *signature) -{ - MD5_CTX md5; - uchar_t digest[MD5_DIGEST_LENGTH]; - - /* - * This union is a little bit of trickery to: - * (1) get the sequence number int aligned, and - * (2) reduce the number of digest calls, at the - * cost of a copying 32 bytes instead of 8. - * Both sides of this union are 2+32 bytes. - */ - union { - struct { - uint8_t skip[2]; /* not used - just alignment */ - uint8_t raw[SMB_HDRLEN]; /* header length (32) */ - } r; - struct { - uint8_t skip[2]; /* not used - just alignment */ - uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */ - uint32_t sig[2]; /* MAC signature, aligned! */ - uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */ - } s; - } smbhdr; - - if (m->m_len < SMB_HDRLEN) - return (EIO); - if (ctx->ct_mackey == NULL) - return (EINVAL); - - /* - * Make an aligned copy of the SMB header - * and fill in the sequence number. - */ - bcopy(m->m_data, smbhdr.r.raw, SMB_HDRLEN); - smbhdr.s.sig[0] = htolel(seqno); - smbhdr.s.sig[1] = 0; - - /* - * Compute the MAC: MD5(concat(Key, message)) - */ - MD5Init(&md5); - - /* Digest the MAC Key */ - MD5Update(&md5, ctx->ct_mackey, ctx->ct_mackeylen); - - /* Digest the (copied) SMB header */ - MD5Update(&md5, smbhdr.r.raw, SMB_HDRLEN); - - /* Digest the rest of the first mbuf */ - if (m->m_len > SMB_HDRLEN) { - MD5Update(&md5, m->m_data + SMB_HDRLEN, - m->m_len - SMB_HDRLEN); - } - m = m->m_next; - - /* Digest rest of the SMB message. */ - while (m) { - MD5Update(&md5, m->m_data, m->m_len); - m = m->m_next; - } - - /* Final */ - MD5Final(digest, &md5); - - /* - * Finally, store the signature. - * (first 8 bytes of the digest) - */ - if (signature) - bcopy(digest, signature, SMBSIGLEN); - - return (0); -} - -/* - * Sign a request with HMAC-MD5. - */ -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 <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <strings.h> -#include <netdb.h> -#include <libintl.h> -#include <xti.h> -#include <assert.h> - -#include <sys/types.h> -#include <sys/time.h> -#include <sys/byteorder.h> -#include <sys/socket.h> -#include <sys/fcntl.h> - -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> - -#include <netsmb/mchain.h> -#include <netsmb/netbios.h> -#include <netsmb/smb_dev.h> -#include <netsmb/smb.h> - -#include <netsmb/smb_lib.h> -#include <netsmb/nb_lib.h> - -#include "private.h" -#include "charsets.h" -#include "ntlm.h" -#include "smb_crypt.h" - - -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 @@ -146,6 +144,41 @@ typedef struct smb_connobj smb_connobj_t; #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, * because it has nothing to do with the SMB notion of a @@ -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 <sys/types.h> @@ -62,7 +62,7 @@ #include <sys/modctl.h> #include <sys/devops.h> #include <sys/thread.h> -#include <sys/types.h> +#include <sys/socket.h> #include <sys/zone.h> #include <netsmb/smb_osdep.h> @@ -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 <netsmb/smb_tran.h> #include <netsmb/smb_trantcp.h> +/* + * SMB messages are up to 64K. + * Let's leave room for two. + */ +static int smb_tcpsndbuf = 0x20000; +static int smb_tcprcvbuf = 0x20000; +static 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); @@ -565,21 +575,11 @@ 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 <sys/param.h> @@ -331,6 +332,34 @@ ok_out: } /* + * 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 * to figure out what value to fill in. @@ -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 <sys/param.h> @@ -58,40 +59,6 @@ #include <netsmb/smb_rq.h> #include <netsmb/smb_subr.h> -/* - * XXX:This conversion might not be fully MS-Compatible - * for calculating hashes. The output length may differ - * for some locales and needs to be handled from where - * the call is made. - */ -int -smb_toupper(const char *inbuf, char *outbuf, size_t outlen) -{ - int err = 0; - size_t inlen, inrem, outrem; - - inrem = inlen = strlen(inbuf); - outrem = outlen; - (void) u8_textprep_str((char *)inbuf, &inrem, outbuf, &outrem, - U8_TEXTPREP_TOUPPER, U8_UNICODE_LATEST, &err); - /* inrem, outrem are bytes unused, remaining */ - if (inrem) { - SMBSDEBUG("input %d remains: %s\n", (int)inrem, inbuf); - inlen -= inrem; - } - if (outrem) { - outlen -= outrem; - outbuf[outlen] = '\0'; - } - if (outlen > inlen) { - SMBSDEBUG("outlen > inlen! (%d > %d)\n", - (int)outlen, (int)inlen); - /* Truncate to inlen here? */ - } - - return (err); -} - void smb_credinit(struct smb_cred *scred, 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 <sys/param.h> @@ -74,13 +74,6 @@ #include <netsmb/smb_tran.h> #include <netsmb/smb_trantcp.h> -/* - * SMB messages are up to 64K. - * Let's leave room for two. - */ -static int smb_tcpsndbuf = 0x20000; -static int smb_tcprcvbuf = 0x20000; - static 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 <sys/param.h> @@ -61,28 +62,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 |