1 /*	$NetBSD: smb_subr.c,v 1.37 2014/11/15 18:52:45 nakayama Exp $	*/
2 
3 /*
4  * Copyright (c) 2000-2001 Boris Popov
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *    This product includes software developed by Boris Popov.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * FreeBSD: src/sys/netsmb/smb_subr.c,v 1.6 2002/04/17 03:14:28 bp Exp
35  */
36 
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: smb_subr.c,v 1.37 2014/11/15 18:52:45 nakayama Exp $");
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
44 #include <sys/proc.h>
45 #include <sys/lock.h>
46 #include <sys/sysctl.h>
47 #include <sys/socket.h>
48 #include <sys/signal.h>
49 #include <sys/signalvar.h>
50 #include <sys/mbuf.h>
51 #include <sys/socketvar.h>		/* for M_SONAME */
52 #include <sys/kauth.h>
53 
54 #include <netsmb/iconv.h>
55 
56 #include <netsmb/smb.h>
57 #include <netsmb/smb_conn.h>
58 #include <netsmb/smb_rq.h>
59 #include <netsmb/smb_subr.h>
60 
61 const smb_unichar smb_unieol = 0;
62 
63 /* XXX M_SMBSTR could be static but that doesn't work with gcc 4.5 on alpha. */
64 MALLOC_DEFINE(M_SMBSTR, "smbstr", "SMB strings");
65 MALLOC_DEFINE(M_SMBTEMP, "smbtemp", "Temp netsmb data");
66 
67 void
smb_makescred(struct smb_cred * scred,struct lwp * l,kauth_cred_t cred)68 smb_makescred(struct smb_cred *scred, struct lwp *l, kauth_cred_t cred)
69 {
70 	if (l) {
71 		scred->scr_l = l;
72 		scred->scr_cred = cred ? cred : l->l_cred;
73 	} else {
74 		scred->scr_l = NULL;
75 		scred->scr_cred = cred ? cred : NULL;
76 	}
77 }
78 
79 int
smb_proc_intr(struct lwp * l)80 smb_proc_intr(struct lwp *l)
81 {
82 	struct proc *p;
83 	int error;
84 
85 	if (l == NULL)
86 		return 0;
87 	p = l->l_proc;
88 
89 	mutex_enter(p->p_lock);
90 	error = sigispending(l, 0);
91 	mutex_exit(p->p_lock);
92 
93 	return (error != 0 ? EINTR : 0);
94 }
95 
96 char *
smb_strdup(const char * s)97 smb_strdup(const char *s)
98 {
99 	char *p;
100 	size_t len;
101 
102 	len = s ? strlen(s) + 1 : 1;
103 	p = malloc(len, M_SMBSTR, M_WAITOK);
104 	if (s)
105 		memcpy(p, s, len);
106 	else
107 		*p = 0;
108 	return p;
109 }
110 
111 /*
112  * duplicate string from a user space.
113  */
114 char *
smb_strdupin(char * s,size_t maxlen)115 smb_strdupin(char *s, size_t maxlen)
116 {
117 	char *p, bt;
118 	size_t 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 *
smb_memdupin(void * umem,size_t len)138 smb_memdupin(void *umem, size_t 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 void
smb_strfree(char * s)152 smb_strfree(char *s)
153 {
154 	free(s, M_SMBSTR);
155 }
156 
157 void
smb_memfree(void * s)158 smb_memfree(void *s)
159 {
160 	free(s, M_SMBSTR);
161 }
162 
163 void *
smb_zmalloc(size_t size,struct malloc_type * type,int flags)164 smb_zmalloc(size_t size, struct malloc_type *type, int flags)
165 {
166 
167 	return malloc(size, type, flags | M_ZERO);
168 }
169 
170 void
smb_strtouni(u_int16_t * dst,const char * src)171 smb_strtouni(u_int16_t *dst, const char *src)
172 {
173 	while (*src) {
174 		*dst++ = htole16(*src++);
175 	}
176 	*dst = 0;
177 }
178 
179 #ifdef SMB_SOCKETDATA_DEBUG
180 void
m_dumpm(struct mbuf * m)181 m_dumpm(struct mbuf *m) {
182 	char *p;
183 	size_t len;
184 	printf("d=");
185 	while(m) {
186 		p = mtod(m,char *);
187 		len = m->m_len;
188 		printf("(%zu)", len);
189 		while(len--){
190 			printf("%02x ",((int)*(p++)) & 0xff);
191 		}
192 		m=m->m_next;
193 	};
194 	printf("\n");
195 }
196 #endif
197 
198 int
smb_maperror(int eclass,int eno)199 smb_maperror(int eclass, int eno)
200 {
201 	if (eclass == 0 && eno == 0)
202 		return 0;
203 	switch (eclass) {
204 	    case ERRDOS:
205 		switch (eno) {
206 		    case ERRbadfunc:
207 		    case ERRbadmcb:
208 		    case ERRbadenv:
209 		    case ERRbadformat:
210 		    case ERRrmuns:
211 			return EINVAL;
212 		    case ERRnofiles:
213 		    case ERRbadfile:
214 		    case ERRbadpath:
215 		    case ERRremcd:
216 		    case ERRnoipc: /* nt returns it when share not available */
217 		    case ERRnosuchshare:	/* observed from nt4sp6 when sharename wrong */
218 			return ENOENT;
219 		    case ERRnofids:
220 			return EMFILE;
221 		    case ERRnoaccess:
222 		    case ERRbadshare:
223 			return EACCES;
224 		    case ERRbadfid:
225 			return EBADF;
226 		    case ERRnomem:
227 			return ENOMEM;	/* actually remote no mem... */
228 		    case ERRbadmem:
229 			return EFAULT;
230 		    case ERRbadaccess:
231 			return EACCES;
232 		    case ERRbaddata:
233 			return E2BIG;
234 		    case ERRbaddrive:
235 		    case ERRnotready:	/* nt */
236 			return ENXIO;
237 		    case ERRdiffdevice:
238 			return EXDEV;
239 		    case ERRlock:
240 			return EDEADLK;
241 		    case ERRfilexists:
242 			return EEXIST;
243 		    case ERRinvalidname:	/* dunno what is it, but samba maps as noent */
244 			return ENOENT;
245 		    case ERRdirnempty:	/* samba */
246 			return ENOTEMPTY;
247 		    case ERRrename:
248 			return EEXIST;
249 		    case ERRquota:
250 			return EDQUOT;
251 		    case ERRnotlocked:
252 			/* it's okay to try to unlock already unlocked file */
253 			return 0;
254 		    case NT_STATUS_NOTIFY_ENUM_DIR:
255 			return EMSGSIZE;
256 		}
257 		break;
258 	    case ERRSRV:
259 		switch (eno) {
260 		    case ERRerror:
261 			return EINVAL;
262 		    case ERRbadpw:
263 		    case ERRpasswordExpired:
264 		    case ERRbaduid:
265 			return EAUTH;
266 		    case ERRaccess:
267 			return EACCES;
268 		    case ERRinvnid:
269 			return ENETRESET;
270 		    case ERRinvnetname:
271 			SMBERROR(("NetBIOS name is invalid\n"));
272 			return EAUTH;
273 		    case ERRbadtype:	/* reserved and returned */
274 			return EIO;
275 		    case ERRaccountExpired:
276 		    case ERRbadClient:
277 		    case ERRbadLogonTime:
278 			return EPERM;
279 		    case ERRnosupport:
280 			return EBADRPC;
281 		}
282 		break;
283 	    case ERRHRD:
284 		switch (eno) {
285 		    case ERRnowrite:
286 			return EROFS;
287 		    case ERRbadunit:
288 			return ENODEV;
289 		    case ERRnotready:
290 		    case ERRbadcmd:
291 		    case ERRdata:
292 			return EIO;
293 		    case ERRbadreq:
294 			return EBADRPC;
295 		    case ERRbadshare:
296 			return ETXTBSY;
297 		    case ERRlock:
298 			return EDEADLK;
299 		    case ERRgeneral:
300 			/* returned e.g. for NT CANCEL SMB by Samba */
301 			return ECANCELED;
302 		}
303 		break;
304 	}
305 	SMBERROR(("Unmapped error %d:%d\n", eclass, eno));
306 	return EBADRPC;
307 }
308 
309 static int
smb_copy_iconv(struct mbchain * mbp,const char * src,char * dst,size_t * srclen,size_t * dstlen)310 smb_copy_iconv(struct mbchain *mbp, const char *src, char *dst,
311     size_t *srclen, size_t *dstlen)
312 {
313 	int error;
314 	size_t inlen = *srclen, outlen = *dstlen;
315 
316 	error = iconv_conv((struct iconv_drv*)mbp->mb_udata, &src, &inlen,
317 	    &dst, &outlen);
318 	if (inlen != *srclen || outlen != *dstlen) {
319 		*srclen -= inlen;
320 		*dstlen -= outlen;
321 		return 0;
322 	} else
323 		return error;
324 }
325 
326 int
smb_put_dmem(struct mbchain * mbp,struct smb_vc * vcp,const char * src,size_t size,int caseopt)327 smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
328 	size_t size, int caseopt)
329 {
330 	struct iconv_drv *dp = vcp->vc_toserver;
331 
332 	if (size == 0)
333 		return 0;
334 	if (dp == NULL) {
335 		return mb_put_mem(mbp, (const void *)src, size, MB_MSYSTEM);
336 	}
337 	mbp->mb_copy = smb_copy_iconv;
338 	mbp->mb_udata = dp;
339 	return mb_put_mem(mbp, (const void *)src, size, MB_MCUSTOM);
340 }
341 
342 int
smb_put_dstring(struct mbchain * mbp,struct smb_vc * vcp,const char * src,int caseopt)343 smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
344 	int caseopt)
345 {
346 	int error;
347 
348 	error = smb_put_dmem(mbp, vcp, src, strlen(src), caseopt);
349 	if (error)
350 		return error;
351 	return mb_put_uint8(mbp, 0);
352 }
353 
354 #if 0
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 #endif
372 
373 struct sockaddr *
dup_sockaddr(struct sockaddr * sa,int canwait)374 dup_sockaddr(struct sockaddr *sa, int canwait)
375 {
376 	struct sockaddr *sa2;
377 
378 	sa2 = malloc(sa->sa_len, M_SONAME, canwait ? M_WAITOK : M_NOWAIT);
379 	if (sa2)
380 		memcpy(sa2, sa, sa->sa_len);
381 	return sa2;
382 }
383