smb_subr.c revision 110849
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: head/sys/netsmb/smb_subr.c 110849 2003-02-14 09:12:12Z tjr $
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
53MALLOC_DEFINE(M_SMBDATA, "SMBDATA", "Misc netsmb data");
54MALLOC_DEFINE(M_SMBSTR, "SMBSTR", "netsmb string data");
55MALLOC_DEFINE(M_SMBTEMP, "SMBTEMP", "Temp netsmb data");
56
57smb_unichar smb_unieol = 0;
58
59void
60smb_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
71int
72smb_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
90char *
91smb_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, 0);
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 */
108char *
109smb_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, 0);
124	copyin(s, p, len);
125	return p;
126}
127
128/*
129 * duplicate memory block from a user space.
130 */
131void *
132smb_memdupin(void *umem, int len)
133{
134	char *p;
135
136	if (len > 8 * 1024)
137		return NULL;
138	p = malloc(len, M_SMBSTR, 0);
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 */
148void *
149smb_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, 0);
156	if (p == NULL)
157		return NULL;
158	bcopy(umem, p, len);
159	return p;
160}
161
162void
163smb_strfree(char *s)
164{
165	free(s, M_SMBSTR);
166}
167
168void
169smb_memfree(void *s)
170{
171	free(s, M_SMBSTR);
172}
173
174void *
175smb_zmalloc(unsigned long size, struct malloc_type *type, int flags)
176{
177
178	return malloc(size, type, flags | M_ZERO);
179}
180
181void
182smb_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
191void
192m_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
209int
210smb_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
313static int
314smb_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
321int
322smb_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
337int
338smb_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
349int
350smb_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