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: src/sys/netsmb/smb_subr.c,v 1.1.2.2 2001/09/03 08:55:11 bp Exp $ 33 */ 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/endian.h> 37 #include <sys/kernel.h> 38 #include <sys/kthread.h> 39 #include <sys/malloc.h> 40 #include <sys/mbuf.h> 41 #include <sys/proc.h> 42 #include <sys/lock.h> 43 #include <sys/resourcevar.h> 44 #include <sys/sysctl.h> 45 #include <sys/socket.h> 46 #include <sys/signalvar.h> 47 #include <sys/wait.h> 48 #include <sys/unistd.h> 49 50 #include <sys/signal2.h> 51 52 #include <machine/stdarg.h> 53 54 #include <sys/iconv.h> 55 56 #include "smb.h" 57 #include "smb_conn.h" 58 #include "smb_rq.h" 59 #include "smb_subr.h" 60 61 MALLOC_DEFINE(M_SMBSTR, "SMBSTR", "netsmb string data"); 62 MALLOC_DEFINE(M_SMBTEMP, "SMBTEMP", "Temp netsmb data"); 63 64 smb_unichar smb_unieol = 0; 65 66 void 67 smb_makescred(struct smb_cred *scred, struct thread *td, struct ucred *cred) 68 { 69 scred->scr_td = td; 70 if (td && td->td_proc) { 71 scred->scr_cred = cred ? cred : td->td_proc->p_ucred; 72 } else { 73 scred->scr_cred = cred ? cred : NULL; 74 } 75 } 76 77 int 78 smb_proc_intr(struct thread *td) 79 { 80 sigset_t tmpset; 81 struct proc *p; 82 struct lwp *lp; 83 84 if (td == NULL || (p = td->td_proc) == NULL) 85 return 0; 86 lp = td->td_lwp; 87 tmpset = lwp_sigpend(lp); 88 SIGSETNAND(tmpset, lp->lwp_sigmask); 89 SIGSETNAND(tmpset, p->p_sigignore); 90 if (SIGNOTEMPTY(tmpset) && SMB_SIGMASK(tmpset)) 91 return EINTR; 92 return 0; 93 } 94 95 char * 96 smb_strdup(const char *s) 97 { 98 char *p; 99 int len; 100 101 len = s ? strlen(s) + 1 : 1; 102 p = kmalloc(len, M_SMBSTR, M_WAITOK); 103 if (s) 104 bcopy(s, p, len); 105 else 106 *p = 0; 107 return p; 108 } 109 110 /* 111 * duplicate string from a user space. 112 */ 113 char * 114 smb_strdupin(char *s, int maxlen) 115 { 116 char *p, bt; 117 int len = 0; 118 119 for (p = s; ;p++) { 120 if (copyin(p, &bt, 1)) 121 return NULL; 122 len++; 123 if (maxlen && len > maxlen) 124 return NULL; 125 if (bt == 0) 126 break; 127 } 128 p = kmalloc(len, M_SMBSTR, M_WAITOK); 129 copyin(s, p, len); 130 return p; 131 } 132 133 /* 134 * duplicate memory block from a user space. 135 */ 136 void * 137 smb_memdupin(void *umem, int len) 138 { 139 char *p; 140 141 if (len > 8 * 1024) 142 return NULL; 143 p = kmalloc(len, M_SMBSTR, M_WAITOK); 144 if (copyin(umem, p, len) == 0) 145 return p; 146 kfree(p, M_SMBSTR); 147 return NULL; 148 } 149 150 /* 151 * duplicate memory block in the kernel space. 152 */ 153 void * 154 smb_memdup(const void *umem, int len) 155 { 156 char *p; 157 158 if (len > 8 * 1024) 159 return NULL; 160 p = kmalloc(len, M_SMBSTR, M_WAITOK); 161 bcopy(umem, p, len); 162 return p; 163 } 164 165 void 166 smb_strfree(char *s) 167 { 168 kfree(s, M_SMBSTR); 169 } 170 171 void 172 smb_memfree(void *s) 173 { 174 kfree(s, M_SMBSTR); 175 } 176 177 void * 178 smb_zmalloc(unsigned long size, struct malloc_type *type, int flags) 179 { 180 181 return kmalloc(size, type, flags | M_ZERO); 182 } 183 184 void 185 smb_strtouni(u_int16_t *dst, const char *src) 186 { 187 while (*src) { 188 *dst++ = htole16(*src++); 189 } 190 *dst = 0; 191 } 192 193 #ifdef SMB_SOCKETDATA_DEBUG 194 void 195 m_dumpm(struct mbuf *m) { 196 char *p; 197 int len; 198 kprintf("d="); 199 while(m) { 200 p=mtod(m,char *); 201 len=m->m_len; 202 kprintf("(%d)",len); 203 while(len--){ 204 kprintf("%02x ",((int)*(p++)) & 0xff); 205 } 206 m=m->m_next; 207 } 208 kprintf("\n"); 209 } 210 #endif 211 212 int 213 smb_maperror(int eclass, int eno) 214 { 215 if (eclass == 0 && eno == 0) 216 return 0; 217 switch (eclass) { 218 case ERRDOS: 219 switch (eno) { 220 case ERRbadfunc: 221 case ERRbadmcb: 222 case ERRbadenv: 223 case ERRbadformat: 224 case ERRrmuns: 225 return EINVAL; 226 case ERRbadfile: 227 case ERRbadpath: 228 case ERRremcd: 229 case 66: /* nt returns it when share not available */ 230 case 67: /* observed from nt4sp6 when sharename wrong */ 231 return ENOENT; 232 case ERRnofids: 233 return EMFILE; 234 case ERRnoaccess: 235 case ERRbadshare: 236 return EACCES; 237 case ERRbadfid: 238 return EBADF; 239 case ERRnomem: 240 return ENOMEM; /* actually remote no mem... */ 241 case ERRbadmem: 242 return EFAULT; 243 case ERRbadaccess: 244 return EACCES; 245 case ERRbaddata: 246 return E2BIG; 247 case ERRbaddrive: 248 case ERRnotready: /* nt */ 249 return ENXIO; 250 case ERRdiffdevice: 251 return EXDEV; 252 case ERRnofiles: 253 return 0; /* eeof ? */ 254 return ETXTBSY; 255 case ERRlock: 256 return EDEADLK; 257 case ERRfilexists: 258 return EEXIST; 259 case 123: /* dunno what is it, but samba maps as noent */ 260 return ENOENT; 261 case 145: /* samba */ 262 return ENOTEMPTY; 263 case 183: 264 return EEXIST; 265 } 266 break; 267 case ERRSRV: 268 switch (eno) { 269 case ERRerror: 270 return EINVAL; 271 case ERRbadpw: 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 2239: /* NT: account exists but disabled */ 283 return EPERM; 284 } 285 break; 286 case ERRHRD: 287 switch (eno) { 288 case ERRnowrite: 289 return EROFS; 290 case ERRbadunit: 291 return ENODEV; 292 case ERRnotready: 293 case ERRbadcmd: 294 case ERRdata: 295 return EIO; 296 case ERRbadreq: 297 return EBADRPC; 298 case ERRbadshare: 299 return ETXTBSY; 300 case ERRlock: 301 return EDEADLK; 302 } 303 break; 304 } 305 SMBERROR("Unmapped error %d:%d\n", eclass, eno); 306 return EBADRPC; 307 } 308 309 static int 310 smb_copy_iconv(struct mbchain *mbp, c_caddr_t src, caddr_t 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 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 372 /* 373 * Create a kernel process/thread/whatever. It shares it's address space 374 * with proc0 - ie: kernel only. 375 * 376 * XXX only the SMB protocol uses this, we should convert this mess to a 377 * pure thread when possible. 378 */ 379 int 380 smb_kthread_create(void (*func)(void *), void *arg, 381 struct proc **newpp, int flags, const char *fmt, ...) 382 { 383 int error; 384 __va_list ap; 385 struct proc *p2; 386 struct lwp *lp2; 387 388 error = fork1(&lwp0, RFMEM | RFFDG | RFPROC | flags, &p2); 389 if (error) 390 return error; 391 392 /* save a global descriptor, if desired */ 393 if (newpp != NULL) 394 *newpp = p2; 395 396 /* this is a non-swapped system process */ 397 p2->p_flags |= P_SYSTEM; 398 p2->p_sigacts->ps_flag |= PS_NOCLDWAIT; 399 400 lp2 = ONLY_LWP_IN_PROC(p2); 401 402 /* set up arg0 for 'ps', et al */ 403 __va_start(ap, fmt); 404 kvsnprintf(p2->p_comm, sizeof(p2->p_comm), fmt, ap); 405 __va_end(ap); 406 407 lp2->lwp_thread->td_ucred = crhold(proc0.p_ucred); 408 409 /* call the processes' main()... */ 410 cpu_set_fork_handler(lp2, 411 (void (*)(void *, struct trapframe *))func, arg); 412 start_forked_proc(&lwp0, p2); 413 414 return 0; 415 } 416 417 void 418 smb_kthread_exit(void) 419 { 420 exit1(0); 421 } 422 423 /* 424 * smb_sleep() icky compat routine. Leave the token held through the tsleep 425 * to interlock against the sleep. Remember that the token could be lost 426 * since we blocked, so reget or release as appropriate. 427 */ 428 int 429 smb_sleep(void *chan, struct smb_slock *sl, int slpflags, const char *wmesg, int timo) 430 { 431 int error; 432 433 if (sl) { 434 tsleep_interlock(chan, slpflags); 435 smb_sl_unlock(sl); 436 error = tsleep(chan, slpflags | PINTERLOCKED, wmesg, timo); 437 if ((slpflags & PDROP) == 0) 438 smb_sl_lock(sl); 439 } else { 440 error = tsleep(chan, slpflags, wmesg, timo); 441 } 442 return error; 443 } 444 445