xref: /freebsd-src/sys/netsmb/smb_subr.c (revision 6e50988cf822f87a524b8da2fdc35b234078cc2f)
1c398230bSWarner Losh /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni  *
4681a5bbeSBoris Popov  * Copyright (c) 2000-2001 Boris Popov
5681a5bbeSBoris Popov  * All rights reserved.
6681a5bbeSBoris Popov  *
7681a5bbeSBoris Popov  * Redistribution and use in source and binary forms, with or without
8681a5bbeSBoris Popov  * modification, are permitted provided that the following conditions
9681a5bbeSBoris Popov  * are met:
10681a5bbeSBoris Popov  * 1. Redistributions of source code must retain the above copyright
11681a5bbeSBoris Popov  *    notice, this list of conditions and the following disclaimer.
12681a5bbeSBoris Popov  * 2. Redistributions in binary form must reproduce the above copyright
13681a5bbeSBoris Popov  *    notice, this list of conditions and the following disclaimer in the
14681a5bbeSBoris Popov  *    documentation and/or other materials provided with the distribution.
15681a5bbeSBoris Popov  *
16681a5bbeSBoris Popov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17681a5bbeSBoris Popov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18681a5bbeSBoris Popov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19681a5bbeSBoris Popov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20681a5bbeSBoris Popov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21681a5bbeSBoris Popov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22681a5bbeSBoris Popov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23681a5bbeSBoris Popov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24681a5bbeSBoris Popov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25681a5bbeSBoris Popov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26681a5bbeSBoris Popov  * SUCH DAMAGE.
27681a5bbeSBoris Popov  */
28ab0de15bSDavid E. O'Brien 
29681a5bbeSBoris Popov #include <sys/param.h>
30681a5bbeSBoris Popov #include <sys/systm.h>
31a30d4b32SMike Barcroft #include <sys/endian.h>
32681a5bbeSBoris Popov #include <sys/kernel.h>
33681a5bbeSBoris Popov #include <sys/malloc.h>
34681a5bbeSBoris Popov #include <sys/proc.h>
35681a5bbeSBoris Popov #include <sys/lock.h>
36681a5bbeSBoris Popov #include <sys/sysctl.h>
37681a5bbeSBoris Popov #include <sys/socket.h>
38681a5bbeSBoris Popov #include <sys/signalvar.h>
39681a5bbeSBoris Popov #include <sys/mbuf.h>
40681a5bbeSBoris Popov 
41681a5bbeSBoris Popov #include <sys/iconv.h>
42681a5bbeSBoris Popov 
43681a5bbeSBoris Popov #include <netsmb/smb.h>
44681a5bbeSBoris Popov #include <netsmb/smb_conn.h>
45681a5bbeSBoris Popov #include <netsmb/smb_rq.h>
46681a5bbeSBoris Popov #include <netsmb/smb_subr.h>
47681a5bbeSBoris Popov 
48d745c852SEd Schouten static MALLOC_DEFINE(M_SMBDATA, "SMBDATA", "Misc netsmb data");
49d745c852SEd Schouten static MALLOC_DEFINE(M_SMBSTR, "SMBSTR", "netsmb string data");
50681a5bbeSBoris Popov MALLOC_DEFINE(M_SMBTEMP, "SMBTEMP", "Temp netsmb data");
51681a5bbeSBoris Popov 
52681a5bbeSBoris Popov smb_unichar smb_unieol = 0;
53681a5bbeSBoris Popov 
54681a5bbeSBoris Popov void
55fce6fbfaSBoris Popov smb_makescred(struct smb_cred *scred, struct thread *td, struct ucred *cred)
56681a5bbeSBoris Popov {
57fce6fbfaSBoris Popov 	if (td) {
58fce6fbfaSBoris Popov 		scred->scr_td = td;
59a854ed98SJohn Baldwin 		scred->scr_cred = cred ? cred : td->td_ucred;
60681a5bbeSBoris Popov 	} else {
61fce6fbfaSBoris Popov 		scred->scr_td = NULL;
62681a5bbeSBoris Popov 		scred->scr_cred = cred ? cred : NULL;
63681a5bbeSBoris Popov 	}
64681a5bbeSBoris Popov }
65681a5bbeSBoris Popov 
66681a5bbeSBoris Popov int
674093529dSJeff Roberson smb_td_intr(struct thread *td)
68681a5bbeSBoris Popov {
694093529dSJeff Roberson 	struct proc *p;
70681a5bbeSBoris Popov 	sigset_t tmpset;
71681a5bbeSBoris Popov 
724093529dSJeff Roberson 	if (td == NULL)
73681a5bbeSBoris Popov 		return 0;
744093529dSJeff Roberson 
754093529dSJeff Roberson 	p = td->td_proc;
76fbbad444STim J. Robbins 	PROC_LOCK(p);
771d9c5696SJuli Mallett 	tmpset = p->p_siglist;
784093529dSJeff Roberson 	SIGSETOR(tmpset, td->td_siglist);
794093529dSJeff Roberson 	SIGSETNAND(tmpset, td->td_sigmask);
8090af4afaSJohn Baldwin 	mtx_lock(&p->p_sigacts->ps_mtx);
8190af4afaSJohn Baldwin 	SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
8290af4afaSJohn Baldwin 	mtx_unlock(&p->p_sigacts->ps_mtx);
834093529dSJeff Roberson 	if (SIGNOTEMPTY(td->td_siglist) && SMB_SIGMASK(tmpset)) {
84fbbad444STim J. Robbins 		PROC_UNLOCK(p);
85681a5bbeSBoris Popov                 return EINTR;
86fbbad444STim J. Robbins 	}
87fbbad444STim J. Robbins 	PROC_UNLOCK(p);
88681a5bbeSBoris Popov 	return 0;
89681a5bbeSBoris Popov }
90681a5bbeSBoris Popov 
91681a5bbeSBoris Popov char *
92681a5bbeSBoris Popov smb_strdup(const char *s)
93681a5bbeSBoris Popov {
94681a5bbeSBoris Popov 	char *p;
95a67b22d6SChristian S.J. Peron 	size_t len;
96681a5bbeSBoris Popov 
97681a5bbeSBoris Popov 	len = s ? strlen(s) + 1 : 1;
98a163d034SWarner Losh 	p = malloc(len, M_SMBSTR, M_WAITOK);
99681a5bbeSBoris Popov 	if (s)
100681a5bbeSBoris Popov 		bcopy(s, p, len);
101681a5bbeSBoris Popov 	else
102681a5bbeSBoris Popov 		*p = 0;
103681a5bbeSBoris Popov 	return p;
104681a5bbeSBoris Popov }
105681a5bbeSBoris Popov 
106681a5bbeSBoris Popov /*
107681a5bbeSBoris Popov  * duplicate string from a user space.
108681a5bbeSBoris Popov  */
109681a5bbeSBoris Popov char *
110a67b22d6SChristian S.J. Peron smb_strdupin(char *s, size_t maxlen)
111681a5bbeSBoris Popov {
11251bcc337SConrad Meyer 	char *p;
113a67b22d6SChristian S.J. Peron 	int error;
114681a5bbeSBoris Popov 
11551bcc337SConrad Meyer 	p = malloc(maxlen + 1, M_SMBSTR, M_WAITOK);
11651bcc337SConrad Meyer 	error = copyinstr(s, p, maxlen + 1, NULL);
117ed9e2ed4SChristian S.J. Peron 	if (error) {
118ed9e2ed4SChristian S.J. Peron 		free(p, M_SMBSTR);
119ed9e2ed4SChristian S.J. Peron 		return (NULL);
120ed9e2ed4SChristian S.J. Peron 	}
121681a5bbeSBoris Popov 	return p;
122681a5bbeSBoris Popov }
123681a5bbeSBoris Popov 
124681a5bbeSBoris Popov /*
125681a5bbeSBoris Popov  * duplicate memory block from a user space.
126681a5bbeSBoris Popov  */
127681a5bbeSBoris Popov void *
128a67b22d6SChristian S.J. Peron smb_memdupin(void *umem, size_t len)
129681a5bbeSBoris Popov {
130681a5bbeSBoris Popov 	char *p;
131681a5bbeSBoris Popov 
132681a5bbeSBoris Popov 	if (len > 8 * 1024)
133681a5bbeSBoris Popov 		return NULL;
134a163d034SWarner Losh 	p = malloc(len, M_SMBSTR, M_WAITOK);
135681a5bbeSBoris Popov 	if (copyin(umem, p, len) == 0)
136681a5bbeSBoris Popov 		return p;
137681a5bbeSBoris Popov 	free(p, M_SMBSTR);
138681a5bbeSBoris Popov 	return NULL;
139681a5bbeSBoris Popov }
140681a5bbeSBoris Popov 
141681a5bbeSBoris Popov /*
142681a5bbeSBoris Popov  * duplicate memory block in the kernel space.
143681a5bbeSBoris Popov  */
144681a5bbeSBoris Popov void *
145681a5bbeSBoris Popov smb_memdup(const void *umem, int len)
146681a5bbeSBoris Popov {
147681a5bbeSBoris Popov 	char *p;
148681a5bbeSBoris Popov 
149681a5bbeSBoris Popov 	if (len > 8 * 1024)
150681a5bbeSBoris Popov 		return NULL;
151a163d034SWarner Losh 	p = malloc(len, M_SMBSTR, M_WAITOK);
152681a5bbeSBoris Popov 	bcopy(umem, p, len);
153681a5bbeSBoris Popov 	return p;
154681a5bbeSBoris Popov }
155681a5bbeSBoris Popov 
156681a5bbeSBoris Popov void
157681a5bbeSBoris Popov smb_strfree(char *s)
158681a5bbeSBoris Popov {
159681a5bbeSBoris Popov 	free(s, M_SMBSTR);
160681a5bbeSBoris Popov }
161681a5bbeSBoris Popov 
162681a5bbeSBoris Popov void
163681a5bbeSBoris Popov smb_memfree(void *s)
164681a5bbeSBoris Popov {
165681a5bbeSBoris Popov 	free(s, M_SMBSTR);
166681a5bbeSBoris Popov }
167681a5bbeSBoris Popov 
168681a5bbeSBoris Popov void *
169a67b22d6SChristian S.J. Peron smb_zmalloc(size_t size, struct malloc_type *type, int flags)
170681a5bbeSBoris Popov {
171681a5bbeSBoris Popov 
172681a5bbeSBoris Popov 	return malloc(size, type, flags | M_ZERO);
173681a5bbeSBoris Popov }
174681a5bbeSBoris Popov 
175681a5bbeSBoris Popov void
176681a5bbeSBoris Popov smb_strtouni(u_int16_t *dst, const char *src)
177681a5bbeSBoris Popov {
178681a5bbeSBoris Popov 	while (*src) {
1790adb6d7aSRobert Drehmel 		*dst++ = htole16(*src++);
180681a5bbeSBoris Popov 	}
181681a5bbeSBoris Popov 	*dst = 0;
182681a5bbeSBoris Popov }
183681a5bbeSBoris Popov 
184681a5bbeSBoris Popov #ifdef SMB_SOCKETDATA_DEBUG
185681a5bbeSBoris Popov void
186681a5bbeSBoris Popov m_dumpm(struct mbuf *m) {
187681a5bbeSBoris Popov 	char *p;
188a67b22d6SChristian S.J. Peron 	size_t len;
189681a5bbeSBoris Popov 	printf("d=");
190681a5bbeSBoris Popov 	while(m) {
191681a5bbeSBoris Popov 		p=mtod(m,char *);
192681a5bbeSBoris Popov 		len=m->m_len;
193a67b22d6SChristian S.J. Peron 		printf("(%zu)",len);
194681a5bbeSBoris Popov 		while(len--){
195681a5bbeSBoris Popov 			printf("%02x ",((int)*(p++)) & 0xff);
196681a5bbeSBoris Popov 		}
197681a5bbeSBoris Popov 		m=m->m_next;
19874b8d63dSPedro F. Giffuni 	}
199681a5bbeSBoris Popov 	printf("\n");
200681a5bbeSBoris Popov }
201681a5bbeSBoris Popov #endif
202681a5bbeSBoris Popov 
203681a5bbeSBoris Popov int
204681a5bbeSBoris Popov smb_maperror(int eclass, int eno)
205681a5bbeSBoris Popov {
206681a5bbeSBoris Popov 	if (eclass == 0 && eno == 0)
207681a5bbeSBoris Popov 		return 0;
208681a5bbeSBoris Popov 	switch (eclass) {
209681a5bbeSBoris Popov 	    case ERRDOS:
210681a5bbeSBoris Popov 		switch (eno) {
211681a5bbeSBoris Popov 		    case ERRbadfunc:
212681a5bbeSBoris Popov 		    case ERRbadmcb:
213681a5bbeSBoris Popov 		    case ERRbadenv:
214681a5bbeSBoris Popov 		    case ERRbadformat:
215681a5bbeSBoris Popov 		    case ERRrmuns:
216681a5bbeSBoris Popov 			return EINVAL;
217681a5bbeSBoris Popov 		    case ERRbadfile:
218681a5bbeSBoris Popov 		    case ERRbadpath:
219681a5bbeSBoris Popov 		    case ERRremcd:
220681a5bbeSBoris Popov 		    case 66:		/* nt returns it when share not available */
221fe98760eSBoris Popov 		    case 67:		/* observed from nt4sp6 when sharename wrong */
222681a5bbeSBoris Popov 			return ENOENT;
223681a5bbeSBoris Popov 		    case ERRnofids:
224681a5bbeSBoris Popov 			return EMFILE;
225681a5bbeSBoris Popov 		    case ERRnoaccess:
226681a5bbeSBoris Popov 		    case ERRbadshare:
227681a5bbeSBoris Popov 			return EACCES;
228681a5bbeSBoris Popov 		    case ERRbadfid:
229681a5bbeSBoris Popov 			return EBADF;
230681a5bbeSBoris Popov 		    case ERRnomem:
231681a5bbeSBoris Popov 			return ENOMEM;	/* actually remote no mem... */
232681a5bbeSBoris Popov 		    case ERRbadmem:
233681a5bbeSBoris Popov 			return EFAULT;
234681a5bbeSBoris Popov 		    case ERRbadaccess:
235681a5bbeSBoris Popov 			return EACCES;
236681a5bbeSBoris Popov 		    case ERRbaddata:
237681a5bbeSBoris Popov 			return E2BIG;
238681a5bbeSBoris Popov 		    case ERRbaddrive:
239681a5bbeSBoris Popov 		    case ERRnotready:	/* nt */
240681a5bbeSBoris Popov 			return ENXIO;
241681a5bbeSBoris Popov 		    case ERRdiffdevice:
242681a5bbeSBoris Popov 			return EXDEV;
243681a5bbeSBoris Popov 		    case ERRnofiles:
244681a5bbeSBoris Popov 			return 0;	/* eeof ? */
245681a5bbeSBoris Popov 			return ETXTBSY;
246681a5bbeSBoris Popov 		    case ERRlock:
247681a5bbeSBoris Popov 			return EDEADLK;
248681a5bbeSBoris Popov 		    case ERRfilexists:
249681a5bbeSBoris Popov 			return EEXIST;
250681a5bbeSBoris Popov 		    case 123:		/* dunno what is it, but samba maps as noent */
251681a5bbeSBoris Popov 			return ENOENT;
252681a5bbeSBoris Popov 		    case 145:		/* samba */
253681a5bbeSBoris Popov 			return ENOTEMPTY;
254834340aeSBoris Popov 		    case ERRnotlocked:
255834340aeSBoris Popov 			return 0;	/* file become unlocked */
256681a5bbeSBoris Popov 		    case 183:
257681a5bbeSBoris Popov 			return EEXIST;
258af9b5e8fSBoris Popov 		    case ERRquota:
259af9b5e8fSBoris Popov 			return EDQUOT;
260681a5bbeSBoris Popov 		}
261681a5bbeSBoris Popov 		break;
262681a5bbeSBoris Popov 	    case ERRSRV:
263681a5bbeSBoris Popov 		switch (eno) {
264681a5bbeSBoris Popov 		    case ERRerror:
265681a5bbeSBoris Popov 			return EINVAL;
266681a5bbeSBoris Popov 		    case ERRbadpw:
267af9b5e8fSBoris Popov 		    case ERRpasswordExpired:
268681a5bbeSBoris Popov 			return EAUTH;
269681a5bbeSBoris Popov 		    case ERRaccess:
270681a5bbeSBoris Popov 			return EACCES;
271681a5bbeSBoris Popov 		    case ERRinvnid:
272681a5bbeSBoris Popov 			return ENETRESET;
273681a5bbeSBoris Popov 		    case ERRinvnetname:
274681a5bbeSBoris Popov 			SMBERROR("NetBIOS name is invalid\n");
275681a5bbeSBoris Popov 			return EAUTH;
276681a5bbeSBoris Popov 		    case 3:		/* reserved and returned */
277681a5bbeSBoris Popov 			return EIO;
278af9b5e8fSBoris Popov 		    case ERRaccountExpired:
279af9b5e8fSBoris Popov 		    case ERRbadClient:
280af9b5e8fSBoris Popov 		    case ERRbadLogonTime:
281681a5bbeSBoris Popov 			return EPERM;
282af9b5e8fSBoris Popov 		    case ERRnosupport:
283af9b5e8fSBoris Popov 			return EBADRPC;
284681a5bbeSBoris Popov 		}
285681a5bbeSBoris Popov 		break;
286681a5bbeSBoris Popov 	    case ERRHRD:
287681a5bbeSBoris Popov 		switch (eno) {
288681a5bbeSBoris Popov 		    case ERRnowrite:
289681a5bbeSBoris Popov 			return EROFS;
290681a5bbeSBoris Popov 		    case ERRbadunit:
291681a5bbeSBoris Popov 			return ENODEV;
292681a5bbeSBoris Popov 		    case ERRnotready:
293681a5bbeSBoris Popov 		    case ERRbadcmd:
294681a5bbeSBoris Popov 		    case ERRdata:
295681a5bbeSBoris Popov 			return EIO;
296681a5bbeSBoris Popov 		    case ERRbadreq:
297681a5bbeSBoris Popov 			return EBADRPC;
298681a5bbeSBoris Popov 		    case ERRbadshare:
299681a5bbeSBoris Popov 			return ETXTBSY;
300681a5bbeSBoris Popov 		    case ERRlock:
301681a5bbeSBoris Popov 			return EDEADLK;
302681a5bbeSBoris Popov 		}
303681a5bbeSBoris Popov 		break;
304681a5bbeSBoris Popov 	}
305681a5bbeSBoris Popov 	SMBERROR("Unmapped error %d:%d\n", eclass, eno);
306681a5bbeSBoris Popov 	return EBADRPC;
307681a5bbeSBoris Popov }
308681a5bbeSBoris Popov 
309681a5bbeSBoris Popov static int
310080e3a63SR. Imura smb_copy_iconv(struct mbchain *mbp, c_caddr_t src, caddr_t dst,
311080e3a63SR. Imura     size_t *srclen, size_t *dstlen)
312681a5bbeSBoris Popov {
313080e3a63SR. Imura 	int error;
314080e3a63SR. Imura 	size_t inlen = *srclen, outlen = *dstlen;
315681a5bbeSBoris Popov 
316080e3a63SR. Imura 	error = iconv_conv((struct iconv_drv*)mbp->mb_udata, &src, &inlen,
317080e3a63SR. Imura 	    &dst, &outlen);
318080e3a63SR. Imura 	if (inlen != *srclen || outlen != *dstlen) {
319080e3a63SR. Imura 		*srclen -= inlen;
320080e3a63SR. Imura 		*dstlen -= outlen;
321080e3a63SR. Imura 		return 0;
322080e3a63SR. Imura 	} else
323080e3a63SR. Imura 		return error;
324681a5bbeSBoris Popov }
325681a5bbeSBoris Popov 
326681a5bbeSBoris Popov int
327681a5bbeSBoris Popov smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
328a67b22d6SChristian S.J. Peron 	size_t size, int caseopt)
329681a5bbeSBoris Popov {
330681a5bbeSBoris Popov 	struct iconv_drv *dp = vcp->vc_toserver;
331681a5bbeSBoris Popov 
332681a5bbeSBoris Popov 	if (size == 0)
333681a5bbeSBoris Popov 		return 0;
334681a5bbeSBoris Popov 	if (dp == NULL) {
335681a5bbeSBoris Popov 		return mb_put_mem(mbp, src, size, MB_MSYSTEM);
336681a5bbeSBoris Popov 	}
337681a5bbeSBoris Popov 	mbp->mb_copy = smb_copy_iconv;
338681a5bbeSBoris Popov 	mbp->mb_udata = dp;
33941f1dcccSKevin Lo 	if (SMB_UNICODE_STRINGS(vcp))
34041f1dcccSKevin Lo 		mb_put_padbyte(mbp);
341681a5bbeSBoris Popov 	return mb_put_mem(mbp, src, size, MB_MCUSTOM);
342681a5bbeSBoris Popov }
343681a5bbeSBoris Popov 
344681a5bbeSBoris Popov int
345681a5bbeSBoris Popov smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
346681a5bbeSBoris Popov 	int caseopt)
347681a5bbeSBoris Popov {
348681a5bbeSBoris Popov 	int error;
349681a5bbeSBoris Popov 
350681a5bbeSBoris Popov 	error = smb_put_dmem(mbp, vcp, src, strlen(src), caseopt);
351681a5bbeSBoris Popov 	if (error)
352681a5bbeSBoris Popov 		return error;
35341f1dcccSKevin Lo 	if (SMB_UNICODE_STRINGS(vcp))
35441f1dcccSKevin Lo 		return mb_put_uint16le(mbp, 0);
355681a5bbeSBoris Popov 	return mb_put_uint8(mbp, 0);
356681a5bbeSBoris Popov }
357681a5bbeSBoris Popov 
358681a5bbeSBoris Popov int
359681a5bbeSBoris Popov smb_put_asunistring(struct smb_rq *rqp, const char *src)
360681a5bbeSBoris Popov {
361681a5bbeSBoris Popov 	struct mbchain *mbp = &rqp->sr_rq;
362681a5bbeSBoris Popov 	struct iconv_drv *dp = rqp->sr_vc->vc_toserver;
363681a5bbeSBoris Popov 	u_char c;
364681a5bbeSBoris Popov 	int error;
365681a5bbeSBoris Popov 
366681a5bbeSBoris Popov 	while (*src) {
367681a5bbeSBoris Popov 		iconv_convmem(dp, &c, src++, 1);
368681a5bbeSBoris Popov 		error = mb_put_uint16le(mbp, c);
369681a5bbeSBoris Popov 		if (error)
370681a5bbeSBoris Popov 			return error;
371681a5bbeSBoris Popov 	}
372681a5bbeSBoris Popov 	return mb_put_uint16le(mbp, 0);
373681a5bbeSBoris Popov }
374