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
61const smb_unichar smb_unieol = 0;
62
63/* XXX M_SMBSTR could be static but that doesn't work with gcc 4.5 on alpha. */
64MALLOC_DEFINE(M_SMBSTR, "smbstr", "SMB strings");
65MALLOC_DEFINE(M_SMBTEMP, "smbtemp", "Temp netsmb data");
66
67void
68smb_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
79int
80smb_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
96char *
97smb_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 */
114char *
115smb_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 */
137void *
138smb_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
151void
152smb_strfree(char *s)
153{
154 free(s, M_SMBSTR);
155}
156
157void
158smb_memfree(void *s)
159{
160 free(s, M_SMBSTR);
161}
162
163void *
164smb_zmalloc(size_t size, struct malloc_type *type, int flags)
165{
166
167 return malloc(size, type, flags | M_ZERO);
168}
169
170void
171smb_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
180void
181m_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
198int
199smb_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
309static int
310smb_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
326int
327smb_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
342int
343smb_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
355int
356smb_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
373struct sockaddr *
374dup_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