xref: /freebsd/sys/netsmb/smb_subr.c (revision f9218d3d4fd34f082473b3a021c6d4d109fb47cf)
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_proc_intr(struct proc *p)
73 {
74 	sigset_t tmpset;
75 
76 	if (p == NULL)
77 		return 0;
78 	PROC_LOCK(p);
79 	tmpset = p->p_siglist;
80 	SIGSETNAND(tmpset, p->p_sigmask);
81 	SIGSETNAND(tmpset, p->p_sigignore);
82 	if (SIGNOTEMPTY(p->p_siglist) && SMB_SIGMASK(tmpset)) {
83 		PROC_UNLOCK(p);
84                 return EINTR;
85 	}
86 	PROC_UNLOCK(p);
87 	return 0;
88 }
89 
90 char *
91 smb_strdup(const char *s)
92 {
93 	char *p;
94 	int len;
95 
96 	len = s ? strlen(s) + 1 : 1;
97 	p = malloc(len, M_SMBSTR, M_WAITOK);
98 	if (s)
99 		bcopy(s, p, len);
100 	else
101 		*p = 0;
102 	return p;
103 }
104 
105 /*
106  * duplicate string from a user space.
107  */
108 char *
109 smb_strdupin(char *s, int maxlen)
110 {
111 	char *p, bt;
112 	int len = 0;
113 
114 	for (p = s; ;p++) {
115 		if (copyin(p, &bt, 1))
116 			return NULL;
117 		len++;
118 		if (maxlen && len > maxlen)
119 			return NULL;
120 		if (bt == 0)
121 			break;
122 	}
123 	p = malloc(len, M_SMBSTR, M_WAITOK);
124 	copyin(s, p, len);
125 	return p;
126 }
127 
128 /*
129  * duplicate memory block from a user space.
130  */
131 void *
132 smb_memdupin(void *umem, int len)
133 {
134 	char *p;
135 
136 	if (len > 8 * 1024)
137 		return NULL;
138 	p = malloc(len, M_SMBSTR, M_WAITOK);
139 	if (copyin(umem, p, len) == 0)
140 		return p;
141 	free(p, M_SMBSTR);
142 	return NULL;
143 }
144 
145 /*
146  * duplicate memory block in the kernel space.
147  */
148 void *
149 smb_memdup(const void *umem, int len)
150 {
151 	char *p;
152 
153 	if (len > 8 * 1024)
154 		return NULL;
155 	p = malloc(len, M_SMBSTR, M_WAITOK);
156 	if (p == NULL)
157 		return NULL;
158 	bcopy(umem, p, len);
159 	return p;
160 }
161 
162 void
163 smb_strfree(char *s)
164 {
165 	free(s, M_SMBSTR);
166 }
167 
168 void
169 smb_memfree(void *s)
170 {
171 	free(s, M_SMBSTR);
172 }
173 
174 void *
175 smb_zmalloc(unsigned long size, struct malloc_type *type, int flags)
176 {
177 
178 	return malloc(size, type, flags | M_ZERO);
179 }
180 
181 void
182 smb_strtouni(u_int16_t *dst, const char *src)
183 {
184 	while (*src) {
185 		*dst++ = htole16(*src++);
186 	}
187 	*dst = 0;
188 }
189 
190 #ifdef SMB_SOCKETDATA_DEBUG
191 void
192 m_dumpm(struct mbuf *m) {
193 	char *p;
194 	int len;
195 	printf("d=");
196 	while(m) {
197 		p=mtod(m,char *);
198 		len=m->m_len;
199 		printf("(%d)",len);
200 		while(len--){
201 			printf("%02x ",((int)*(p++)) & 0xff);
202 		}
203 		m=m->m_next;
204 	};
205 	printf("\n");
206 }
207 #endif
208 
209 int
210 smb_maperror(int eclass, int eno)
211 {
212 	if (eclass == 0 && eno == 0)
213 		return 0;
214 	switch (eclass) {
215 	    case ERRDOS:
216 		switch (eno) {
217 		    case ERRbadfunc:
218 		    case ERRbadmcb:
219 		    case ERRbadenv:
220 		    case ERRbadformat:
221 		    case ERRrmuns:
222 			return EINVAL;
223 		    case ERRbadfile:
224 		    case ERRbadpath:
225 		    case ERRremcd:
226 		    case 66:		/* nt returns it when share not available */
227 		    case 67:		/* observed from nt4sp6 when sharename wrong */
228 			return ENOENT;
229 		    case ERRnofids:
230 			return EMFILE;
231 		    case ERRnoaccess:
232 		    case ERRbadshare:
233 			return EACCES;
234 		    case ERRbadfid:
235 			return EBADF;
236 		    case ERRnomem:
237 			return ENOMEM;	/* actually remote no mem... */
238 		    case ERRbadmem:
239 			return EFAULT;
240 		    case ERRbadaccess:
241 			return EACCES;
242 		    case ERRbaddata:
243 			return E2BIG;
244 		    case ERRbaddrive:
245 		    case ERRnotready:	/* nt */
246 			return ENXIO;
247 		    case ERRdiffdevice:
248 			return EXDEV;
249 		    case ERRnofiles:
250 			return 0;	/* eeof ? */
251 			return ETXTBSY;
252 		    case ERRlock:
253 			return EDEADLK;
254 		    case ERRfilexists:
255 			return EEXIST;
256 		    case 123:		/* dunno what is it, but samba maps as noent */
257 			return ENOENT;
258 		    case 145:		/* samba */
259 			return ENOTEMPTY;
260 		    case 183:
261 			return EEXIST;
262 		    case ERRquota:
263 			return EDQUOT;
264 		}
265 		break;
266 	    case ERRSRV:
267 		switch (eno) {
268 		    case ERRerror:
269 			return EINVAL;
270 		    case ERRbadpw:
271 		    case ERRpasswordExpired:
272 			return EAUTH;
273 		    case ERRaccess:
274 			return EACCES;
275 		    case ERRinvnid:
276 			return ENETRESET;
277 		    case ERRinvnetname:
278 			SMBERROR("NetBIOS name is invalid\n");
279 			return EAUTH;
280 		    case 3:		/* reserved and returned */
281 			return EIO;
282 		    case ERRaccountExpired:
283 		    case ERRbadClient:
284 		    case ERRbadLogonTime:
285 			return EPERM;
286 		    case ERRnosupport:
287 			return EBADRPC;
288 		}
289 		break;
290 	    case ERRHRD:
291 		switch (eno) {
292 		    case ERRnowrite:
293 			return EROFS;
294 		    case ERRbadunit:
295 			return ENODEV;
296 		    case ERRnotready:
297 		    case ERRbadcmd:
298 		    case ERRdata:
299 			return EIO;
300 		    case ERRbadreq:
301 			return EBADRPC;
302 		    case ERRbadshare:
303 			return ETXTBSY;
304 		    case ERRlock:
305 			return EDEADLK;
306 		}
307 		break;
308 	}
309 	SMBERROR("Unmapped error %d:%d\n", eclass, eno);
310 	return EBADRPC;
311 }
312 
313 static int
314 smb_copy_iconv(struct mbchain *mbp, c_caddr_t src, caddr_t dst, size_t len)
315 {
316 	size_t outlen = len;
317 
318 	return iconv_conv((struct iconv_drv*)mbp->mb_udata, &src, &len, &dst, &outlen);
319 }
320 
321 int
322 smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
323 	int size, int caseopt)
324 {
325 	struct iconv_drv *dp = vcp->vc_toserver;
326 
327 	if (size == 0)
328 		return 0;
329 	if (dp == NULL) {
330 		return mb_put_mem(mbp, src, size, MB_MSYSTEM);
331 	}
332 	mbp->mb_copy = smb_copy_iconv;
333 	mbp->mb_udata = dp;
334 	return mb_put_mem(mbp, src, size, MB_MCUSTOM);
335 }
336 
337 int
338 smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
339 	int caseopt)
340 {
341 	int error;
342 
343 	error = smb_put_dmem(mbp, vcp, src, strlen(src), caseopt);
344 	if (error)
345 		return error;
346 	return mb_put_uint8(mbp, 0);
347 }
348 
349 int
350 smb_put_asunistring(struct smb_rq *rqp, const char *src)
351 {
352 	struct mbchain *mbp = &rqp->sr_rq;
353 	struct iconv_drv *dp = rqp->sr_vc->vc_toserver;
354 	u_char c;
355 	int error;
356 
357 	while (*src) {
358 		iconv_convmem(dp, &c, src++, 1);
359 		error = mb_put_uint16le(mbp, c);
360 		if (error)
361 			return error;
362 	}
363 	return mb_put_uint16le(mbp, 0);
364 }
365