diff options
Diffstat (limited to 'usr/src/lib/libsmbfs')
33 files changed, 1079 insertions, 3307 deletions
diff --git a/usr/src/lib/libsmbfs/Makefile.com b/usr/src/lib/libsmbfs/Makefile.com index 160494aff1..be5ad05c42 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,16 @@ 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 \ + rc_scf.o \ spnego.o \ spnegoparse.o \ - ssnsetup.o \ ssp.o \ subr.o \ ui-sun.o \ @@ -95,7 +90,7 @@ $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) CSTD= $(CSTD_GNU99) -LDLIBS += -lsocket -lnsl -lc -lmd -lpkcs11 -lkrb5 -lsec -lidmap +LDLIBS += -lsocket -lnsl -lc -lmd -lpkcs11 -lkrb5 -lsec -lidmap -lscf -luuid # normal warnings... CFLAGS += $(CCVERBOSE) @@ -111,23 +106,21 @@ CPPFLAGS += -D__EXTENSIONS__ -D_REENTRANT -DMIA \ -I$(SRC)/uts/common \ -I$(SRC)/common/smbclnt +# This is pretty mature code, so let's just ignore these. +LINTCHECKFLAGS += -erroff=E_INCONS_ARG_DECL2 +LINTCHECKFLAGS += -erroff=E_INCONS_VAL_TYPE_DECL2 +LINTCHECKFLAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2 +LINTCHECKFLAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2 + # Debugging ${NOT_RELEASE_BUILD} CPPFLAGS += -DDEBUG -# Filter out the less important lint. -# See lgrep.awk -LGREP = $(AWK) -f $(SRCDIR)/lgrep.awk -LTAIL += 2>&1 | $(LGREP) - all: $(LIBS) -lint: lintcheck_t +lint: lintcheck include ../../Makefile.targ -lintcheck_t: $$(SRCS) - $(LINT.c) $(LINTCHECKFLAGS) $(SRCS) $(LDLIBS) $(LTAIL) - objs/%.o pics/%.o: $(CMNDIR)/%.c $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) diff --git a/usr/src/lib/libsmbfs/cflib.h b/usr/src/lib/libsmbfs/cflib.h index 0e8d6b57ee..85db96fcfd 100644 --- a/usr/src/lib/libsmbfs/cflib.h +++ b/usr/src/lib/libsmbfs/cflib.h @@ -35,6 +35,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _CFLIB_H_ @@ -85,6 +87,8 @@ int cf_getopt(int, char * const *, const char *); void cf_opt_lock(void); void cf_opt_unlock(void); +char *cf_get_client_uuid(void); + int rc_getstringptr(struct rcfile *, const char *, const char *, char **); int rc_getstring(struct rcfile *, const char *, const char *, size_t, char *); int rc_getint(struct rcfile *, const char *, const char *, int *); diff --git a/usr/src/lib/libsmbfs/netsmb/smb_lib.h b/usr/src/lib/libsmbfs/netsmb/smb_lib.h index c1dc6886ac..ae71332e97 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 2013 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; }; @@ -133,25 +126,20 @@ struct smb_ctx { */ #define ct_ssn ct_iod_ssn.iod_ossn #define ct_vopt ct_iod_ssn.iod_ossn.ssn_vopt +#define ct_minver ct_iod_ssn.iod_ossn.ssn_minver +#define ct_maxver ct_iod_ssn.iod_ossn.ssn_maxver #define ct_owner ct_iod_ssn.iod_ossn.ssn_owner #define ct_srvaddr ct_iod_ssn.iod_ossn.ssn_srvaddr #define ct_domain ct_iod_ssn.iod_ossn.ssn_domain -#define ct_user ct_iod_ssn.iod_ossn.ssn_user -#define ct_srvname ct_iod_ssn.iod_ossn.ssn_srvname +#define ct_user ct_iod_ssn.iod_ossn.ssn_user +#define ct_srvname ct_iod_ssn.iod_ossn.ssn_srvname #define ct_authflags ct_iod_ssn.iod_authflags #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 +157,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 */ /* @@ -181,6 +167,8 @@ struct smb_ctx { int smb_ctx_init(struct smb_ctx *); void smb_ctx_done(struct smb_ctx *); int smb_open_driver(void); +int nsmb_ioctl(int, int, void *); +int nsmb_close(int); int smb_ctx_gethandle(struct smb_ctx *); int smb_ctx_findvc(struct smb_ctx *); @@ -208,6 +196,9 @@ int smb_iod_work(struct smb_ctx *); int smb_open_rcfile(char *); void smb_close_rcfile(void); +int smb_cf_minauth_from_str(char *); +int smb_cf_version_from_str(char *); + void smb_simplecrypt(char *dst, const char *src); int smb_simpledecrypt(char *dst, const char *src); diff --git a/usr/src/lib/libsmbfs/netsmb/smbfs_api.h b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h index b1f4b1e198..7b87b571ff 100644 --- a/usr/src/lib/libsmbfs/netsmb/smbfs_api.h +++ b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h @@ -22,7 +22,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #ifndef _NETSMB_SMBFS_API_H @@ -48,7 +49,7 @@ extern "C" { * EAUTH is used for CIFS authentication errors. */ #ifndef EBADRPC -#define EBADRPC 113 +#define EBADRPC 113 #endif #ifndef EAUTH #define EAUTH 114 @@ -122,6 +123,8 @@ int smb_ctx_setauthflags(struct smb_ctx *, int); int smb_ctx_setcharset(struct smb_ctx *, const char *); int smb_ctx_setfullserver(struct smb_ctx *, const char *); int smb_ctx_setsigning(struct smb_ctx *, int ena, int req); +int smb_ctx_setminver(struct smb_ctx *, int ver); +int smb_ctx_setmaxver(struct smb_ctx *, int ver); int smb_ctx_setnbflags(struct smb_ctx *, int ena, int bcast); int smb_ctx_setscope(struct smb_ctx *, const char *); diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip index aa3d6ad7e1..35fdfd0404 100644 --- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip @@ -1 +1 @@ -PORTIONS OF LIBSMBFS IN CIFS CLIENT +PORTIONS OF LIBSMBFS IN SMB CLIENT diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip index d7cc9ebbd7..35fdfd0404 100644 --- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip @@ -1 +1 @@ -CIFS CLIENT SOFTWARE +PORTIONS OF LIBSMBFS IN SMB CLIENT diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip index aa3d6ad7e1..35fdfd0404 100644 --- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip @@ -1 +1 @@ -PORTIONS OF LIBSMBFS IN CIFS CLIENT +PORTIONS OF LIBSMBFS IN SMB CLIENT diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip index aa3d6ad7e1..35fdfd0404 100644 --- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip +++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip @@ -1 +1 @@ -PORTIONS OF LIBSMBFS IN CIFS CLIENT +PORTIONS OF LIBSMBFS IN SMB CLIENT diff --git a/usr/src/lib/libsmbfs/smb/acl_api.c b/usr/src/lib/libsmbfs/smb/acl_api.c index 052539316b..92a3262f79 100644 --- a/usr/src/lib/libsmbfs/smb/acl_api.c +++ b/usr/src/lib/libsmbfs/smb/acl_api.c @@ -22,6 +22,8 @@ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ /* @@ -83,6 +85,7 @@ smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp) return (error); m = mbp->mb_top; + bzero(&iocb, sizeof (iocb)); iocb.addr = mtod(m, uintptr_t); iocb.alloc = m->m_maxlen; iocb.used = 0; @@ -91,7 +94,7 @@ smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp) /* * This does the OTW Get. */ - if (ioctl(fd, SMBFSIO_GETSD, &iocb) < 0) { + if (nsmb_ioctl(fd, SMBFSIO_GETSD, &iocb) < 0) { error = errno; goto errout; } @@ -120,6 +123,7 @@ smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp) if (mbp->mb_top != m) mb_initm(mbp, m); + bzero(&iocb, sizeof (iocb)); iocb.addr = mtod(m, uintptr_t); iocb.alloc = m->m_maxlen; iocb.used = m->m_len; @@ -128,7 +132,7 @@ smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp) /* * This does the OTW Set. */ - if (ioctl(fd, SMBFSIO_SETSD, &iocb) < 0) + if (nsmb_ioctl(fd, SMBFSIO_SETSD, &iocb) < 0) error = errno; return (error); diff --git a/usr/src/lib/libsmbfs/smb/connect.c b/usr/src/lib/libsmbfs/smb/connect.c index c2ccc3361d..c231fe0e8a 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. */ /* @@ -50,336 +51,89 @@ #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> +#include <uuid/uuid.h> #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 <cflib.h> + #include "charsets.h" #include "private.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); -} +#include "smb_crypt.h" 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); - } +smb__ssnsetup(struct smb_ctx *ctx, + struct mbdata *mbc1, struct mbdata *mbc2); - err = smb_setopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, 1); - if (err) { - DPRINT("set SO_KEEPALIVE, err %d", err); - } +int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *); - 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) +const char * +smb_iod_state_name(enum smbiod_state st) { - 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); + const char *n = "(?)"; - 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); - -errout: - close(fd); - return (err); -} - -/* - * 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) -{ - 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); - - 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); } /* * Make a new connection, or reconnect. + * + * This is called first from the door service thread in smbiod + * (so that can report success or failure to the door client) + * and thereafter it's called when we need to reconnect after a + * network outage (or whatever might cause connection loss). */ int smb_iod_connect(smb_ctx_t *ctx) { - struct sockaddr *sa; - int err, err2; + smbioc_ossn_t *ossn = &ctx->ct_ssn; + smbioc_ssn_work_t *work = &ctx->ct_work; + char *uuid_str; + int err; struct mbdata blob; + char *nego_buf = NULL; + uint32_t nego_len; memset(&blob, 0, sizeof (blob)); @@ -393,15 +147,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. */ @@ -415,114 +160,235 @@ smb_iod_connect(smb_ctx_t *ctx) } /* + * Get local machine uuid. + */ + uuid_str = cf_get_client_uuid(); + if (uuid_str == NULL) { + err = EINVAL; + smb_error(dgettext(TEXT_DOMAIN, + "can't get local UUID"), err); + return (err); + } + (void) uuid_parse(uuid_str, ctx->ct_work.wk_cl_guid); + free(uuid_str); + uuid_str = NULL; + + /* * We're called with each IP address * already copied into ct_srvaddr. */ 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 { + 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); +} + +/* + * smb_ssnsetup_spnego + * + * This does an SMB session setup sequence using SPNEGO. + * The state changes seen during this sequence are there + * just to help track what's going on. + */ +int +smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb) +{ + 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) { + DPRINT("smb__ssnsetup, ssp next, err=%d", err); + goto out; + } + for (;;) { + err = smb__ssnsetup(ctx, &send_mb, &recv_mb); + DPRINT("smb__ssnsetup rc=%d, new state=%s", err, + smb_iod_state_name(work->wk_out_state)); + + if (err == 0) { + /* + * Session setup complete w/ success. + * Should have state AUTHOK + */ + if (work->wk_out_state != SMBIOD_ST_AUTHOK) { + DPRINT("Wrong state (expected AUTHOK)"); + } + break; + } + + if (err != EINPROGRESS) { /* - * Don't return EAUTH, because a new - * password prompt will not help. + * Session setup complete w/ failure. + * Should have state AUTHFAIL */ - DPRINT("No NTLM authflags"); - err = ENOTSUP; + if (work->wk_out_state != SMBIOD_ST_AUTHFAIL) { + DPRINT("Wrong state (expected AUTHFAIL)"); + } + goto out; + } + + /* + * err == EINPROGRESS + * Session setup continuing. + * Should have state AUTHCONT + */ + if (work->wk_out_state != SMBIOD_ST_AUTHCONT) { + DPRINT("Wrong state (expected 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; } } + /* + * Only get here via break in the err==0 case above, + * so we're finalizing a successful session setup. + * + * NULL output token here indicates the final call. + */ + (void) ssp_ctx_next_token(ctx, &recv_mb, NULL); + + /* + * The session key is in ctx->ct_ssnkey_buf + * (a.k.a. ct_work.wk_u_ssn_key_buf) + */ + out: - mb_done(&blob); + /* Done with ctx->ct_ssp_ctx */ + ssp_ctx_destroy(ctx); - 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); + 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 9455a92344..3aa67fd5f5 100644 --- a/usr/src/lib/libsmbfs/smb/ctx.c +++ b/usr/src/lib/libsmbfs/smb/ctx.c @@ -34,7 +34,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 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"); @@ -169,6 +165,8 @@ dump_iod_ssn(smb_iod_ssn_t *is) ssn->ssn_domain, ssn->ssn_user); printf(" ct_vopt=0x%x, ct_owner=%d\n", ssn->ssn_vopt, ssn->ssn_owner); + printf(" ct_minver=0x%x, ct_maxver=0x%x\n", + ssn->ssn_minver, ssn->ssn_maxver); printf(" ct_authflags=0x%x\n", is->iod_authflags); printf(" ct_nthash:"); @@ -254,16 +252,16 @@ 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; + ctx->ct_maxver = SMB2_DIALECT_MAX; /* * Default domain, user, ... @@ -333,7 +331,12 @@ smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv, cf_opt_lock(); /* Careful: no return/goto before cf_opt_unlock! */ while (error == 0) { - opt = cf_getopt(argc, argv, STDPARAM_OPT); + /* + * Leading ':' tells this to skip unknown opts. + * Just get -A and -U here so we know the user + * for config file parsing. + */ + opt = cf_getopt(argc, argv, ":AU:"); if (opt == -1) break; arg = cf_optarg; @@ -398,17 +401,13 @@ smb_ctx_done(struct smb_ctx *ctx) rpc_cleanup_smbctx(ctx); if (ctx->ct_dev_fd != -1) { - close(ctx->ct_dev_fd); + nsmb_close(ctx->ct_dev_fd); ctx->ct_dev_fd = -1; } if (ctx->ct_door_fd != -1) { 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; @@ -441,17 +440,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; } } @@ -868,6 +859,37 @@ smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require) return (0); } +/* + * Handle .nsmbrc "minver" option. + * Must be <= maxver + */ +int +smb_ctx_setminver(struct smb_ctx *ctx, int ver) +{ + if (ver < 0 || ver > ctx->ct_maxver) + return (EINVAL); + ctx->ct_minver = (uint16_t)ver; + return (0); +} + +/* + * Handle .nsmbrc "maxver" option. + * Must be >= minver + * + * Any "too high" value is just clamped, so the caller + * doesn't need to know what's the highest we support. + */ +int +smb_ctx_setmaxver(struct smb_ctx *ctx, int ver) +{ + if (ver < 1 || ver < ctx->ct_minver) + return (EINVAL); + if (ver > SMB2_DIALECT_MAX) + ver = SMB2_DIALECT_MAX; + ctx->ct_maxver = (uint16_t)ver; + return (0); +} + static int smb_parse_owner(char *pair, uid_t *uid, gid_t *gid) { @@ -899,12 +921,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 }, @@ -930,13 +951,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); @@ -1117,6 +1131,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? @@ -1127,13 +1154,18 @@ smb_ctx_resolve(struct smb_ctx *ctx) * If we don't have a p/w yet, * try the keychain. */ - if (ctx->ct_password[0] == '\0') - (void) smb_get_keychain(ctx); + if (ctx->ct_password[0] == '\0' && + smb_get_keychain(ctx) == 0) { + strlcpy(ctx->ct_password, "$HASH", + sizeof (ctx->ct_password)); + } + /* * Mask out disallowed auth types. */ ctx->ct_authflags &= ctx->ct_minauth; } + if (ctx->ct_authflags == 0) { smb_error(dgettext(TEXT_DOMAIN, "no valid auth. types"), 0); @@ -1147,6 +1179,10 @@ smb_ctx_resolve(struct smb_ctx *ctx) return (0); } +/* + * Note: The next three have NODIRECT binding so the + * "fksmbcl" development tool can provide its own. + */ int smb_open_driver() { @@ -1164,6 +1200,19 @@ smb_open_driver() } int +nsmb_close(int fd) +{ + return (close(fd)); +} + +int +nsmb_ioctl(int fd, int cmd, void *arg) +{ + return (ioctl(fd, cmd, arg)); +} + + +int smb_ctx_gethandle(struct smb_ctx *ctx) { int fd, err; @@ -1171,9 +1220,8 @@ smb_ctx_gethandle(struct smb_ctx *ctx) if (ctx->ct_dev_fd != -1) { rpc_cleanup_smbctx(ctx); - close(ctx->ct_dev_fd); + nsmb_close(ctx->ct_dev_fd); ctx->ct_dev_fd = -1; - ctx->ct_flags &= ~SMBCF_SSNACTIVE; } fd = smb_open_driver(); @@ -1187,12 +1235,12 @@ smb_ctx_gethandle(struct smb_ctx *ctx) /* * Check the driver version (paranoia) */ - if (ioctl(fd, SMBIOC_GETVERS, &version) < 0) + if (nsmb_ioctl(fd, SMBIOC_GETVERS, &version) < 0) version = 0; if (version != NSMB_VERSION) { smb_error(dgettext(TEXT_DOMAIN, "incorrect driver version"), 0); - close(fd); + nsmb_close(fd); return (ENODEV); } @@ -1221,6 +1269,15 @@ smb_ctx_get_ssn(struct smb_ctx *ctx) DPRINT("found an existing VC"); } else { /* + * If we're authenticating (real user, not NULL session) + * and we don't yet have a password, return EAUTH and + * the caller will prompt for it and call again. + */ + if (ctx->ct_user[0] != '\0' && + ctx->ct_password[0] == '\0') + return (EAUTH); + + /* * This calls the IOD to create a new session. */ DPRINT("setup a new VC"); @@ -1272,7 +1329,7 @@ smb_ctx_get_tree(struct smb_ctx *ctx) * * The driver does the actual TCON call. */ - if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) { + if (nsmb_ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) { err = errno; goto out; } @@ -1303,7 +1360,7 @@ smb_ctx_flags2(struct smb_ctx *ctx) { uint16_t flags2; - if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) { + if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) { smb_error(dgettext(TEXT_DOMAIN, "can't get flags2 for a session"), errno); return (-1); @@ -1321,7 +1378,7 @@ smb_fh_getssnkey(int dev_fd, uchar_t *key, size_t len) if (len < SMBIOC_HASH_SZ) return (EINVAL); - if (ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1) + if (nsmb_ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1) return (errno); return (0); @@ -1343,6 +1400,35 @@ minauth_table[] = { { NULL } }; +int +smb_cf_minauth_from_str(char *str) +{ + struct nv *nvp; + + for (nvp = minauth_table; nvp->name; nvp++) + if (strcmp(nvp->name, str) == 0) + return (nvp->value); + return (-1); +} + + +static struct nv +smbver_table[] = { + { "2.1", SMB2_DIALECT_0210 }, + { "1", 1 }, + { NULL, 0 } +}; + +int +smb_cf_version_from_str(char *str) +{ + struct nv *nvp; + + for (nvp = smbver_table; nvp->name; nvp++) + if (strcmp(nvp->name, str) == 0) + return (nvp->value); + return (-1); +} /* * level values: @@ -1355,7 +1441,9 @@ static int smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) { char *p; + int ival; int error; + int minver, maxver; #ifdef KICONV_SUPPORT if (level > 0) { @@ -1373,19 +1461,79 @@ smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) if (level <= 1) { /* Section is: [default] or [server] */ + /* + * Handle min_protocol, max_protocol + * (SMB protocol versions) + */ + minver = -1; + rc_getstringptr(smb_rc, sname, "min_protocol", &p); + if (p != NULL) { + minver = smb_cf_version_from_str(p); + if (minver == -1) { + smb_error(dgettext(TEXT_DOMAIN, +"invalid min_protocol value \"%s\" specified in the section %s"), + 0, p, sname); + } + } + maxver = -1; + rc_getstringptr(smb_rc, sname, "max_protocol", &p); + if (p != NULL) { + maxver = smb_cf_version_from_str(p); + if (maxver == -1) { + smb_error(dgettext(TEXT_DOMAIN, +"invalid max_protocol value \"%s\" specified in the section %s"), + 0, p, sname); + } + } + + /* + * If setting both min/max protocol, + * validate against each other + */ + if (minver != -1 && maxver != -1) { + if (minver > maxver) { + smb_error(dgettext(TEXT_DOMAIN, +"invalid min/max protocol combination in the section %s"), + 0, sname); + } else { + ctx->ct_minver = minver; + ctx->ct_maxver = maxver; + } + } + + /* + * Setting just min or max, validate against + * current settings + */ + if (minver != -1) { + if (minver > ctx->ct_maxver) { + smb_error(dgettext(TEXT_DOMAIN, +"invalid min/max protocol combination in the section %s"), + 0, sname); + } else { + ctx->ct_minver = minver; + } + } + if (maxver != -1) { + if (maxver < ctx->ct_minver) { + smb_error(dgettext(TEXT_DOMAIN, +"invalid min/max protocol combination in the section %s"), + 0, sname); + } else { + ctx->ct_maxver = maxver; + } + } + rc_getstringptr(smb_rc, sname, "minauth", &p); if (p) { /* * "minauth" was set in this section; override * the current minimum authentication setting. */ - struct nv *nvp; - for (nvp = minauth_table; nvp->name; nvp++) - if (strcmp(p, nvp->name) == 0) - break; - if (nvp->name) - ctx->ct_minauth = nvp->value; - else { + ival = smb_cf_minauth_from_str(p); + if (ival != -1) { + ctx->ct_minauth = ival; + } else { /* * Unknown minimum authentication level. */ diff --git a/usr/src/lib/libsmbfs/smb/file.c b/usr/src/lib/libsmbfs/smb/file.c index 8ca9d2cee1..3d2a431142 100644 --- a/usr/src/lib/libsmbfs/smb/file.c +++ b/usr/src/lib/libsmbfs/smb/file.c @@ -33,9 +33,10 @@ */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include <sys/param.h> @@ -62,10 +63,16 @@ #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) { - return (close(fd)); + (void) nsmb_ioctl(fd, SMBIOC_CLOSEFH, NULL); + return (nsmb_close(fd)); } int @@ -96,7 +103,7 @@ smb_fh_ntcreate( goto errout; } from_fd = ctx->ct_dev_fd; - if (ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) { + if (nsmb_ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) { err = errno; goto errout; } @@ -111,7 +118,7 @@ smb_fh_ntcreate( ioc.ioc_share_acc = share_acc; ioc.ioc_open_disp = open_disp; ioc.ioc_creat_opts = create_opts; - if (ioctl(new_fd, SMBIOC_NTCREATE, &ioc) == -1) { + if (nsmb_ioctl(new_fd, SMBIOC_NTCREATE, &ioc) == -1) { err = errno; goto errout; } @@ -120,7 +127,7 @@ smb_fh_ntcreate( errout: if (new_fd != -1) - close(new_fd); + nsmb_close(new_fd); errno = err; return (-1); } @@ -210,11 +217,10 @@ smb_fh_read(int fd, off64_t offset, size_t count, struct smbioc_rw rwrq; bzero(&rwrq, sizeof (rwrq)); - rwrq.ioc_fh = -1; /* tell driver to supply this */ rwrq.ioc_base = dst; rwrq.ioc_cnt = count; rwrq.ioc_offset = offset; - if (ioctl(fd, SMBIOC_READ, &rwrq) == -1) { + if (nsmb_ioctl(fd, SMBIOC_READ, &rwrq) == -1) { return (-1); } return (rwrq.ioc_cnt); @@ -227,11 +233,10 @@ smb_fh_write(int fd, off64_t offset, size_t count, struct smbioc_rw rwrq; bzero(&rwrq, sizeof (rwrq)); - rwrq.ioc_fh = -1; /* tell driver to supply this */ rwrq.ioc_base = (char *)src; rwrq.ioc_cnt = count; rwrq.ioc_offset = offset; - if (ioctl(fd, SMBIOC_WRITE, &rwrq) == -1) { + if (nsmb_ioctl(fd, SMBIOC_WRITE, &rwrq) == -1) { return (-1); } return (rwrq.ioc_cnt); @@ -251,21 +256,23 @@ 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_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 63c6cce242..0e781f7099 100644 --- a/usr/src/lib/libsmbfs/smb/findvc.c +++ b/usr/src/lib/libsmbfs/smb/findvc.c @@ -22,6 +22,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* @@ -76,7 +78,7 @@ findvc(struct smb_ctx *ctx, struct addrinfo *ai) bzero(&ssn->ssn_srvaddr, sizeof (ssn->ssn_srvaddr)); bcopy(ai->ai_addr, &ssn->ssn_srvaddr, ai->ai_addrlen); - if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_FIND, ssn) == -1) + if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_FIND, ssn) == -1) return (errno); return (0); @@ -119,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); } } @@ -137,7 +138,7 @@ int smb_ctx_kill(struct smb_ctx *ctx) { - if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_KILL, NULL) == -1) + if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_KILL, NULL) == -1) return (errno); 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 53f3c515be..38e9d5e0de 100644 --- a/usr/src/lib/libsmbfs/smb/iod_wk.c +++ b/usr/src/lib/libsmbfs/smb/iod_wk.c @@ -20,9 +20,10 @@ */ /* - * Copyright 2012 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); - /* Calle 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,34 +84,35 @@ 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"); - if (ioctl(ctx->ct_dev_fd, - SMBIOC_IOD_IDLE, &vcst) == -1) { + DPRINT("Call _ioc_idle..."); + if (nsmb_ioctl(ctx->ct_dev_fd, + SMBIOC_IOD_IDLE, work) == -1) { err = errno; DPRINT("ioc_idle: err %d", err); goto out; } + DPRINT("Ret. from _ioc_idle"); 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 @@ -119,64 +120,57 @@ smb_iod_work(smb_ctx_t *ctx) * will need to run smbutil to get * a new thread with new auth info. */ - if (err == EAUTH) + if (err == EAUTH) { + DPRINT("iod_connect: EAUTH (give up)"); goto out; - 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. + * Reconnect failed. Notify any requests + * that we're not connected, and delay. + * Next state will be IDLE or RECONNECT. */ - if (ioctl(ctx->ct_dev_fd, - SMBIOC_IOD_RCFAIL, &vcst) == -1) { + DPRINT("Call _iod_rcfail..."); + if (nsmb_ioctl(ctx->ct_dev_fd, + 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"); - if (ioctl(ctx->ct_dev_fd, + 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; + DPRINT("Ret. from _ioc_work"); continue; case SMBIOD_ST_DEAD: - DPRINT("state: dead"); + DPRINT("got 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) { - close(ctx->ct_dev_fd); + nsmb_close(ctx->ct_dev_fd); ctx->ct_dev_fd = -1; } diff --git a/usr/src/lib/libsmbfs/smb/keychain.c b/usr/src/lib/libsmbfs/smb/keychain.c index fd9bcc9496..3a89fbd550 100644 --- a/usr/src/lib/libsmbfs/smb/keychain.c +++ b/usr/src/lib/libsmbfs/smb/keychain.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -128,7 +128,7 @@ smbfs_keychain_cmn( } err = 0; - if (ioctl(fd, cmd, &pk) < 0) { + if (nsmb_ioctl(fd, cmd, &pk) < 0) { err = errno; goto out; } @@ -142,7 +142,7 @@ smbfs_keychain_cmn( out: if (fd != -1) - close(fd); + nsmb_close(fd); return (err); } 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/lgrep.awk b/usr/src/lib/libsmbfs/smb/lgrep.awk deleted file mode 100644 index fe6e8fa0b9..0000000000 --- a/usr/src/lib/libsmbfs/smb/lgrep.awk +++ /dev/null @@ -1,68 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# Copyright 2012 Milan Jurik. All rights reserved. -# - -# This is a "lint tail" that removes all the -# uninteresting lines from our lint output. -# It's nawk because sed doesn't do (a|b). -# Also comments are easier here. - -# There's no lintlib for krb5 yet (CR 6911968) -/: Warning: -lkrb5 not found/ { next; } -/: Warning: library -lkrb5 not found/ { next; } - -# Kill noise from xti.h with _XOPEN_SOURCE vs not. (CR 6911717) -/: _xti_.* .E_INCONS_ARG_DECL2./ { next; } -/: _xti_.* .E_INCONS_ARG_USED2./ { next; } -/: _xti_.* .E_INCONS_VAL_TYPE_DECL2./ { next; } - -# This is third-party code we'd rather not "fix" -/\/spnego.c.* .E_STMT_NOT_REACHED./ { next; } - -# The mb_put/md_get functions are intentionally used both -# with and without return value checks. Not a concern. -/: mb_put_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } -/: md_get_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } - -# The rc_get* functions clear the out arg even on failure, -# so most callers don't need to check the return value. -/: rc_get[a-z]* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } - -# These have uninteresting return values, usually ignored. -/: (n|sm)b_ctx_readrcsection .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } -/: nls_str_(lower|upper) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } -/: rc_(close|freesect) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } - -# Other functions for which we often ignore return values. -/: [a-z]*close .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } -/: [a-z]*flush .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } -/: [a-z]*printf .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } -/: mem(cpy|move|set) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } -/: mutex_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } -/: str[ln]?(cat|cpy) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } - -{ print; } diff --git a/usr/src/lib/libsmbfs/smb/mapfile-vers b/usr/src/lib/libsmbfs/smb/mapfile-vers index 8f0c3905c6..a94b3bc6e1 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 2013 Nexenta Systems, Inc. All rights reserved. +# Copyright 2018 Nexenta Systems, Inc. All rights reserved. # # @@ -36,6 +36,11 @@ # MAPFILE HEADER END # +# +# Note that several things in here are NODIRECT so that the +# "fksmbcl" development tool can provide its own versions. +# + $mapfile_version 2 SYMBOL_VERSION SUNWprivate { @@ -60,6 +65,12 @@ SYMBOL_VERSION SUNWprivate { nls_str_toloc; nls_str_upper; + nsmb_close { FLAGS = NODIRECT }; + nsmb_ioctl { FLAGS = NODIRECT }; + + smb_cf_minauth_from_str; + smb_cf_version_from_str; + smb_close_rcfile; smb_ctx_alloc; @@ -72,6 +83,7 @@ SYMBOL_VERSION SUNWprivate { smb_ctx_gethandle; smb_ctx_init; smb_ctx_kill; + smb_ctx_newvc { FLAGS = NODIRECT }; smb_ctx_opt; smb_ctx_parseunc; smb_ctx_readrc; @@ -82,6 +94,8 @@ SYMBOL_VERSION SUNWprivate { smb_ctx_setauthflags; smb_ctx_setdomain; smb_ctx_setfullserver; + smb_ctx_setminver; + smb_ctx_setmaxver; smb_ctx_setnbflags; smb_ctx_setpassword; smb_ctx_setpwhash; @@ -108,25 +122,16 @@ SYMBOL_VERSION SUNWprivate { smb_getprogname; smb_iod_connect; smb_iod_door_path; - smb_iod_open_door; - smb_iod_start; + smb_iod_open_door { FLAGS = NODIRECT }; + smb_iod_start { FLAGS = NODIRECT }; smb_iod_work; smb_lib_init; + smb_open_driver { FLAGS = NODIRECT }; smb_open_printer; smb_open_rcfile; 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/print.c b/usr/src/lib/libsmbfs/smb/print.c index c59bef81b4..698dd8359f 100644 --- a/usr/src/lib/libsmbfs/smb/print.c +++ b/usr/src/lib/libsmbfs/smb/print.c @@ -1,5 +1,4 @@ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2000, Boris Popov * All rights reserved. * @@ -33,6 +32,10 @@ * $Id: print.c,v 1.1.1.3 2001/07/06 22:38:43 conrad Exp $ */ +/* + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + #include <sys/param.h> #include <sys/ioctl.h> #include <sys/time.h> @@ -54,12 +57,24 @@ #include "private.h" +/* + * Replacing invalid characters in print job titles: + * + * The spec. is unclear about what characters are allowed in a + * print job title (used with NtCreate) so out of caution this + * makes sure the title contains none of the characters that + * are known to be illegal in a file name component. + */ +static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS; + int smb_open_printer(struct smb_ctx *ctx, const char *title, int setuplen, int mode) { smbioc_printjob_t ioc; - int err, tlen, new_fd; + char *p; + int err, tlen; + int new_fd = -1; int32_t from_fd; tlen = strlen(title); @@ -75,7 +90,7 @@ smb_open_printer(struct smb_ctx *ctx, const char *title, if (new_fd < 0) return (errno); from_fd = ctx->ct_dev_fd; - if (ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) { + if (nsmb_ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) { err = errno; goto errout; } @@ -88,7 +103,15 @@ smb_open_printer(struct smb_ctx *ctx, const char *title, ioc.ioc_prmode = mode; strlcpy(ioc.ioc_title, title, SMBIOC_MAX_NAME); - if (ioctl(new_fd, SMBIOC_PRINTJOB, &ioc) == -1) { + /* + * The title is used in NtCreate so sanitize by + * replacing any illegal chars with spaces. + */ + for (p = ioc.ioc_title; *p != '\0'; p++) + if (strchr(invalid_chars, *p) != NULL) + *p = ' '; + + if (nsmb_ioctl(new_fd, SMBIOC_PRINTJOB, &ioc) == -1) { err = errno; goto errout; } @@ -96,7 +119,7 @@ smb_open_printer(struct smb_ctx *ctx, const char *title, return (new_fd); errout: - close(new_fd); + nsmb_close(new_fd); errno = err; return (-1); } 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/rc_scf.c b/usr/src/lib/libsmbfs/smb/rc_scf.c new file mode 100644 index 0000000000..477982c0c8 --- /dev/null +++ b/usr/src/lib/libsmbfs/smb/rc_scf.c @@ -0,0 +1,231 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + +/* + * Support functions for getting things libsmbfs needs + * from the SMF configuration (using libscf). + */ + +#include <sys/types.h> +#include <sys/queue.h> + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include <libscf.h> + +#include <cflib.h> +#include "rcfile_priv.h" + +#define IDMAP_SERVICE_FMRI "svc:/system/idmap" +#define IDMAP_PG_NAME "config" +#define MACHINE_UUID "machine_uuid" + +#define SMBC_DEFAULT_INSTANCE_FMRI "svc:/network/smb/client:default" + +scf_handle_t *_scf_handle_create_and_bind(scf_version_t ver); + +/* + * Get the "machine_uuid" from idmap, as a string (allocated) + */ +char * +cf_get_client_uuid(void) +{ + char val_buf[64]; + char *ret = NULL; + + scf_handle_t *h = NULL; + scf_service_t *svc = NULL; + scf_propertygroup_t *pg = NULL; + scf_property_t *prop = NULL; + scf_value_t *val = NULL; + + if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL) + goto out; + + if ((svc = scf_service_create(h)) == NULL || + (pg = scf_pg_create(h)) == NULL || + (prop = scf_property_create(h)) == NULL || + (val = scf_value_create(h)) == NULL) + goto out; + + if (scf_handle_decode_fmri(h, IDMAP_SERVICE_FMRI, + NULL, svc, NULL, NULL, NULL, 0) == -1) + goto out; + + + if (scf_service_get_pg(svc, IDMAP_PG_NAME, pg) != 0) + goto out; + if (scf_pg_get_property(pg, MACHINE_UUID, prop) != 0) + goto out; + if (scf_property_get_value(prop, val) != 0) + goto out; + if (scf_value_get_as_string(val, val_buf, sizeof (val_buf)) < 0) + goto out; + + ret = strdup(val_buf); + +out: + scf_value_destroy(val); + scf_property_destroy(prop); + scf_pg_destroy(pg); + scf_service_destroy(svc); + + if (h != NULL) + scf_handle_destroy(h); + + return (ret); +} + +/* + * Get the output of "sharectl get smbfs" into a file, without an + * actual fork/exec of sharectl. + * + * Each section of the smbfs settings are represented as an SMF + * property group with an "S-" prefix and a UUID, and the section + * name itself a property which can have a more flexible name than + * a property group name can have. + */ +int +rc_scf_get_sharectl(FILE *fp) +{ + char sect_name[256]; + char prop_name[256]; + char val_buf[1024]; + + scf_handle_t *h = NULL; + scf_service_t *svc = NULL; + scf_instance_t *inst = NULL; + scf_propertygroup_t *pg = NULL; + scf_property_t *prop = NULL; + scf_value_t *val = NULL; + scf_iter_t *pgiter = NULL; + scf_iter_t *propiter = NULL; + scf_iter_t *valiter = NULL; + int ret = -1; + + if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL) + goto out; + + if ((svc = scf_service_create(h)) == NULL || + (inst = scf_instance_create(h)) == NULL || + (pgiter = scf_iter_create(h)) == NULL || + (propiter = scf_iter_create(h)) == NULL || + (valiter = scf_iter_create(h)) == NULL || + (pg = scf_pg_create(h)) == NULL || + (prop = scf_property_create(h)) == NULL || + (val = scf_value_create(h)) == NULL) + goto out; + + if (scf_handle_decode_fmri(h, SMBC_DEFAULT_INSTANCE_FMRI, + NULL, svc, inst, NULL, NULL, 0) == -1) + goto out; + + if (scf_iter_instance_pgs_composed(pgiter, inst, NULL) == -1) + goto out; + while ((ret = scf_iter_next_pg(pgiter, pg)) == 1) { + /* + * Using prop_name array for pg name temporarily. + * Skip any property groups names other than "S-*". + */ + if (scf_pg_get_name(pg, prop_name, sizeof (prop_name)) < 0) + continue; + if (strncmp(prop_name, "S-", 2) != 0) + continue; + + /* + * Get the "section" name, which is a property of + * this property group. + */ + if (scf_pg_get_property(pg, "section", prop) != 0) + continue; + if (scf_property_get_value(prop, val) != 0) + continue; + if (scf_value_get_as_string(val, sect_name, + sizeof (sect_name)) < 0) + continue; + + /* + * Have an S-* property group with a "section" name. + * Print the section start. + */ + fprintf(fp, "[%s]\n", sect_name); + + /* + * Now print the remaining properties in this PG, + * but skip the special "section" (name) prop. + */ + if (scf_iter_pg_properties(propiter, pg) == -1) + goto out; + while ((ret = scf_iter_next_property(propiter, prop)) == 1) { + + if (scf_property_get_name(prop, prop_name, + sizeof (prop_name)) < 0) + continue; + + /* Skip the "section" prop. now */ + if (strcmp(prop_name, "section") == 0) + continue; + + if (scf_property_get_value(prop, val) != 0) + continue; + + if (scf_value_get_as_string(val, val_buf, + sizeof (val_buf)) < 0) + continue; + + fprintf(fp, "%s=%s\n", prop_name, val_buf); + } + } + ret = 0; + +out: + fflush(fp); + + scf_value_destroy(val); + scf_property_destroy(prop); + scf_pg_destroy(pg); + scf_iter_destroy(valiter); + scf_iter_destroy(propiter); + scf_iter_destroy(pgiter); + scf_instance_destroy(inst); + scf_service_destroy(svc); + + if (h != NULL) + scf_handle_destroy(h); + + return (ret); +} + +/* + * Simple test wrapper. Compile with: + * cc -o rc_scf_test -I.. -DTEST_MAIN rc_scf.c -lscf + */ +#ifdef TEST_MAIN +int +main(int argc, char **arv) +{ + char *s; + int rc; + + rc = rc_scf_get_sharectl(stdout); + printf("# rc=%d\n", rc); + return (0); +} +#endif /* TEST_MAIN */ diff --git a/usr/src/lib/libsmbfs/smb/rcfile.c b/usr/src/lib/libsmbfs/smb/rcfile.c index 22ca0fc420..d7ee2d15af 100644 --- a/usr/src/lib/libsmbfs/smb/rcfile.c +++ b/usr/src/lib/libsmbfs/smb/rcfile.c @@ -31,6 +31,9 @@ * * $Id: rcfile.c,v 1.1.1.2 2001/07/06 22:38:43 conrad Exp $ */ +/* + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ #include <fcntl.h> #include <sys/types.h> @@ -57,7 +60,6 @@ #define SMB_CFG_FILE "/etc/nsmb.conf" #define OLD_SMB_CFG_FILE "/usr/local/etc/nsmb.conf" #endif -#define SMBFS_SHARECTL_CMD "/usr/sbin/sharectl get smbfs" extern int smb_debug; @@ -147,37 +149,77 @@ rc_merge(const char *filename, struct rcfile **rcfile) } /* - * Like rc_open, but does popen of command: - * sharectl get smbfs + * Like rc_open, but creates a temporary file and + * reads the sharectl settings into it. + * The file is deleted when we close it. */ static int -rc_popen_cmd(const char *command, struct rcfile **rcfile) +rc_open_sharectl(struct rcfile **rcfile) { - struct rcfile *rcp; - FILE *f; + static char template[24] = "/tmp/smbfsXXXXXX"; + struct rcfile *rcp = NULL; + FILE *fp = NULL; + int err; + int fd = -1; assert(MUTEX_HELD(&rcfile_mutex)); - f = popen(command, "r"); - if (f == NULL) - return (errno); - insecure_nsmbrc = 0; + fd = mkstemp(template); + if (fd < 0) { + err = errno; + goto errout; + } + + fp = fdopen(fd, "w+"); + if (fp == NULL) { + err = errno; + close(fd); + goto errout; + } + fd = -1; /* The fp owns this fd now. */ + + /* + * Get smbfs sharectl settings into the file. + */ + if ((err = rc_scf_get_sharectl(fp)) != 0) + goto errout; rcp = malloc(sizeof (struct rcfile)); if (rcp == NULL) { - fclose(f); - return (ENOMEM); + err = ENOMEM; + goto errout; } bzero(rcp, sizeof (struct rcfile)); - rcp->rf_name = strdup(command); - rcp->rf_f = f; + + rcp->rf_name = strdup(template); + if (rcp->rf_name == NULL) { + err = ENOMEM; + goto errout; + } + rcp->rf_f = fp; + rcp->rf_flags = RCFILE_DELETE_ON_CLOSE; + SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); + insecure_nsmbrc = 0; rc_parse(rcp); *rcfile = rcp; /* fclose(f) in rc_close */ return (0); + +errout: + if (rcp != NULL) + free(rcp); + if (fp != NULL) { + fclose(fp); + fd = -1; + } + if (fd != -1) + close(fd); + + return (err); } + static int rc_close(struct rcfile *rcp) { @@ -186,6 +228,9 @@ rc_close(struct rcfile *rcp) mutex_lock(&rcfile_mutex); fclose(rcp->rf_f); + if (rcp->rf_flags & RCFILE_DELETE_ON_CLOSE) + (void) unlink(rcp->rf_name); + for (p = SLIST_FIRST(&rcp->rf_sect); p; ) { n = p; p = SLIST_NEXT(p, rs_next); @@ -343,11 +388,10 @@ set_value(struct rcfile *rcp, struct rcsection *rsp, struct rckey *rkp, { int now, new; #ifdef DEBUG - char *from; + char *from = "SMF"; - if (smb_debug) - from = (home_nsmbrc) ? - "user file" : "SMF"; + if (home_nsmbrc != 0) + from = "user file"; #endif if (strcmp(rkp->rk_name, "minauth") == 0) { @@ -485,7 +529,7 @@ rc_parse(struct rcfile *rcp) set_value(rcp, rsp, rkp, buf); state = stNewLine; rkp = NULL; - } /* while */ + } /* while */ if (c == EOF && state == stGetValue) { *next = 0; set_value(rcp, rsp, rkp, buf); @@ -661,8 +705,8 @@ smb_open_rcfile(char *home) fn = SMB_CFG_FILE; error = rc_open(fn, &smb_rc); #else - fn = SMBFS_SHARECTL_CMD; - error = rc_popen_cmd(fn, &smb_rc); + fn = "(sharectl get smbfs)"; + error = rc_open_sharectl(&smb_rc); #endif if (error != 0 && error != ENOENT) { /* Error from fopen. strerror is OK. */ diff --git a/usr/src/lib/libsmbfs/smb/rcfile_priv.h b/usr/src/lib/libsmbfs/smb/rcfile_priv.h index ef9e31d7fc..b239c77a67 100644 --- a/usr/src/lib/libsmbfs/smb/rcfile_priv.h +++ b/usr/src/lib/libsmbfs/smb/rcfile_priv.h @@ -30,9 +30,26 @@ * SUCH DAMAGE. */ +/* + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + +#ifndef _RCFILE_PRIV_H +#define _RCFILE_PRIV_H + +/* + * Private RC file support. + */ + +#include <sys/queue.h> + +#ifdef __cplusplus +extern "C" { +#endif + struct rckey { SLIST_ENTRY(rckey) rk_next; - char *rk_name; + char *rk_name; char *rk_value; }; @@ -52,3 +69,12 @@ struct rcfile { #define RCFILE_HOME_NSMBRC 1 #define RCFILE_IS_INSECURE 2 +#define RCFILE_DELETE_ON_CLOSE 4 + +int rc_scf_get_sharectl(FILE *); + +#ifdef __cplusplus +} +#endif + +#endif /* _RCFILE_PRIV_H */ diff --git a/usr/src/lib/libsmbfs/smb/rq.c b/usr/src/lib/libsmbfs/smb/rq.c deleted file mode 100644 index c4e929eff9..0000000000 --- a/usr/src/lib/libsmbfs/smb/rq.c +++ /dev/null @@ -1,467 +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: rq.c,v 1.4 2004/12/13 00:25:23 lindak Exp $ - */ - -#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 (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 (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); -} |