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
smb_makescred(struct smb_cred * scred,struct thread * td,struct ucred * cred)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
smb_td_intr(struct thread * td)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 *
smb_strdup(const char * s)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 *
smb_strdupin(char * s,size_t maxlen)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 *
smb_memdupin(void * umem,size_t len)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 *
smb_memdup(const void * umem,int len)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
smb_strfree(char * s)157681a5bbeSBoris Popov smb_strfree(char *s)
158681a5bbeSBoris Popov {
159681a5bbeSBoris Popov free(s, M_SMBSTR);
160681a5bbeSBoris Popov }
161681a5bbeSBoris Popov
162681a5bbeSBoris Popov void
smb_memfree(void * s)163681a5bbeSBoris Popov smb_memfree(void *s)
164681a5bbeSBoris Popov {
165681a5bbeSBoris Popov free(s, M_SMBSTR);
166681a5bbeSBoris Popov }
167681a5bbeSBoris Popov
168681a5bbeSBoris Popov void *
smb_zmalloc(size_t size,struct malloc_type * type,int flags)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
smb_strtouni(u_int16_t * dst,const char * src)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
m_dumpm(struct mbuf * m)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
smb_maperror(int eclass,int eno)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
smb_copy_iconv(struct mbchain * mbp,c_caddr_t src,caddr_t dst,size_t * srclen,size_t * dstlen)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
smb_put_dmem(struct mbchain * mbp,struct smb_vc * vcp,const char * src,size_t size,int caseopt)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
smb_put_dstring(struct mbchain * mbp,struct smb_vc * vcp,const char * src,int caseopt)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
smb_put_asunistring(struct smb_rq * rqp,const char * src)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