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/lib/libsmbfs | |
parent | 8329232e00f1048795bae53acb230316243aadb5 (diff) | |
download | illumos-joyent-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/lib/libsmbfs')
-rw-r--r-- | usr/src/lib/libsmbfs/Makefile.com | 8 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/netsmb/smb_lib.h | 34 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/connect.c | 603 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ctx.c | 52 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/file.c | 38 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/findvc.c | 3 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/getaddr.c | 17 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/iod_wk.c | 71 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/krb5ssp.c | 61 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/mapfile-vers | 12 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/nb_ssn.c | 336 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/negprot.c | 457 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ntlm.c | 47 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ntlm.h | 20 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ntlmssp.c | 113 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/private.h | 68 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/rap.c | 446 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/rq.c | 470 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/signing.c | 263 | ||||
-rw-r--r-- | usr/src/lib/libsmbfs/smb/ssnsetup.c | 459 |
20 files changed, 425 insertions, 3153 deletions
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); -} |