xref: /freebsd/sys/netsmb/smb_subr.c (revision aa64588d28258aef88cc33b8043112e8856948d0)
1 /*-
2  * Copyright (c) 2000-2001 Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/endian.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #include <sys/proc.h>
36 #include <sys/lock.h>
37 #include <sys/sysctl.h>
38 #include <sys/socket.h>
39 #include <sys/signalvar.h>
40 #include <sys/mbuf.h>
41 
42 #include <sys/iconv.h>
43 
44 #include <netsmb/smb.h>
45 #include <netsmb/smb_conn.h>
46 #include <netsmb/smb_rq.h>
47 #include <netsmb/smb_subr.h>
48 
49 MALLOC_DEFINE(M_SMBDATA, "SMBDATA", "Misc netsmb data");
50 MALLOC_DEFINE(M_SMBSTR, "SMBSTR", "netsmb string data");
51 MALLOC_DEFINE(M_SMBTEMP, "SMBTEMP", "Temp netsmb data");
52 
53 smb_unichar smb_unieol = 0;
54 
55 void
56 smb_makescred(struct smb_cred *scred, struct thread *td, struct ucred *cred)
57 {
58 	if (td) {
59 		scred->scr_td = td;
60 		scred->scr_cred = cred ? cred : td->td_ucred;
61 	} else {
62 		scred->scr_td = NULL;
63 		scred->scr_cred = cred ? cred : NULL;
64 	}
65 }
66 
67 int
68 smb_td_intr(struct thread *td)
69 {
70 	struct proc *p;
71 	sigset_t tmpset;
72 
73 	if (td == NULL)
74 		return 0;
75 
76 	p = td->td_proc;
77 	PROC_LOCK(p);
78 	tmpset = p->p_siglist;
79 	SIGSETOR(tmpset, td->td_siglist);
80 	SIGSETNAND(tmpset, td->td_sigmask);
81 	mtx_lock(&p->p_sigacts->ps_mtx);
82 	SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
83 	mtx_unlock(&p->p_sigacts->ps_mtx);
84 	if (SIGNOTEMPTY(td->td_siglist) && SMB_SIGMASK(tmpset)) {
85 		PROC_UNLOCK(p);
86                 return EINTR;
87 	}
88 	PROC_UNLOCK(p);
89 	return 0;
90 }
91 
92 char *
93 smb_strdup(const char *s)
94 {
95 	char *p;
96 	int len;
97 
98 	len = s ? strlen(s) + 1 : 1;
99 	p = malloc(len, M_SMBSTR, M_WAITOK);
100 	if (s)
101 		bcopy(s, p, len);
102 	else
103 		*p = 0;
104 	return p;
105 }
106 
107 /*
108  * duplicate string from a user space.
109  */
110 char *
111 smb_strdupin(char *s, int maxlen)
112 {
113 	char *p, bt;
114 	int error, len = 0;
115 
116 	for (p = s; ;p++) {
117 		if (copyin(p, &bt, 1))
118 			return NULL;
119 		len++;
120 		if (maxlen && len > maxlen)
121 			return NULL;
122 		if (bt == 0)
123 			break;
124 	}
125 	p = malloc(len, M_SMBSTR, M_WAITOK);
126 	error = copyin(s, p, len);
127 	if (error) {
128 		free(p, M_SMBSTR);
129 		return (NULL);
130 	}
131 	return p;
132 }
133 
134 /*
135  * duplicate memory block from a user space.
136  */
137 void *
138 smb_memdupin(void *umem, int len)
139 {
140 	char *p;
141 
142 	if (len > 8 * 1024)
143 		return NULL;
144 	p = malloc(len, M_SMBSTR, M_WAITOK);
145 	if (copyin(umem, p, len) == 0)
146 		return p;
147 	free(p, M_SMBSTR);
148 	return NULL;
149 }
150 
151 /*
152  * duplicate memory block in the kernel space.
153  */
154 void *
155 smb_memdup(const void *umem, int len)
156 {
157 	char *p;
158 
159 	if (len > 8 * 1024)
160 		return NULL;
161 	p = malloc(len, M_SMBSTR, M_WAITOK);
162 	if (p == NULL)
163 		return NULL;
164 	bcopy(umem, p, len);
165 	return p;
166 }
167 
168 void
169 smb_strfree(char *s)
170 {
171 	free(s, M_SMBSTR);
172 }
173 
174 void
175 smb_memfree(void *s)
176 {
177 	free(s, M_SMBSTR);
178 }
179 
180 void *
181 smb_zmalloc(unsigned long size, struct malloc_type *type, int flags)
182 {
183 
184 	return malloc(size, type, flags | M_ZERO);
185 }
186 
187 void
188 smb_strtouni(u_int16_t *dst, const char *src)
189 {
190 	while (*src) {
191 		*dst++ = htole16(*src++);
192 	}
193 	*dst = 0;
194 }
195 
196 #ifdef SMB_SOCKETDATA_DEBUG
197 void
198 m_dumpm(struct mbuf *m) {
199 	char *p;
200 	int len;
201 	printf("d=");
202 	while(m) {
203 		p=mtod(m,char *);
204 		len=m->m_len;
205 		printf("(%d)",len);
206 		while(len--){
207 			printf("%02x ",((int)*(p++)) & 0xff);
208 		}
209 		m=m->m_next;
210 	};
211 	printf("\n");
212 }
213 #endif
214 
215 int
216 smb_maperror(int eclass, int eno)
217 {
218 	if (eclass == 0 && eno == 0)
219 		return 0;
220 	switch (eclass) {
221 	    case ERRDOS:
222 		switch (eno) {
223 		    case ERRbadfunc:
224 		    case ERRbadmcb:
225 		    case ERRbadenv:
226 		    case ERRbadformat:
227 		    case ERRrmuns:
228 			return EINVAL;
229 		    case ERRbadfile:
230 		    case ERRbadpath:
231 		    case ERRremcd:
232 		    case 66:		/* nt returns it when share not available */
233 		    case 67:		/* observed from nt4sp6 when sharename wrong */
234 			return ENOENT;
235 		    case ERRnofids:
236 			return EMFILE;
237 		    case ERRnoaccess:
238 		    case ERRbadshare:
239 			return EACCES;
240 		    case ERRbadfid:
241 			return EBADF;
242 		    case ERRnomem:
243 			return ENOMEM;	/* actually remote no mem... */
244 		    case ERRbadmem:
245 			return EFAULT;
246 		    case ERRbadaccess:
247 			return EACCES;
248 		    case ERRbaddata:
249 			return E2BIG;
250 		    case ERRbaddrive:
251 		    case ERRnotready:	/* nt */
252 			return ENXIO;
253 		    case ERRdiffdevice:
254 			return EXDEV;
255 		    case ERRnofiles:
256 			return 0;	/* eeof ? */
257 			return ETXTBSY;
258 		    case ERRlock:
259 			return EDEADLK;
260 		    case ERRfilexists:
261 			return EEXIST;
262 		    case 123:		/* dunno what is it, but samba maps as noent */
263 			return ENOENT;
264 		    case 145:		/* samba */
265 			return ENOTEMPTY;
266 		    case ERRnotlocked:
267 			return 0;	/* file become unlocked */
268 		    case 183:
269 			return EEXIST;
270 		    case ERRquota:
271 			return EDQUOT;
272 		}
273 		break;
274 	    case ERRSRV:
275 		switch (eno) {
276 		    case ERRerror:
277 			return EINVAL;
278 		    case ERRbadpw:
279 		    case ERRpasswordExpired:
280 			return EAUTH;
281 		    case ERRaccess:
282 			return EACCES;
283 		    case ERRinvnid:
284 			return ENETRESET;
285 		    case ERRinvnetname:
286 			SMBERROR("NetBIOS name is invalid\n");
287 			return EAUTH;
288 		    case 3:		/* reserved and returned */
289 			return EIO;
290 		    case ERRaccountExpired:
291 		    case ERRbadClient:
292 		    case ERRbadLogonTime:
293 			return EPERM;
294 		    case ERRnosupport:
295 			return EBADRPC;
296 		}
297 		break;
298 	    case ERRHRD:
299 		switch (eno) {
300 		    case ERRnowrite:
301 			return EROFS;
302 		    case ERRbadunit:
303 			return ENODEV;
304 		    case ERRnotready:
305 		    case ERRbadcmd:
306 		    case ERRdata:
307 			return EIO;
308 		    case ERRbadreq:
309 			return EBADRPC;
310 		    case ERRbadshare:
311 			return ETXTBSY;
312 		    case ERRlock:
313 			return EDEADLK;
314 		}
315 		break;
316 	}
317 	SMBERROR("Unmapped error %d:%d\n", eclass, eno);
318 	return EBADRPC;
319 }
320 
321 static int
322 smb_copy_iconv(struct mbchain *mbp, c_caddr_t src, caddr_t dst,
323     size_t *srclen, size_t *dstlen)
324 {
325 	int error;
326 	size_t inlen = *srclen, outlen = *dstlen;
327 
328 	error = iconv_conv((struct iconv_drv*)mbp->mb_udata, &src, &inlen,
329 	    &dst, &outlen);
330 	if (inlen != *srclen || outlen != *dstlen) {
331 		*srclen -= inlen;
332 		*dstlen -= outlen;
333 		return 0;
334 	} else
335 		return error;
336 }
337 
338 int
339 smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
340 	int size, int caseopt)
341 {
342 	struct iconv_drv *dp = vcp->vc_toserver;
343 
344 	if (size == 0)
345 		return 0;
346 	if (dp == NULL) {
347 		return mb_put_mem(mbp, src, size, MB_MSYSTEM);
348 	}
349 	mbp->mb_copy = smb_copy_iconv;
350 	mbp->mb_udata = dp;
351 	return mb_put_mem(mbp, src, size, MB_MCUSTOM);
352 }
353 
354 int
355 smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
356 	int caseopt)
357 {
358 	int error;
359 
360 	error = smb_put_dmem(mbp, vcp, src, strlen(src), caseopt);
361 	if (error)
362 		return error;
363 	return mb_put_uint8(mbp, 0);
364 }
365 
366 int
367 smb_put_asunistring(struct smb_rq *rqp, const char *src)
368 {
369 	struct mbchain *mbp = &rqp->sr_rq;
370 	struct iconv_drv *dp = rqp->sr_vc->vc_toserver;
371 	u_char c;
372 	int error;
373 
374 	while (*src) {
375 		iconv_convmem(dp, &c, src++, 1);
376 		error = mb_put_uint16le(mbp, c);
377 		if (error)
378 			return error;
379 	}
380 	return mb_put_uint16le(mbp, 0);
381 }
382