1/*
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
4 *
5 * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *    This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/malloc.h>
38#include <sys/proc.h>
39#include <sys/lock.h>
40#include <sys/sysctl.h>
41#include <sys/socket.h>
42#include <sys/kpi_mbuf.h>
43#include <sys/vnode.h>
44
45#include <sys/smb_apple.h>
46#include <netsmb/smb.h>
47#include <netsmb/smb_2.h>
48#include <netsmb/smb_conn.h>
49#include <netsmb/smb_rq.h>
50#include <netsmb/smb_subr.h>
51#include <netsmb/smb_dev.h>
52#include <netsmb/smb_converter.h>
53#include <smbclient/ntstatus.h>
54
55
56static const struct {
57	uint32_t nterr;
58	uint32_t errno;
59} nt2errno[] = {
60	{STATUS_LOGON_TYPE_NOT_GRANTED,	EAUTH},
61	{STATUS_NO_LOGON_SERVERS,		EAUTH},	/* Server can't talk to domain, just return eauth */
62	{STATUS_ACCESS_DENIED,			EACCES},
63	{STATUS_ACCESS_VIOLATION,		EACCES},
64	{STATUS_ACCOUNT_DISABLED,		SMB_ENETFSACCOUNTRESTRICTED},	/* ask the admin for help */
65	{STATUS_ACCOUNT_RESTRICTION,	SMB_ENETFSACCOUNTRESTRICTED},	/* ask the admin for help */
66	{STATUS_LOGIN_TIME_RESTRICTION,	SMB_ENETFSACCOUNTRESTRICTED},	/* ask the admin for help */
67	{STATUS_ACCOUNT_LOCKED_OUT,		SMB_ENETFSACCOUNTRESTRICTED},	/* ask the admin for help */
68	{STATUS_INVALID_ACCOUNT_NAME,	SMB_ENETFSACCOUNTRESTRICTED},	/* ask the admin for help */
69	{STATUS_PWD_TOO_SHORT,			SMB_ENETFSPWDPOLICY},			/* violates password policy */
70	{STATUS_PWD_TOO_RECENT,			SMB_ENETFSPWDPOLICY},			/* violates password policy */
71	{STATUS_PWD_HISTORY_CONFLICT,	SMB_ENETFSPWDPOLICY},			/* violates password policy */
72	{STATUS_ACCOUNT_EXPIRED,		SMB_ENETFSACCOUNTRESTRICTED},	/* ask the admin for help */
73	{STATUS_PASSWORD_EXPIRED,		SMB_ENETFSPWDNEEDSCHANGE},		/* change your password */
74	{STATUS_PASSWORD_RESTRICTION,	SMB_ENETFSPWDPOLICY},			/* violates password policy */
75	{STATUS_PASSWORD_MUST_CHANGE,	SMB_ENETFSPWDNEEDSCHANGE},		/* change your password */
76	{STATUS_INVALID_LOGON_HOURS,	SMB_ENETFSACCOUNTRESTRICTED},	/* ask the admin for help */
77	{STATUS_ADDRESS_ALREADY_EXISTS,	EADDRINUSE},
78	{STATUS_BAD_NETWORK_NAME,		ENOENT},
79	{STATUS_NETWORK_NAME_DELETED,	ENOENT},
80	{STATUS_DUPLICATE_NAME,			ENOENT},
81	{STATUS_BAD_NETWORK_PATH,		ENOENT},
82	{STATUS_BUFFER_TOO_SMALL,		E2BIG},
83	{STATUS_INVALID_BUFFER_SIZE,	EIO},
84	{STATUS_CONFLICTING_ADDRESSES,	EADDRINUSE},
85	{STATUS_CONNECTION_ABORTED,		ECONNABORTED},
86	{STATUS_CONNECTION_DISCONNECTED,ECONNABORTED},
87	{STATUS_CONNECTION_REFUSED,		ECONNREFUSED},
88	{STATUS_CONNECTION_RESET,		ENETRESET},
89	{STATUS_DEVICE_DOES_NOT_EXIST,	ENODEV},
90	{STATUS_DEVICE_PROTOCOL_ERROR,	EPROTO},
91	{STATUS_DIRECTORY_NOT_EMPTY,	ENOTEMPTY},
92	{STATUS_DISK_FULL,				ENOSPC},
93	{STATUS_DLL_NOT_FOUND,			ENOENT},
94	{STATUS_END_OF_FILE,			ENODATA},
95	{STATUS_FILE_IS_A_DIRECTORY,	EISDIR},
96	{STATUS_FILE_LOCK_CONFLICT,		EIO}, /* Return the IO error (AFP Like) and let the lock code reset it */
97	{STATUS_LOCK_NOT_GRANTED,		EACCES},
98	{STATUS_FLOAT_INEXACT_RESULT,	ERANGE},
99	{STATUS_FLOAT_OVERFLOW,			ERANGE},
100	{STATUS_FLOAT_UNDERFLOW,		ERANGE},
101	{STATUS_HOST_UNREACHABLE,		EHOSTUNREACH},
102	{STATUS_ILL_FORMED_PASSWORD,	EAUTH},
103	{STATUS_INTEGER_OVERFLOW,		ERANGE},
104	{STATUS_FILE_CLOSED,			EBADF},
105	{STATUS_INVALID_HANDLE,			EBADF},
106	{STATUS_INVALID_PARAMETER,		EINVAL},
107	{STATUS_INVALID_PIPE_STATE,		EPIPE},
108	{STATUS_INVALID_WORKSTATION,	EACCES},
109	{STATUS_IN_PAGE_ERROR,			EFAULT},
110	{STATUS_IO_TIMEOUT,				ETIMEDOUT},
111	{STATUS_IP_ADDRESS_CONFLICT1,	EADDRINUSE},
112	{STATUS_IP_ADDRESS_CONFLICT2,	EADDRINUSE},
113	{STATUS_LICENSE_QUOTA_EXCEEDED,	EDQUOT},
114	{STATUS_LOGON_FAILURE,			EAUTH},
115	{STATUS_MEDIA_WRITE_PROTECTED,	EROFS},
116	{STATUS_MEMORY_NOT_ALLOCATED,	EFAULT},
117	{STATUS_NAME_TOO_LONG,			ENAMETOOLONG},
118	{STATUS_NETWORK_ACCESS_DENIED,	EACCES},
119	{STATUS_NETWORK_BUSY,			EBUSY},
120	{STATUS_NETWORK_UNREACHABLE,	ENETUNREACH},
121	{STATUS_NET_WRITE_FAULT,		EIO},
122	{STATUS_NONEXISTENT_SECTOR,		ESPIPE},
123	{STATUS_NOT_A_DIRECTORY,		ENOTDIR},
124	{STATUS_NOT_IMPLEMENTED,		ENOTSUP},
125	{STATUS_NOT_MAPPED_VIEW,		EINVAL},
126	{STATUS_NOT_SUPPORTED,			ENOTSUP},
127	{STATUS_NO_MEDIA,				EIO},
128	{STATUS_IO_DEVICE_ERROR,		EIO},
129	{STATUS_NO_MEDIA_IN_DEVICE,		EIO},
130	{STATUS_NO_MEMORY,				ENOMEM},
131	{STATUS_NO_SUCH_DEVICE,			ENODEV},
132	{STATUS_NO_SUCH_FILE,			ENOENT},
133	{STATUS_OBJECT_NAME_COLLISION,	EEXIST},
134	{STATUS_OBJECT_NAME_NOT_FOUND,	ENOENT},
135	{STATUS_OBJECT_PATH_INVALID,	ENOTDIR},
136	{STATUS_OBJECT_PATH_NOT_FOUND,	ENOENT},
137	{STATUS_PAGEFILE_QUOTA,			EDQUOT},
138	{STATUS_PATH_NOT_COVERED,		ENOENT},
139	{STATUS_NOT_A_REPARSE_POINT,	ENOENT},
140	{STATUS_IO_REPARSE_TAG_MISMATCH,EIO},
141	{STATUS_IO_REPARSE_DATA_INVALID,EIO},
142	{STATUS_IO_REPARSE_TAG_NOT_HANDLED,	EIO},
143	{STATUS_REPARSE_POINT_NOT_RESOLVED,	ENOENT},
144	{STATUS_PIPE_BROKEN,			EPIPE},
145	{STATUS_PIPE_BUSY,				EPIPE},
146	{STATUS_PIPE_CONNECTED,			EISCONN},
147	{STATUS_PIPE_DISCONNECTED,		EPIPE},
148	{STATUS_SMB_BAD_TID,			ENOENT},
149	{STATUS_INSUFFICIENT_RESOURCES, EAGAIN},
150	{STATUS_INSUFF_SERVER_RESOURCES, EAGAIN},
151	{STATUS_PIPE_NOT_AVAILABLE,		ENOSYS},
152	{STATUS_PORT_CONNECTION_REFUSED,ECONNREFUSED},
153	{STATUS_PORT_MESSAGE_TOO_LONG,	EMSGSIZE},
154	{STATUS_PORT_UNREACHABLE,		EHOSTUNREACH},
155	{STATUS_PROTOCOL_UNREACHABLE,	ENOPROTOOPT},
156	{STATUS_QUOTA_EXCEEDED,			EDQUOT},
157	{STATUS_REGISTRY_QUOTA_LIMIT,	EDQUOT},
158	{STATUS_REMOTE_DISCONNECT,		ESHUTDOWN},
159	{STATUS_REMOTE_NOT_LISTENING,	ECONNREFUSED},
160	{STATUS_REQUEST_NOT_ACCEPTED,	EUSERS},
161	{STATUS_RETRY,					EAGAIN},
162	{STATUS_SHARING_VIOLATION,		EBUSY},
163	{STATUS_TIMER_NOT_CANCELED,		ETIME},
164	{STATUS_TOO_MANY_LINKS,			EMLINK},
165	{STATUS_TOO_MANY_OPENED_FILES,	EMFILE},
166	{STATUS_UNABLE_TO_FREE_VM,		EADDRINUSE},
167	{STATUS_UNSUCCESSFUL,			EINVAL},
168	{STATUS_WRONG_PASSWORD,			EAUTH},
169	{STATUS_DELETE_PENDING,			EACCES},
170	{STATUS_OBJECT_NAME_INVALID,	ENAMETOOLONG},
171	{STATUS_CANNOT_DELETE,			EPERM},
172	{STATUS_RANGE_NOT_LOCKED,		EAGAIN},	/* Setting to match F_SETLK, see AFP  */
173	{STATUS_INVALID_LEVEL,			ENOTSUP},
174	{STATUS_MORE_PROCESSING_REQUIRED,  EAGAIN},	/* SetupX message requires more processing */
175	{STATUS_CANCELLED,				ECANCELED},
176	{STATUS_INVALID_INFO_CLASS,		EINVAL},
177	{STATUS_INFO_LENGTH_MISMATCH,	EINVAL},
178	{STATUS_INVALID_DEVICE_REQUEST, EINVAL},
179	{STATUS_WRONG_VOLUME,			ENOENT},
180	{STATUS_UNRECOGNIZED_MEDIA,		EIO},
181	{STATUS_INVALID_SYSTEM_SERVICE,	EINVAL},
182	{STATUS_INVALID_LOCK_SEQUENCE,	EACCES},
183	{STATUS_ALREADY_COMMITTED,		EACCES},
184	{STATUS_OBJECT_TYPE_MISMATCH,	EBADF},
185	{STATUS_NOT_LOCKED,				ENOLCK},
186	{STATUS_INVALID_PARAMETER_MIX,	EINVAL},
187	{STATUS_PORT_DISCONNECTED,		EBADF},
188	{STATUS_INVALID_PORT_HANDLE,	EBADF},
189	{STATUS_OBJECT_PATH_SYNTAX_BAD,	ENOENT},
190	{STATUS_EAS_NOT_SUPPORTED,		ENOTSUP},
191	{STATUS_EA_TOO_LARGE,			ENOATTR},
192	{STATUS_NONEXISTENT_EA_ENTRY,	ENOATTR},
193	{STATUS_NO_EAS_ON_FILE,			ENOATTR},
194	{STATUS_NO_SUCH_LOGON_SESSION,	SMB_ENETFSACCOUNTRESTRICTED},
195	{STATUS_USER_EXISTS,			SMB_ENETFSACCOUNTRESTRICTED},
196	{STATUS_NO_SUCH_USER,			SMB_ENETFSACCOUNTRESTRICTED},
197	{STATUS_USER_SESSION_DELETED,	SMB_ENETFSACCOUNTRESTRICTED},
198	{STATUS_FILE_INVALID,			EIO},
199	{STATUS_DFS_EXIT_PATH_FOUND,	ENOENT},
200	{STATUS_DEVICE_DATA_ERROR,		EIO},
201	{STATUS_DEVICE_NOT_READY,		EAGAIN},
202	{STATUS_ILLEGAL_FUNCTION,		EINVAL},
203	{STATUS_FILE_RENAMED,			ENOENT},
204	{STATUS_FILE_DELETED,			ENOENT},
205	{STATUS_NO_TRUST_LSA_SECRET,	EAUTH},
206	{STATUS_NO_TRUST_SAM_ACCOUNT,	EAUTH},
207	{STATUS_TRUSTED_DOMAIN_FAILURE,	EAUTH},
208	{STATUS_TRUSTED_RELATIONSHIP_FAILURE,	EAUTH},
209	{0,	0}
210};
211
212#ifdef SMB_DEBUG
213void smb_hexdump(const char *func, const char *s, unsigned char *buf, size_t inlen)
214{
215    int32_t addr;
216    int32_t i;
217	int32_t len = (int32_t)inlen;
218
219	printf("%s: hexdump: %s %p length %d inlen %ld\n", func, s, buf, len, inlen);
220    addr = 0;
221    while( addr < len )
222    {
223        printf("%6.6x - " , addr );
224        for( i=0; i<16; i++ )
225        {
226            if( addr+i < len )
227                printf("%2.2x ", buf[addr+i] );
228            else
229                printf("   " );
230        }
231        printf(" \"");
232        for( i=0; i<16; i++ )
233        {
234            if( addr+i < len )
235            {
236                if(( buf[addr+i] > 0x19 ) && ( buf[addr+i] < 0x7e ) )
237                    printf("%c", buf[addr+i] );
238                else
239                    printf(".");
240            }
241        }
242        printf("\" \n");
243        addr += 16;
244    }
245    printf("\" \n");
246}
247#endif // SMB_DEBUG
248
249char *
250smb_strndup(const char * string, size_t maxlen)
251{
252    char * result = NULL;
253    size_t size;
254
255    if (!string) {
256        goto finish;
257    }
258
259    size = strnlen(string, maxlen);
260	SMB_MALLOC(result, char *, size + 1, M_SMBSTR, M_WAITOK | M_ZERO);
261    if (!result) {
262        goto finish;
263    }
264
265    memcpy(result, string, size);
266
267finish:
268    return result;
269}
270
271/* Same as the kernel defualt */
272#define SMB_KALLOC_MAP_SIZE_MAX  (128 * 1024 * 1024)
273#define SMB_WAIT_SIZE_MAX		(32 * 1024)
274
275/*
276 * duplicate memory block from a user space.
277 */
278void * smb_memdupin(user_addr_t umem, int len)
279{
280	int error;
281	char *p;
282	int flags = M_WAITOK;
283
284	/* Never let them allocate something unreasonable */
285	if ((len < 0) || (len > SMB_KALLOC_MAP_SIZE_MAX)) {
286		SMBERROR("Bad size : %d\n", len);
287		return NULL;
288	}
289	/* Requesting large amount of memory don't wait */
290	if (len > SMB_WAIT_SIZE_MAX) {
291		flags = M_NOWAIT;
292	}
293    SMB_MALLOC(p, char *, len, M_SMBSTR, flags);
294	if (!p) {
295		SMBDEBUG("malloc failed : %d\n", ENOMEM);
296		return NULL;
297	}
298	error = copyin(umem, p, len);
299	if (error == 0)
300		return p;
301
302	SMBDEBUG("copyin failed :  %d\n", error);
303	SMB_FREE(p, M_SMBDATA);
304	return NULL;
305}
306
307/*
308 * duplicate memory block in the kernel space.
309 */
310void *
311smb_memdup(const void *umem, int len)
312{
313	char *p;
314
315	if (len > 32 * 1024)
316		return NULL;
317    SMB_MALLOC(p, char *, len, M_SMBSTR, M_WAITOK);
318	if (p == NULL)
319		return NULL;
320	bcopy(umem, p, len);
321	return p;
322}
323
324#ifdef SMB_SOCKETDATA_DEBUG
325void
326m_dumpm(mbuf_t m) {
327	char *p;
328	int len;
329	SMBDEBUG("d=");
330	while(m) {
331		p = mbuf_data(m);
332		len = mbuf_len(m);
333		SMBDEBUG("(%d)",len);
334		while(len--){
335			SMBDEBUG("%02x ",((int)*(p++)) & 0xff);
336		}
337		m = mbuf_next(m);
338	};
339	SMBDEBUG("\n");
340}
341#endif
342
343/* Convert the DOS Class Error to a NTSTATUS error */
344static uint32_t
345smb_dos_class_err_to_ntstatus(uint16_t dosErr)
346{
347	switch (dosErr) {
348		case ERRbadfunc:
349			return STATUS_NOT_IMPLEMENTED;
350		case ERRbadfile:
351			return STATUS_NO_SUCH_FILE;
352		case ERRbadpath:
353			return STATUS_OBJECT_PATH_NOT_FOUND;
354		case ERRnofids:
355			return STATUS_TOO_MANY_OPENED_FILES;
356		case ERRnoaccess:
357			return STATUS_ACCESS_DENIED;
358		case ERRbadfid:
359			return STATUS_INVALID_HANDLE;
360		case ERRbadmcb:
361			return STATUS_INSUFF_SERVER_RESOURCES;
362		case ERRnomem:
363			return STATUS_NO_MEMORY;
364		case ERRbadmem:
365			return STATUS_NO_MEMORY;
366		case ERRbadenv:
367			return STATUS_INVALID_PARAMETER;
368		case ERRbadformat:
369			return STATUS_INVALID_PARAMETER;
370		case ERRbadaccess:
371			return STATUS_ACCESS_DENIED;
372		case ERRbaddata:
373			return STATUS_DATA_ERROR;
374		case ERRoutofmem:
375			return STATUS_NO_MEMORY;
376		case ERRbaddrive:
377			return STATUS_INSUFF_SERVER_RESOURCES;
378		case ERRremcd:
379			return STATUS_DIRECTORY_NOT_EMPTY;
380		case ERRdiffdevice:
381			return STATUS_NOT_SAME_DEVICE;
382		case ERRnofiles:
383			return STATUS_NO_MORE_FILES;
384		case ERRwriteprotect:
385			return STATUS_MEDIA_WRITE_PROTECTED;
386		case ERRnotready:
387			return STATUS_DEVICE_NOT_READY;
388		case ERRbadcmd:
389			return STATUS_SMB_BAD_COMMAND;
390		case ERRcrc:
391			return STATUS_DATA_ERROR;
392		case ERRbadlength:
393			return STATUS_INFO_LENGTH_MISMATCH;
394		case ERRsectornotfound:
395			return STATUS_NONEXISTENT_SECTOR;
396		case ERRgeneral:
397			return STATUS_UNSUCCESSFUL;
398		case ERRbadshare:
399			return STATUS_SHARING_VIOLATION;
400		case ERRlock:
401			return STATUS_FILE_LOCK_CONFLICT;
402		case ERRwrongdisk:
403			return STATUS_WRONG_VOLUME;
404		case ERReof:
405			return STATUS_END_OF_FILE;
406		case ERRunsup:
407			return STATUS_NOT_SUPPORTED;
408		case ERRnoipc:
409			return STATUS_BAD_NETWORK_NAME;
410		case ERRnosuchshare:
411			return STATUS_BAD_NETWORK_NAME;
412		case ERRtoomanynames:
413			return STATUS_TOO_MANY_NAMES;
414		case ERRfilexists:
415			return STATUS_OBJECT_NAME_COLLISION;
416		case ERRinvalidparam:
417			return STATUS_INVALID_PARAMETER;
418		case ERRinvalidname:
419			return STATUS_OBJECT_NAME_INVALID;
420		case ERRunknownlevel:
421			return STATUS_INVALID_LEVEL;
422		case ERRdirnotempty:
423			return STATUS_DIRECTORY_NOT_EMPTY;
424		case ERRnotlocked:
425			return STATUS_RANGE_NOT_LOCKED;
426		case ERRrename:
427			return STATUS_OBJECT_NAME_COLLISION;
428		case ERRbadpipe:
429			return STATUS_INVALID_PIPE_STATE;
430		case ERRpipebusy:
431			return STATUS_PIPE_BUSY;
432		case ERRpipeclosing:
433			return STATUS_PIPE_CLOSING;
434		case ERRnotconnected:
435			return STATUS_PIPE_DISCONNECTED;
436		case ERRmoredata:
437			return STATUS_MORE_PROCESSING_REQUIRED;
438		case ERRbadealist:
439			return STATUS_EA_TOO_LARGE;
440		case ERReasunsupported:
441			return STATUS_EAS_NOT_SUPPORTED;
442		case ERRnotifyenumdir:
443			return STATUS_NOTIFY_ENUM_DIR;
444		case ERRinvgroup:
445			return STATUS_NETLOGON_NOT_STARTED;
446		default:
447			break;
448	}
449	return STATUS_UNSUCCESSFUL;
450}
451
452/* Convert the Server Class Error to a NTSTATUS error */
453static uint32_t
454smb_srv_class_err_to_ntstatus(uint16_t srvErr)
455{
456	switch (srvErr) {
457		case ERRerror:
458            /*
459             * Non-specific error: resource other than disk space exhausted
460             * (for example, TIDs); or first command was not negotiate; or
461             * multiple negotiates attempted; or internal server error.
462             */
463			return STATUS_INSUFFICIENT_RESOURCES;
464		case ERRbadpw:
465			return STATUS_WRONG_PASSWORD;
466		case ERRbadpath:
467			return STATUS_PATH_NOT_COVERED;
468		case ERRaccess:
469			return STATUS_NETWORK_ACCESS_DENIED;
470		case ERRinvtid:
471			return STATUS_SMB_BAD_TID;
472		case ERRinvnetname:
473			return STATUS_BAD_NETWORK_NAME;
474		case ERRinvdevice:
475			return STATUS_BAD_DEVICE_TYPE;
476		case ERRinvsess:
477			return STATUS_UNSUCCESSFUL;
478		case ERRworking:
479			return STATUS_UNSUCCESSFUL;
480		case ERRnotme:
481			return STATUS_UNSUCCESSFUL;
482		case ERRbadcmd:
483			return STATUS_SMB_BAD_COMMAND;
484		case ERRqfull:
485			return STATUS_PRINT_QUEUE_FULL;
486		case ERRqtoobig:
487			return STATUS_NO_SPOOL_SPACE;
488		case ERRqeof:
489			return STATUS_UNSUCCESSFUL;
490		case ERRinvpfid:
491			return STATUS_PRINT_CANCELLED;
492		case ERRsmbcmd:
493			return STATUS_NOT_IMPLEMENTED;
494		case ERRsrverror:
495			return STATUS_UNEXPECTED_NETWORK_ERROR;
496		case ERRfilespecs:
497			return STATUS_INVALID_HANDLE;
498		case ERRbadpermits:
499			return STATUS_NETWORK_ACCESS_DENIED;
500		case ERRsetattrmode:
501			return STATUS_INVALID_PARAMETER;
502		case ERRtimeout:
503			return STATUS_IO_TIMEOUT;
504		case ERRnoresource:
505			return STATUS_REQUEST_NOT_ACCEPTED;
506		case ERRtoomanyuids:
507			return STATUS_TOO_MANY_SESSIONS;
508		case ERRbaduid:
509			return STATUS_SMB_BAD_UID;
510		case ERRnotconnected:
511			return STATUS_PIPE_DISCONNECTED;
512		case ERRusempx:
513			return STATUS_NOT_IMPLEMENTED;
514		case ERRusestd:
515			return STATUS_SMB_USE_STANDARD;
516		case ERRcontmpx:
517			return STATUS_NOT_IMPLEMENTED;
518		case ERRaccountExpired:
519			return STATUS_ACCOUNT_EXPIRED;
520		case ERRbadClient:
521			return STATUS_INVALID_WORKSTATION;
522		case ERRbadLogonTime:
523			return STATUS_INVALID_LOGON_HOURS;
524		case ERRpasswordExpired:
525			return STATUS_PASSWORD_EXPIRED;
526		case ERRnosupport:
527			return STATUS_NOT_IMPLEMENTED;
528		default:
529			break;
530	}
531	return STATUS_UNSUCCESSFUL;
532}
533
534/* Convert the Hardware Class Error to a NTSTATUS error */
535static uint32_t
536smb_hrd_class_err_to_ntstatus(uint16_t hrdErr)
537{
538	switch (hrdErr) {
539		case ERRnowrite:
540			return STATUS_MEDIA_WRITE_PROTECTED;
541		case ERRbadunit:
542			return STATUS_UNSUCCESSFUL;
543		case ERRnotready:
544			return STATUS_NO_MEDIA_IN_DEVICE;
545		case ERRbadcmd:
546			return STATUS_INVALID_DEVICE_STATE;
547		case ERRdata:
548			return STATUS_DATA_ERROR;
549		case ERRbadreq:
550			return STATUS_DATA_ERROR;
551		case ERRseek:
552			return STATUS_UNSUCCESSFUL;
553		case ERRbadmedia:
554			return STATUS_DISK_CORRUPT_ERROR;
555		case ERRbadsector:
556			return STATUS_NONEXISTENT_SECTOR;
557		case ERRnopaper:
558			return STATUS_DEVICE_PAPER_EMPTY;
559		case ERRwrite:
560			return STATUS_IO_DEVICE_ERROR;
561		case ERRread:
562			return STATUS_IO_DEVICE_ERROR;
563		case ERRgeneral:
564			return STATUS_UNSUCCESSFUL;
565		case ERRbadshare:
566			return STATUS_SHARING_VIOLATION;
567		case ERRlock:
568			return STATUS_FILE_LOCK_CONFLICT;
569		case ERRwrongdisk:
570			return STATUS_WRONG_VOLUME;
571		case ERRFCBunavail:
572			return STATUS_UNSUCCESSFUL;
573		case ERRsharebufexc:
574			return STATUS_UNSUCCESSFUL;
575		case ERRdiskfull:
576			return STATUS_DISK_FULL;
577		default:
578			break;
579	}
580	return STATUS_UNSUCCESSFUL;
581}
582
583uint32_t
584smb_errClassCodes_to_ntstatus(uint8_t errClass, uint16_t errCode)
585{
586	switch (errClass) {
587		case ERRDOS_Class:
588			return smb_dos_class_err_to_ntstatus(errCode);
589			break;
590		case ERRSRV_Class:
591			return smb_srv_class_err_to_ntstatus(errCode);
592			break;
593		case ERRHRD_Class:
594			return smb_hrd_class_err_to_ntstatus(errCode);
595			break;
596		case SUCCESS_Class:
597			if (!errCode) {
598				return 0;
599			}
600			/* Fall through have no idea what to do here */
601		default:
602			break;
603	}
604	return STATUS_UNSUCCESSFUL;
605}
606
607static uint32_t
608smb_ntstatus_error_to_errno(uint32_t ntstatus)
609{
610	int	ii;
611
612	for (ii = 0; nt2errno[ii].errno; ii++)
613		if (nt2errno[ii].nterr == ntstatus)
614			return (nt2errno[ii].errno);
615
616	SMBERROR("Couldn't map ntstatus (0x%x) to errno returning EIO\n", ntstatus);
617	return EIO;
618}
619
620static uint32_t
621smb_ntstatus_warning_to_errno(uint32_t ntstatus)
622{
623	switch (ntstatus) {
624		case STATUS_BUFFER_OVERFLOW:
625			/*  Do a special check for STATUS_BUFFER_OVERFLOW; it's not an error. */
626			return 0;
627			break;
628		case STATUS_NO_MORE_FILES:
629			/*  Do a special check for STATUS_NO_MORE_FILES; it's not an error. */
630			return ENOENT;
631			break;
632		case STATUS_STOPPED_ON_SYMLINK:
633			return EIO; /* May want to change this to access denied, but leave the same error for now */
634			break;
635		default:
636			break;
637	}
638	/* XXX - How should we treat ntstatus warnings? */
639	SMBERROR("Couldn't map ntstatus (0x%x) to errno returning EIO\n", ntstatus);
640	return EIO;
641}
642
643uint32_t
644smb_ntstatus_to_errno(uint32_t ntstatus)
645{
646	switch (ntstatus & STATUS_SEVERITY_MASK) {
647		case STATUS_SEVERITY_SUCCESS:
648            /*
649             * Lion Servers returns STATUS_NOTIFY_ENUM_DIR, which just tells
650             * the notify code that something has changed. Just skip printing
651             * the warning since we know why this is being returned.
652             */
653			if ((ntstatus == STATUS_SUCCESS) ||
654                (ntstatus == STATUS_NOTIFY_ENUM_DIR) ||
655                (ntstatus == STATUS_NOTIFY_CLEANUP)) {
656				return 0;
657			}
658			SMBWARNING("STATUS_SEVERITY_SUCCESS ntstatus = 0x%x\n", ntstatus);
659			return 0;
660			break;
661		case STATUS_SEVERITY_INFORMATIONAL:
662			SMBWARNING("STATUS_SEVERITY_INFORMATIONAL ntstatus = 0x%x\n", ntstatus);
663			return 0;
664			break;
665		case STATUS_SEVERITY_WARNING:
666			return smb_ntstatus_warning_to_errno(ntstatus);
667			break;
668		case STATUS_SEVERITY_ERROR:
669			return smb_ntstatus_error_to_errno(ntstatus);
670			break;
671		default:
672			break;
673	}
674	return EIO;
675}
676
677int
678smb_put_dmem(struct mbchain *mbp, const char *src, size_t srcSize,
679				 int flags, int usingUnicode, size_t *lenp)
680{
681	char convbuf[512];
682	char *utf16Str;
683	char *dst;
684	size_t utf16InLen, utf16OutLen;
685	int error;
686
687	if (srcSize == 0)
688		return 0;
689	/* Just to be safe make sure we have room for the null bytes */
690	utf16InLen = (srcSize * 2) + 2;
691	/* We need a bigger buffer */
692	if (utf16InLen > sizeof(convbuf)) {
693		SMB_MALLOC(utf16Str, void *, utf16InLen, M_TEMP, M_WAITOK);
694		if (!utf16Str)
695			return ENOMEM;
696
697	} else {
698		/* Just to be safe behave the same as before */
699		utf16InLen = sizeof(convbuf);
700		utf16Str = convbuf;
701	}
702
703	utf16OutLen = utf16InLen;
704	dst = utf16Str;
705
706	error = smb_convert_to_network(&src, &srcSize, &dst, &utf16OutLen, flags,
707								   usingUnicode);
708	if (error)
709		goto done;
710
711	utf16OutLen = utf16InLen - utf16OutLen;
712	if (usingUnicode)
713		mb_put_padbyte(mbp);
714	error = mb_put_mem(mbp, utf16Str, utf16OutLen, MB_MSYSTEM);
715	if (!error && lenp)
716		*lenp += utf16OutLen;
717done:
718	/* We allocated it so free it */
719	if (utf16Str != convbuf) {
720		SMB_FREE(utf16Str, M_TEMP);
721	}
722
723	return error;
724}
725
726int smb_put_dstring(struct mbchain *mbp, int usingUnicode, const char *src,
727					size_t maxlen, int flags)
728{
729	int error;
730
731	error = smb_put_dmem(mbp, src, strnlen(src, maxlen), flags, usingUnicode, NULL);
732	if (error)
733		return error;
734	if (usingUnicode)
735		return mb_put_uint16le(mbp, 0);
736	return mb_put_uint8(mbp, 0);
737}
738