xref: /freebsd/sys/netsmb/smb_subr.c (revision 90af4afacb3d76aba2261a2dba4a1c5f69670a19)
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  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *    This product includes software developed by Boris Popov.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD$
33  */
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/endian.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/proc.h>
40 #include <sys/lock.h>
41 #include <sys/sysctl.h>
42 #include <sys/socket.h>
43 #include <sys/signalvar.h>
44 #include <sys/mbuf.h>
45 
46 #include <sys/iconv.h>
47 
48 #include <netsmb/smb.h>
49 #include <netsmb/smb_conn.h>
50 #include <netsmb/smb_rq.h>
51 #include <netsmb/smb_subr.h>
52 
53 MALLOC_DEFINE(M_SMBDATA, "SMBDATA", "Misc netsmb data");
54 MALLOC_DEFINE(M_SMBSTR, "SMBSTR", "netsmb string data");
55 MALLOC_DEFINE(M_SMBTEMP, "SMBTEMP", "Temp netsmb data");
56 
57 smb_unichar smb_unieol = 0;
58 
59 void
60 smb_makescred(struct smb_cred *scred, struct thread *td, struct ucred *cred)
61 {
62 	if (td) {
63 		scred->scr_td = td;
64 		scred->scr_cred = cred ? cred : td->td_ucred;
65 	} else {
66 		scred->scr_td = NULL;
67 		scred->scr_cred = cred ? cred : NULL;
68 	}
69 }
70 
71 int
72 smb_td_intr(struct thread *td)
73 {
74 	struct proc *p;
75 	sigset_t tmpset;
76 
77 	if (td == NULL)
78 		return 0;
79 
80 	p = td->td_proc;
81 	PROC_LOCK(p);
82 	tmpset = p->p_siglist;
83 	SIGSETOR(tmpset, td->td_siglist);
84 	SIGSETNAND(tmpset, td->td_sigmask);
85 	mtx_lock(&p->p_sigacts->ps_mtx);
86 	SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
87 	mtx_unlock(&p->p_sigacts->ps_mtx);
88 	if (SIGNOTEMPTY(td->td_siglist) && SMB_SIGMASK(tmpset)) {
89 		PROC_UNLOCK(p);
90                 return EINTR;
91 	}
92 	PROC_UNLOCK(p);
93 	return 0;
94 }
95 
96 char *
97 smb_strdup(const char *s)
98 {
99 	char *p;
100 	int len;
101 
102 	len = s ? strlen(s) + 1 : 1;
103 	p = malloc(len, M_SMBSTR, M_WAITOK);
104 	if (s)
105 		bcopy(s, p, len);
106 	else
107 		*p = 0;
108 	return p;
109 }
110 
111 /*
112  * duplicate string from a user space.
113  */
114 char *
115 smb_strdupin(char *s, int maxlen)
116 {
117 	char *p, bt;
118 	int len = 0;
119 
120 	for (p = s; ;p++) {
121 		if (copyin(p, &bt, 1))
122 			return NULL;
123 		len++;
124 		if (maxlen && len > maxlen)
125 			return NULL;
126 		if (bt == 0)
127 			break;
128 	}
129 	p = malloc(len, M_SMBSTR, M_WAITOK);
130 	copyin(s, p, len);
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 183:
267 			return EEXIST;
268 		    case ERRquota:
269 			return EDQUOT;
270 		}
271 		break;
272 	    case ERRSRV:
273 		switch (eno) {
274 		    case ERRerror:
275 			return EINVAL;
276 		    case ERRbadpw:
277 		    case ERRpasswordExpired:
278 			return EAUTH;
279 		    case ERRaccess:
280 			return EACCES;
281 		    case ERRinvnid:
282 			return ENETRESET;
283 		    case ERRinvnetname:
284 			SMBERROR("NetBIOS name is invalid\n");
285 			return EAUTH;
286 		    case 3:		/* reserved and returned */
287 			return EIO;
288 		    case ERRaccountExpired:
289 		    case ERRbadClient:
290 		    case ERRbadLogonTime:
291 			return EPERM;
292 		    case ERRnosupport:
293 			return EBADRPC;
294 		}
295 		break;
296 	    case ERRHRD:
297 		switch (eno) {
298 		    case ERRnowrite:
299 			return EROFS;
300 		    case ERRbadunit:
301 			return ENODEV;
302 		    case ERRnotready:
303 		    case ERRbadcmd:
304 		    case ERRdata:
305 			return EIO;
306 		    case ERRbadreq:
307 			return EBADRPC;
308 		    case ERRbadshare:
309 			return ETXTBSY;
310 		    case ERRlock:
311 			return EDEADLK;
312 		}
313 		break;
314 	}
315 	SMBERROR("Unmapped error %d:%d\n", eclass, eno);
316 	return EBADRPC;
317 }
318 
319 static int
320 smb_copy_iconv(struct mbchain *mbp, c_caddr_t src, caddr_t dst, size_t len)
321 {
322 	size_t outlen = len;
323 
324 	return iconv_conv((struct iconv_drv*)mbp->mb_udata, &src, &len, &dst, &outlen);
325 }
326 
327 int
328 smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
329 	int size, int caseopt)
330 {
331 	struct iconv_drv *dp = vcp->vc_toserver;
332 
333 	if (size == 0)
334 		return 0;
335 	if (dp == NULL) {
336 		return mb_put_mem(mbp, src, size, MB_MSYSTEM);
337 	}
338 	mbp->mb_copy = smb_copy_iconv;
339 	mbp->mb_udata = dp;
340 	return mb_put_mem(mbp, src, size, MB_MCUSTOM);
341 }
342 
343 int
344 smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
345 	int caseopt)
346 {
347 	int error;
348 
349 	error = smb_put_dmem(mbp, vcp, src, strlen(src), caseopt);
350 	if (error)
351 		return error;
352 	return mb_put_uint8(mbp, 0);
353 }
354 
355 int
356 smb_put_asunistring(struct smb_rq *rqp, const char *src)
357 {
358 	struct mbchain *mbp = &rqp->sr_rq;
359 	struct iconv_drv *dp = rqp->sr_vc->vc_toserver;
360 	u_char c;
361 	int error;
362 
363 	while (*src) {
364 		iconv_convmem(dp, &c, src++, 1);
365 		error = mb_put_uint16le(mbp, c);
366 		if (error)
367 			return error;
368 	}
369 	return mb_put_uint16le(mbp, 0);
370 }
371