Print this page
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-16824 SMB client connection setup rework
NEX-17232 SMB client reconnect failures
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (improve debug)
NEX-16818 Add fksmbcl development tool
NEX-17264 SMB client test tp_smbutil_013 fails after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (fix ref leaks)
NEX-6309 Update NT status codes
Update ntstatus.h from [MS-ERREF] October 2015
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>

*** 32,41 **** --- 32,43 ---- * $Id: smb_subr.c,v 1.27.108.1 2005/06/02 00:55:39 lindak Exp $ */ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include <sys/param.h> #include <sys/systm.h> #include <sys/kmem.h>
*** 55,108 **** #include <netsmb/smb.h> #include <netsmb/smb_conn.h> #include <netsmb/smb_rq.h> #include <netsmb/smb_subr.h> - /* - * XXX:This conversion might not be fully MS-Compatible - * for calculating hashes. The output length may differ - * for some locales and needs to be handled from where - * the call is made. - */ - int - smb_toupper(const char *inbuf, char *outbuf, size_t outlen) - { - int err = 0; - size_t inlen, inrem, outrem; - - inrem = inlen = strlen(inbuf); - outrem = outlen; - (void) u8_textprep_str((char *)inbuf, &inrem, outbuf, &outrem, - U8_TEXTPREP_TOUPPER, U8_UNICODE_LATEST, &err); - /* inrem, outrem are bytes unused, remaining */ - if (inrem) { - SMBSDEBUG("input %d remains: %s\n", (int)inrem, inbuf); - inlen -= inrem; - } - if (outrem) { - outlen -= outrem; - outbuf[outlen] = '\0'; - } - if (outlen > inlen) { - SMBSDEBUG("outlen > inlen! (%d > %d)\n", - (int)outlen, (int)inlen); - /* Truncate to inlen here? */ - } - - return (err); - } - void smb_credinit(struct smb_cred *scred, cred_t *cr) { /* cr arg is optional */ if (cr == NULL) cr = ddi_get_cred(); if (is_system_labeled()) { cr = crdup(cr); (void) setpflags(NET_MAC_AWARE, 1, cr); ! } else { crhold(cr); } scred->scr_cred = cr; } --- 57,79 ---- #include <netsmb/smb.h> #include <netsmb/smb_conn.h> #include <netsmb/smb_rq.h> #include <netsmb/smb_subr.h> void smb_credinit(struct smb_cred *scred, cred_t *cr) { /* cr arg is optional */ if (cr == NULL) cr = ddi_get_cred(); + #ifdef _KERNEL if (is_system_labeled()) { cr = crdup(cr); (void) setpflags(NET_MAC_AWARE, 1, cr); ! } else ! #endif ! { crhold(cr); } scred->scr_cred = cr; }
*** 113,122 **** --- 84,101 ---- crfree(scred->scr_cred); scred->scr_cred = NULL; } } + #ifndef _KERNEL + /* ARGSUSED */ + void + smb_debugmsg(const char *func, char *msg) + { + } + #endif /* _KERNEL */ + /* * Helper for the SMBERROR macro, etc. * This is also a good place for a breakpoint * or a dtrace probe, i.e. fbt:nsmb:smb_errmsg */
*** 135,144 **** --- 114,126 ---- */ (void) vsnprintf(buf, sizeof (buf), fmt, adx); DTRACE_PROBE2(debugmsg2, (char *), func_name, (char *), buf); + #ifndef _KERNEL + smb_debugmsg(func_name, buf); + #endif } else { /* * This is one of our xxxERROR macros. * Add a prefix to the fmt string, * then let vcmn_err do the args.
*** 188,197 **** --- 170,182 ---- #define ENOMEDIUM ENXIO #endif #ifndef ETIME #define ETIME ETIMEDOUT #endif + #ifndef EMOREDATA + #define EMOREDATA (0x7fff) + #endif /* * Log any un-handled NT or DOS errors we encounter. * Make these log NOTICE in a debug build to ensure * they get noticed during tests. In the field these
*** 217,227 **** {NT_STATUS_ACCOUNT_EXPIRED, EACCES}, {NT_STATUS_ACCOUNT_LOCKED_OUT, EACCES}, {NT_STATUS_ACCOUNT_RESTRICTION, EACCES}, {NT_STATUS_ADDRESS_ALREADY_EXISTS, EADDRINUSE}, {NT_STATUS_BAD_NETWORK_NAME, ENOENT}, ! {NT_STATUS_BUFFER_TOO_SMALL, EMOREDATA}, {NT_STATUS_CANNOT_DELETE, EACCES}, {NT_STATUS_CONFLICTING_ADDRESSES, EADDRINUSE}, {NT_STATUS_CONNECTION_ABORTED, ECONNABORTED}, {NT_STATUS_CONNECTION_DISCONNECTED, ECONNABORTED}, {NT_STATUS_CONNECTION_REFUSED, ECONNREFUSED}, --- 202,214 ---- {NT_STATUS_ACCOUNT_EXPIRED, EACCES}, {NT_STATUS_ACCOUNT_LOCKED_OUT, EACCES}, {NT_STATUS_ACCOUNT_RESTRICTION, EACCES}, {NT_STATUS_ADDRESS_ALREADY_EXISTS, EADDRINUSE}, {NT_STATUS_BAD_NETWORK_NAME, ENOENT}, ! {NT_STATUS_BAD_NETWORK_PATH, ENOENT}, ! {NT_STATUS_BUFFER_TOO_SMALL, E2BIG}, ! {NT_STATUS_CANCELLED, ECANCELED}, {NT_STATUS_CANNOT_DELETE, EACCES}, {NT_STATUS_CONFLICTING_ADDRESSES, EADDRINUSE}, {NT_STATUS_CONNECTION_ABORTED, ECONNABORTED}, {NT_STATUS_CONNECTION_DISCONNECTED, ECONNABORTED}, {NT_STATUS_CONNECTION_REFUSED, ECONNREFUSED},
*** 231,317 **** {NT_STATUS_DEVICE_PROTOCOL_ERROR, EPROTO}, {NT_STATUS_DIRECTORY_NOT_EMPTY, ENOTEMPTY}, {NT_STATUS_DISK_FULL, ENOSPC}, {NT_STATUS_DLL_NOT_FOUND, ELIBACC}, {NT_STATUS_DUPLICATE_NAME, EINVAL}, {NT_STATUS_END_OF_FILE, ENODATA}, {NT_STATUS_FILE_IS_A_DIRECTORY, EISDIR}, {NT_STATUS_FILE_LOCK_CONFLICT, EAGAIN}, {NT_STATUS_FLOAT_INEXACT_RESULT, ERANGE}, {NT_STATUS_FLOAT_OVERFLOW, ERANGE}, {NT_STATUS_FLOAT_UNDERFLOW, ERANGE}, {NT_STATUS_HOST_UNREACHABLE, EHOSTUNREACH}, ! {NT_STATUS_ILL_FORMED_PASSWORD, EACCES}, {NT_STATUS_INTEGER_OVERFLOW, ERANGE}, ! {NT_STATUS_INVALID_ACCOUNT_NAME, EACCES}, {NT_STATUS_INVALID_HANDLE, EBADF}, {NT_STATUS_INVALID_LEVEL, ENOTSUP}, ! {NT_STATUS_INVALID_LOGON_HOURS, EACCES}, {NT_STATUS_INVALID_OWNER, EINVAL}, {NT_STATUS_INVALID_PARAMETER, EINVAL}, {NT_STATUS_INVALID_PIPE_STATE, EPIPE}, {NT_STATUS_INVALID_PRIMARY_GROUP, EINVAL}, {NT_STATUS_INVALID_WORKSTATION, EACCES}, {NT_STATUS_IN_PAGE_ERROR, EFAULT}, {NT_STATUS_IO_TIMEOUT, ETIMEDOUT}, ! {NT_STATUS_IP_ADDRESS_CONFLICT1, ENOTUNIQ}, ! {NT_STATUS_IP_ADDRESS_CONFLICT2, ENOTUNIQ}, {NT_STATUS_LICENSE_QUOTA_EXCEEDED, EDQUOT}, {NT_STATUS_LOCK_NOT_GRANTED, EAGAIN}, ! {NT_STATUS_LOGIN_TIME_RESTRICTION, EACCES}, ! {NT_STATUS_LOGON_FAILURE, EACCES}, {NT_STATUS_MEDIA_WRITE_PROTECTED, EROFS}, {NT_STATUS_MEMORY_NOT_ALLOCATED, EFAULT}, {NT_STATUS_NAME_TOO_LONG, ENAMETOOLONG}, {NT_STATUS_NETWORK_ACCESS_DENIED, EACCES}, {NT_STATUS_NETWORK_BUSY, EBUSY}, {NT_STATUS_NETWORK_UNREACHABLE, ENETUNREACH}, {NT_STATUS_NET_WRITE_FAULT, ECOMM}, {NT_STATUS_NONEXISTENT_SECTOR, ESPIPE}, {NT_STATUS_NONE_MAPPED, EINVAL}, {NT_STATUS_NOT_A_DIRECTORY, ENOTDIR}, {NT_STATUS_NOT_IMPLEMENTED, ENOTSUP}, {NT_STATUS_NOT_MAPPED_VIEW, EINVAL}, {NT_STATUS_NOT_SUPPORTED, ENOTSUP}, {NT_STATUS_NO_MEDIA, ENOMEDIUM}, {NT_STATUS_NO_MEDIA_IN_DEVICE, ENOMEDIUM}, {NT_STATUS_NO_MEMORY, ENOMEM}, {NT_STATUS_NO_SUCH_DEVICE, ENODEV}, {NT_STATUS_NO_SUCH_FILE, ENOENT}, {NT_STATUS_OBJECT_NAME_COLLISION, EEXIST}, {NT_STATUS_OBJECT_NAME_INVALID, EINVAL}, {NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT}, {NT_STATUS_OBJECT_PATH_INVALID, ENOTDIR}, {NT_STATUS_OBJECT_PATH_NOT_FOUND, ENOENT}, {NT_STATUS_PAGEFILE_QUOTA, EDQUOT}, ! {NT_STATUS_PASSWORD_EXPIRED, EACCES}, ! {NT_STATUS_PASSWORD_MUST_CHANGE, EACCES}, ! {NT_STATUS_PASSWORD_RESTRICTION, EACCES}, {NT_STATUS_PATH_NOT_COVERED, ENOENT}, {NT_STATUS_PIPE_BROKEN, EPIPE}, {NT_STATUS_PIPE_BUSY, EPIPE}, {NT_STATUS_PIPE_CONNECTED, EISCONN}, {NT_STATUS_PIPE_DISCONNECTED, EPIPE}, {NT_STATUS_PIPE_NOT_AVAILABLE, EBUSY}, {NT_STATUS_PORT_CONNECTION_REFUSED, ECONNREFUSED}, {NT_STATUS_PORT_MESSAGE_TOO_LONG, EMSGSIZE}, {NT_STATUS_PORT_UNREACHABLE, EHOSTUNREACH}, {NT_STATUS_PROTOCOL_UNREACHABLE, ENOPROTOOPT}, {NT_STATUS_QUOTA_EXCEEDED, EDQUOT}, ! {NT_STATUS_RANGE_NOT_LOCKED, EIO}, {NT_STATUS_REGISTRY_QUOTA_LIMIT, EDQUOT}, {NT_STATUS_REMOTE_DISCONNECT, ESHUTDOWN}, {NT_STATUS_REMOTE_NOT_LISTENING, ECONNREFUSED}, {NT_STATUS_REQUEST_NOT_ACCEPTED, EACCES}, {NT_STATUS_RETRY, EAGAIN}, {NT_STATUS_SHARING_VIOLATION, EBUSY}, {NT_STATUS_TIMER_NOT_CANCELED, ETIME}, {NT_STATUS_TOO_MANY_LINKS, EMLINK}, {NT_STATUS_TOO_MANY_OPENED_FILES, EMFILE}, {NT_STATUS_UNABLE_TO_FREE_VM, EADDRINUSE}, {NT_STATUS_UNSUCCESSFUL, EINVAL}, ! {NT_STATUS_WRONG_PASSWORD, EACCES}, {0, 0} }; /* * Table for converting NT STATUS values to DOS class/code. --- 218,335 ---- {NT_STATUS_DEVICE_PROTOCOL_ERROR, EPROTO}, {NT_STATUS_DIRECTORY_NOT_EMPTY, ENOTEMPTY}, {NT_STATUS_DISK_FULL, ENOSPC}, {NT_STATUS_DLL_NOT_FOUND, ELIBACC}, {NT_STATUS_DUPLICATE_NAME, EINVAL}, + {NT_STATUS_EAS_NOT_SUPPORTED, ENOTSUP}, + {NT_STATUS_EA_TOO_LARGE, E2BIG}, {NT_STATUS_END_OF_FILE, ENODATA}, + {NT_STATUS_FILE_CLOSED, EBADF}, + {NT_STATUS_FILE_DELETED, ENOENT}, + {NT_STATUS_FILE_INVALID, EIO}, {NT_STATUS_FILE_IS_A_DIRECTORY, EISDIR}, {NT_STATUS_FILE_LOCK_CONFLICT, EAGAIN}, + {NT_STATUS_FILE_RENAMED, ENOENT}, {NT_STATUS_FLOAT_INEXACT_RESULT, ERANGE}, {NT_STATUS_FLOAT_OVERFLOW, ERANGE}, {NT_STATUS_FLOAT_UNDERFLOW, ERANGE}, {NT_STATUS_HOST_UNREACHABLE, EHOSTUNREACH}, ! {NT_STATUS_ILL_FORMED_PASSWORD, EAUTH}, ! {NT_STATUS_INFO_LENGTH_MISMATCH, EINVAL}, ! {NT_STATUS_INSUFFICIENT_RESOURCES, EAGAIN}, ! {NT_STATUS_INSUFF_SERVER_RESOURCES, EAGAIN}, {NT_STATUS_INTEGER_OVERFLOW, ERANGE}, ! {NT_STATUS_INVALID_ACCOUNT_NAME, EAUTH}, ! {NT_STATUS_INVALID_BUFFER_SIZE, EIO}, ! {NT_STATUS_INVALID_DEVICE_REQUEST, EINVAL}, {NT_STATUS_INVALID_HANDLE, EBADF}, + {NT_STATUS_INVALID_INFO_CLASS, EINVAL}, {NT_STATUS_INVALID_LEVEL, ENOTSUP}, ! {NT_STATUS_INVALID_LOCK_SEQUENCE, EINVAL}, ! {NT_STATUS_INVALID_LOGON_HOURS, EAUTH}, {NT_STATUS_INVALID_OWNER, EINVAL}, {NT_STATUS_INVALID_PARAMETER, EINVAL}, {NT_STATUS_INVALID_PIPE_STATE, EPIPE}, {NT_STATUS_INVALID_PRIMARY_GROUP, EINVAL}, {NT_STATUS_INVALID_WORKSTATION, EACCES}, {NT_STATUS_IN_PAGE_ERROR, EFAULT}, + {NT_STATUS_IO_DEVICE_ERROR, EIO}, {NT_STATUS_IO_TIMEOUT, ETIMEDOUT}, ! {NT_STATUS_IP_ADDRESS_CONFLICT1, EADDRINUSE}, ! {NT_STATUS_IP_ADDRESS_CONFLICT2, EADDRINUSE}, {NT_STATUS_LICENSE_QUOTA_EXCEEDED, EDQUOT}, {NT_STATUS_LOCK_NOT_GRANTED, EAGAIN}, ! {NT_STATUS_LOGIN_TIME_RESTRICTION, EAUTH}, ! {NT_STATUS_LOGON_FAILURE, EAUTH}, ! {NT_STATUS_LOGON_TYPE_NOT_GRANTED, EAUTH}, {NT_STATUS_MEDIA_WRITE_PROTECTED, EROFS}, {NT_STATUS_MEMORY_NOT_ALLOCATED, EFAULT}, + {NT_STATUS_MORE_PROCESSING_REQUIRED, EINPROGRESS}, {NT_STATUS_NAME_TOO_LONG, ENAMETOOLONG}, {NT_STATUS_NETWORK_ACCESS_DENIED, EACCES}, {NT_STATUS_NETWORK_BUSY, EBUSY}, + {NT_STATUS_NETWORK_NAME_DELETED, ENOENT}, {NT_STATUS_NETWORK_UNREACHABLE, ENETUNREACH}, {NT_STATUS_NET_WRITE_FAULT, ECOMM}, + {NT_STATUS_NONEXISTENT_EA_ENTRY, ENOENT}, {NT_STATUS_NONEXISTENT_SECTOR, ESPIPE}, {NT_STATUS_NONE_MAPPED, EINVAL}, {NT_STATUS_NOT_A_DIRECTORY, ENOTDIR}, + {NT_STATUS_NOT_FOUND, ENOENT}, {NT_STATUS_NOT_IMPLEMENTED, ENOTSUP}, + {NT_STATUS_NOT_LOCKED, ENOLCK}, {NT_STATUS_NOT_MAPPED_VIEW, EINVAL}, {NT_STATUS_NOT_SUPPORTED, ENOTSUP}, + {NT_STATUS_NO_EAS_ON_FILE, ENOENT}, + {NT_STATUS_NO_LOGON_SERVERS, EAUTH}, {NT_STATUS_NO_MEDIA, ENOMEDIUM}, {NT_STATUS_NO_MEDIA_IN_DEVICE, ENOMEDIUM}, {NT_STATUS_NO_MEMORY, ENOMEM}, {NT_STATUS_NO_SUCH_DEVICE, ENODEV}, {NT_STATUS_NO_SUCH_FILE, ENOENT}, + {NT_STATUS_NO_SUCH_LOGON_SESSION, EAUTH}, + {NT_STATUS_NO_SUCH_USER, EAUTH}, + {NT_STATUS_NO_TRUST_LSA_SECRET, EAUTH}, + {NT_STATUS_NO_TRUST_SAM_ACCOUNT, EAUTH}, {NT_STATUS_OBJECT_NAME_COLLISION, EEXIST}, {NT_STATUS_OBJECT_NAME_INVALID, EINVAL}, {NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT}, {NT_STATUS_OBJECT_PATH_INVALID, ENOTDIR}, {NT_STATUS_OBJECT_PATH_NOT_FOUND, ENOENT}, + {NT_STATUS_OBJECT_PATH_SYNTAX_BAD, EINVAL}, + {NT_STATUS_OBJECT_TYPE_MISMATCH, EBADF}, {NT_STATUS_PAGEFILE_QUOTA, EDQUOT}, ! {NT_STATUS_PASSWORD_EXPIRED, EAUTH}, ! {NT_STATUS_PASSWORD_MUST_CHANGE, EAUTH}, ! {NT_STATUS_PASSWORD_RESTRICTION, EAUTH}, {NT_STATUS_PATH_NOT_COVERED, ENOENT}, {NT_STATUS_PIPE_BROKEN, EPIPE}, {NT_STATUS_PIPE_BUSY, EPIPE}, {NT_STATUS_PIPE_CONNECTED, EISCONN}, {NT_STATUS_PIPE_DISCONNECTED, EPIPE}, {NT_STATUS_PIPE_NOT_AVAILABLE, EBUSY}, {NT_STATUS_PORT_CONNECTION_REFUSED, ECONNREFUSED}, + {NT_STATUS_PORT_DISCONNECTED, EBADF}, {NT_STATUS_PORT_MESSAGE_TOO_LONG, EMSGSIZE}, {NT_STATUS_PORT_UNREACHABLE, EHOSTUNREACH}, {NT_STATUS_PROTOCOL_UNREACHABLE, ENOPROTOOPT}, {NT_STATUS_QUOTA_EXCEEDED, EDQUOT}, ! {NT_STATUS_RANGE_NOT_LOCKED, EAGAIN}, /* like F_SETLK */ {NT_STATUS_REGISTRY_QUOTA_LIMIT, EDQUOT}, {NT_STATUS_REMOTE_DISCONNECT, ESHUTDOWN}, {NT_STATUS_REMOTE_NOT_LISTENING, ECONNREFUSED}, {NT_STATUS_REQUEST_NOT_ACCEPTED, EACCES}, {NT_STATUS_RETRY, EAGAIN}, {NT_STATUS_SHARING_VIOLATION, EBUSY}, {NT_STATUS_TIMER_NOT_CANCELED, ETIME}, {NT_STATUS_TOO_MANY_LINKS, EMLINK}, {NT_STATUS_TOO_MANY_OPENED_FILES, EMFILE}, + {NT_STATUS_TRUSTED_DOMAIN_FAILURE, EAUTH}, + {NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE, EAUTH}, {NT_STATUS_UNABLE_TO_FREE_VM, EADDRINUSE}, {NT_STATUS_UNSUCCESSFUL, EINVAL}, ! {NT_STATUS_WRONG_PASSWORD, EAUTH}, {0, 0} }; /* * Table for converting NT STATUS values to DOS class/code.
*** 591,608 **** {ERRDOS, ERRnoaccess, NT_STATUS_PROCESS_IS_TERMINATING}, {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LOGON_TYPE}, {ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION}, {ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE}, {ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED}, - {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT}, - {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST}, - {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED}, - {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER}, - {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND}, - {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID}, - {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE}, - {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR}, {ERRHRD, ERRgeneral, NT_STATUS_NO_LDT}, {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE}, {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET}, {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_DESCRIPTOR}, {ERRDOS, ERROR_BAD_EXE_FORMAT, NT_STATUS_INVALID_IMAGE_NE_FORMAT}, --- 609,618 ----
*** 866,876 **** --- 876,899 ---- if (nt2d->nterr == nterr) return (smb_maperror(nt2d->dclass, nt2d->derr)); return (EIO); } + uint_t + smb_doserr2status(int dclass, int derr) + { + const nt2doserr_t *nt2d; + if (dclass == 0 && derr == 0) + return (0); + + for (nt2d = nt2doserr; nt2d->nterr; nt2d++) + if (nt2d->dclass == dclass && nt2d->derr == derr) + return (nt2d->nterr); + return (NT_STATUS_UNSUCCESSFUL); + } + int smb_maperror(int eclass, int eno) { if (eclass == 0 && eno == 0) return (0);
*** 994,1010 **** smb_errmsg(unknown_err_logpri, "smb_maperror", "Unknown DOS error %d/%d\n", eclass, eno); return (EIO); } - #if defined(NOICONVSUPPORT) || defined(lint) - extern int iconv_conv(void *handle, const char **inbuf, - size_t *inbytesleft, char **outbuf, size_t *outbytesleft); - #endif - #define SMALL_CONV 256 /*ARGSUSED*/ int smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src, int size, int caseopt, int *lenp) { --- 1017,1110 ---- smb_errmsg(unknown_err_logpri, "smb_maperror", "Unknown DOS error %d/%d\n", eclass, eno); return (EIO); } #define SMALL_CONV 256 + /* + * Decode an SMB OTW string (Unicode or OEM chars) + * converting to UTF-8 in the output buffer. + * outlen is in/out (max size on input) + * insize is the wire size (2 * chars if unicode) + * The output string is null terminated. + * Output length does not include the null. + */ + int + smb_get_dstring(struct mdchain *mdc, struct smb_vc *vcp, + char *outbuf, size_t *outlen, int insize) + { + uint16_t convbuf[SMALL_CONV]; + uint16_t *cbuf; + size_t cbufalloc, inlen, outsize; + int error; + + if (insize <= 0) + return (0); + /* Note: inlen is UTF-16 symbols. */ + inlen = insize / 2; + + if (*outlen < 2) + return (EINVAL); + outsize = *outlen - 1; /* room for null */ + + /* + * Get a buffer for the conversion and fill it. + * Use stack buffer if the string is + * small enough, else allocate. + */ + if (insize < sizeof (convbuf)) { + cbufalloc = 0; + cbuf = convbuf; + } else { + cbufalloc = insize + 2; + cbuf = kmem_alloc(cbufalloc, KM_SLEEP); + } + error = md_get_mem(mdc, cbuf, insize, MB_MSYSTEM); + if (error != 0) + goto out; + cbuf[inlen] = 0; + + /* + * Handle the easy case (non-unicode). + * XXX: Technically, we should convert + * the string to OEM codeset first... + * Modern servers all use Unicode, so + * this is good enough. + */ + if (SMB_UNICODE_STRINGS(vcp) == 0) { + *outlen = strlcpy(outbuf, (char *)cbuf, outsize); + if (*outlen > outsize) { + *outlen = outsize; + error = E2BIG; + } + } else { + /* + * Convert from UTF-16 to UTF-8 + */ + error = uconv_u16tou8(cbuf, &inlen, + (uchar_t *)outbuf, outlen, + UCONV_IN_LITTLE_ENDIAN); + if (error == 0) { + outbuf[*outlen] = '\0'; + } + } + + ASSERT(*outlen == strlen(outbuf)); + + out: + if (cbufalloc != 0) + kmem_free(cbuf, cbufalloc); + + return (error); + } + + /* + * It's surprising that this function does utf8-ucs2 conversion. + * One would expect only smb_put_dstring to do that. + * Fixing that will require changing a bunch of callers. XXX + */ /*ARGSUSED*/ int smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src, int size, int caseopt, int *lenp) {
*** 1077,1082 **** --- 1177,1309 ---- error = smb_put_dmem(mbp, vcp, src, len, caseopt, NULL); if (error) return (error); return (error); + } + int + smb_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb, + uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc, + uint32_t disp, uint32_t createopt, uint32_t impersonate, + struct smb_cred *scrp, smb_fh_t *fhp, + uint32_t *cr_act_p, struct smbfattr *fap) + { + int err; + + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + err = smb2_smb_ntcreate(ssp, name_mb, NULL, NULL, + crflag, req_acc, efa, sh_acc, disp, createopt, + impersonate, scrp, &fhp->fh_fid2, cr_act_p, fap); + } else { + err = smb1_smb_ntcreate(ssp, name_mb, crflag, req_acc, + efa, sh_acc, disp, createopt, impersonate, scrp, + &fhp->fh_fid1, cr_act_p, fap); + } + return (err); + } + + int + smb_smb_close(struct smb_share *ssp, smb_fh_t *fhp, + struct smb_cred *scrp) + { + int err; + + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + err = smb2_smb_close(ssp, &fhp->fh_fid2, scrp); + } else { + err = smb1_smb_close(ssp, fhp->fh_fid1, NULL, scrp); + } + + return (err); + } + + /* + * Largest size to use with LARGE_READ/LARGE_WRITE. + * Specs say up to 64k data bytes, but Windows traffic + * uses 60k... no doubt for some good reason. + * (Probably to keep 4k block alignment.) + */ + uint32_t smb1_large_io_max = (60*1024); + + /* + * Common function for read/write with UIO. + * Called by netsmb smb_usr_rw, + * smbfs_readvnode, smbfs_writevnode + */ + int + smb_rwuio(smb_fh_t *fhp, uio_rw_t rw, + uio_t *uiop, smb_cred_t *scred, int timo) + { + struct smb_share *ssp = FHTOSS(fhp); + struct smb_vc *vcp = SSTOVC(ssp); + ssize_t save_resid; + uint32_t len, rlen, maxlen; + int error = 0; + int (*iofun)(smb_fh_t *, uint32_t *, + uio_t *, smb_cred_t *, int); + + /* After reconnect, the fid is invalid. */ + if (fhp->fh_vcgenid != ssp->ss_vcgenid) + return (ESTALE); + + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + if (rw == UIO_READ) { + iofun = smb2_smb_read; + maxlen = vcp->vc_sopt.sv2_maxread; + } else { /* UIO_WRITE */ + iofun = smb2_smb_write; + maxlen = vcp->vc_sopt.sv2_maxwrite; + } + } else { + /* + * Using NT LM 0.12, so readx, writex. + * Make sure we can represent the offset. + */ + if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 && + (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX) + return (EFBIG); + + if (rw == UIO_READ) { + iofun = smb_smb_readx; + if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) + maxlen = smb1_large_io_max; + else + maxlen = vcp->vc_rxmax; + } else { /* UIO_WRITE */ + iofun = smb_smb_writex; + if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) + maxlen = smb1_large_io_max; + else + maxlen = vcp->vc_wxmax; + } + } + + save_resid = uiop->uio_resid; + while (uiop->uio_resid > 0) { + /* Lint: uio_resid may be 64-bits */ + rlen = len = (uint32_t)min(maxlen, uiop->uio_resid); + error = (*iofun)(fhp, &rlen, uiop, scred, timo); + + /* + * Note: the iofun called uio_update, so + * not doing that here as one might expect. + * + * Quit the loop either on error, or if we + * transferred less then requested. + */ + if (error || (rlen < len)) + break; + + timo = 0; /* only first I/O should wait */ + } + if (error && (save_resid != uiop->uio_resid)) { + /* + * Stopped on an error after having + * successfully transferred data. + * Suppress this error. + */ + SMBSDEBUG("error %d suppressed\n", error); + error = 0; + } + + return (error); }