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 #include <sys/mplock2.h> 52 53 #include <machine/stdarg.h> 54 55 #include <sys/iconv.h> 56 57 #include "smb.h" 58 #include "smb_conn.h" 59 #include "smb_rq.h" 60 #include "smb_subr.h" 61 62 MALLOC_DEFINE(M_SMBSTR, "SMBSTR", "netsmb string data"); 63 MALLOC_DEFINE(M_SMBTEMP, "SMBTEMP", "Temp netsmb data"); 64 65 smb_unichar smb_unieol = 0; 66 67 void 68 smb_makescred(struct smb_cred *scred, struct thread *td, struct ucred *cred) 69 { 70 scred->scr_td = td; 71 if (td && td->td_proc) { 72 scred->scr_cred = cred ? cred : td->td_proc->p_ucred; 73 } else { 74 scred->scr_cred = cred ? cred : NULL; 75 } 76 } 77 78 int 79 smb_proc_intr(struct thread *td) 80 { 81 sigset_t tmpset; 82 struct proc *p; 83 struct lwp *lp; 84 85 if (td == NULL || (p = td->td_proc) == NULL) 86 return 0; 87 lp = td->td_lwp; 88 tmpset = lwp_sigpend(lp); 89 SIGSETNAND(tmpset, lp->lwp_sigmask); 90 SIGSETNAND(tmpset, p->p_sigignore); 91 if (SIGNOTEMPTY(tmpset) && SMB_SIGMASK(tmpset)) 92 return EINTR; 93 return 0; 94 } 95 96 char * 97 smb_strdup(const char *s) 98 { 99 char *p; 100 int len; 101 102 len = s ? strlen(s) + 1 : 1; 103 p = kmalloc(len, M_SMBSTR, M_WAITOK); 104 if (s) 105 bcopy(s, p, len); 106 else 107 *p = 0; 108 return p; 109 } 110 111 /* 112 * duplicate string from a user space. 113 */ 114 char * 115 smb_strdupin(char *s, int maxlen) 116 { 117 char *p, bt; 118 int 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 = kmalloc(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 * 138 smb_memdupin(void *umem, int len) 139 { 140 char *p; 141 142 if (len > 8 * 1024) 143 return NULL; 144 p = kmalloc(len, M_SMBSTR, M_WAITOK); 145 if (copyin(umem, p, len) == 0) 146 return p; 147 kfree(p, M_SMBSTR); 148 return NULL; 149 } 150 151 /* 152 * duplicate memory block in the kernel space. 153 */ 154 void * 155 smb_memdup(const void *umem, int len) 156 { 157 char *p; 158 159 if (len > 8 * 1024) 160 return NULL; 161 p = kmalloc(len, M_SMBSTR, M_WAITOK); 162 bcopy(umem, p, len); 163 return p; 164 } 165 166 void 167 smb_strfree(char *s) 168 { 169 kfree(s, M_SMBSTR); 170 } 171 172 void 173 smb_memfree(void *s) 174 { 175 kfree(s, M_SMBSTR); 176 } 177 178 void * 179 smb_zmalloc(unsigned long size, struct malloc_type *type, int flags) 180 { 181 182 return kmalloc(size, type, flags | M_ZERO); 183 } 184 185 void 186 smb_strtouni(u_int16_t *dst, const char *src) 187 { 188 while (*src) { 189 *dst++ = htole16(*src++); 190 } 191 *dst = 0; 192 } 193 194 #ifdef SMB_SOCKETDATA_DEBUG 195 void 196 m_dumpm(struct mbuf *m) { 197 char *p; 198 int len; 199 kprintf("d="); 200 while(m) { 201 p=mtod(m,char *); 202 len=m->m_len; 203 kprintf("(%d)",len); 204 while(len--){ 205 kprintf("%02x ",((int)*(p++)) & 0xff); 206 } 207 m=m->m_next; 208 } 209 kprintf("\n"); 210 } 211 #endif 212 213 int 214 smb_maperror(int eclass, int eno) 215 { 216 if (eclass == 0 && eno == 0) 217 return 0; 218 switch (eclass) { 219 case ERRDOS: 220 switch (eno) { 221 case ERRbadfunc: 222 case ERRbadmcb: 223 case ERRbadenv: 224 case ERRbadformat: 225 case ERRrmuns: 226 return EINVAL; 227 case ERRbadfile: 228 case ERRbadpath: 229 case ERRremcd: 230 case 66: /* nt returns it when share not available */ 231 case 67: /* observed from nt4sp6 when sharename wrong */ 232 return ENOENT; 233 case ERRnofids: 234 return EMFILE; 235 case ERRnoaccess: 236 case ERRbadshare: 237 return EACCES; 238 case ERRbadfid: 239 return EBADF; 240 case ERRnomem: 241 return ENOMEM; /* actually remote no mem... */ 242 case ERRbadmem: 243 return EFAULT; 244 case ERRbadaccess: 245 return EACCES; 246 case ERRbaddata: 247 return E2BIG; 248 case ERRbaddrive: 249 case ERRnotready: /* nt */ 250 return ENXIO; 251 case ERRdiffdevice: 252 return EXDEV; 253 case ERRnofiles: 254 return 0; /* eeof ? */ 255 return ETXTBSY; 256 case ERRlock: 257 return EDEADLK; 258 case ERRfilexists: 259 return EEXIST; 260 case 123: /* dunno what is it, but samba maps as noent */ 261 return ENOENT; 262 case 145: /* samba */ 263 return ENOTEMPTY; 264 case 183: 265 return EEXIST; 266 } 267 break; 268 case ERRSRV: 269 switch (eno) { 270 case ERRerror: 271 return EINVAL; 272 case ERRbadpw: 273 return EAUTH; 274 case ERRaccess: 275 return EACCES; 276 case ERRinvnid: 277 return ENETRESET; 278 case ERRinvnetname: 279 SMBERROR("NetBIOS name is invalid\n"); 280 return EAUTH; 281 case 3: /* reserved and returned */ 282 return EIO; 283 case 2239: /* NT: account exists but disabled */ 284 return EPERM; 285 } 286 break; 287 case ERRHRD: 288 switch (eno) { 289 case ERRnowrite: 290 return EROFS; 291 case ERRbadunit: 292 return ENODEV; 293 case ERRnotready: 294 case ERRbadcmd: 295 case ERRdata: 296 return EIO; 297 case ERRbadreq: 298 return EBADRPC; 299 case ERRbadshare: 300 return ETXTBSY; 301 case ERRlock: 302 return EDEADLK; 303 } 304 break; 305 } 306 SMBERROR("Unmapped error %d:%d\n", eclass, eno); 307 return EBADRPC; 308 } 309 310 static int 311 smb_copy_iconv(struct mbchain *mbp, c_caddr_t src, caddr_t dst, 312 size_t *srclen, size_t *dstlen) 313 { 314 int error; 315 size_t inlen = *srclen, outlen = *dstlen; 316 317 error = iconv_conv((struct iconv_drv*)mbp->mb_udata, &src, &inlen, 318 &dst, &outlen); 319 if (inlen != *srclen || outlen != *dstlen) { 320 *srclen -= inlen; 321 *dstlen -= outlen; 322 return 0; 323 } else { 324 return error; 325 } 326 } 327 328 int 329 smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src, 330 int size, int caseopt) 331 { 332 struct iconv_drv *dp = vcp->vc_toserver; 333 334 if (size == 0) 335 return 0; 336 if (dp == NULL) { 337 return mb_put_mem(mbp, src, size, MB_MSYSTEM); 338 } 339 mbp->mb_copy = smb_copy_iconv; 340 mbp->mb_udata = dp; 341 return mb_put_mem(mbp, src, size, MB_MCUSTOM); 342 } 343 344 int 345 smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src, 346 int caseopt) 347 { 348 int error; 349 350 error = smb_put_dmem(mbp, vcp, src, strlen(src), caseopt); 351 if (error) 352 return error; 353 return mb_put_uint8(mbp, 0); 354 } 355 356 int 357 smb_put_asunistring(struct smb_rq *rqp, const char *src) 358 { 359 struct mbchain *mbp = &rqp->sr_rq; 360 struct iconv_drv *dp = rqp->sr_vc->vc_toserver; 361 u_char c; 362 int error; 363 364 while (*src) { 365 iconv_convmem(dp, &c, src++, 1); 366 error = mb_put_uint16le(mbp, c); 367 if (error) 368 return error; 369 } 370 return mb_put_uint16le(mbp, 0); 371 } 372 373 /* 374 * Create a kernel process/thread/whatever. It shares it's address space 375 * with proc0 - ie: kernel only. 376 * 377 * XXX only the SMB protocol uses this, we should convert this mess to a 378 * pure thread when possible. 379 */ 380 int 381 smb_kthread_create(void (*func)(void *), void *arg, 382 struct proc **newpp, int flags, const char *fmt, ...) 383 { 384 int error; 385 __va_list ap; 386 struct proc *p2; 387 struct lwp *lp2; 388 389 error = fork1(&lwp0, RFMEM | RFFDG | RFPROC | flags, &p2); 390 if (error) 391 return error; 392 393 /* save a global descriptor, if desired */ 394 if (newpp != NULL) 395 *newpp = p2; 396 397 /* this is a non-swapped system process */ 398 p2->p_flags |= P_SYSTEM; 399 p2->p_sigacts->ps_flag |= PS_NOCLDWAIT; 400 401 lp2 = ONLY_LWP_IN_PROC(p2); 402 403 /* set up arg0 for 'ps', et al */ 404 __va_start(ap, fmt); 405 kvsnprintf(p2->p_comm, sizeof(p2->p_comm), fmt, ap); 406 __va_end(ap); 407 408 lp2->lwp_thread->td_ucred = crhold(proc0.p_ucred); 409 410 /* call the processes' main()... */ 411 cpu_set_fork_handler(lp2, 412 (void (*)(void *, struct trapframe *))func, arg); 413 start_forked_proc(&lwp0, p2); 414 415 return 0; 416 } 417 418 void 419 smb_kthread_exit(void) 420 { 421 exit1(0); 422 } 423 424 /* 425 * smb_sleep() icky compat routine. Leave the token held through the tsleep 426 * to interlock against the sleep. Remember that the token could be lost 427 * since we blocked, so reget or release as appropriate. 428 */ 429 int 430 smb_sleep(void *chan, struct smb_slock *sl, int slpflags, const char *wmesg, int timo) 431 { 432 int error; 433 434 if (sl) { 435 tsleep_interlock(chan, slpflags); 436 smb_sl_unlock(sl); 437 error = tsleep(chan, slpflags | PINTERLOCKED, wmesg, timo); 438 if ((slpflags & PDROP) == 0) 439 smb_sl_lock(sl); 440 } else { 441 error = tsleep(chan, slpflags, wmesg, timo); 442 } 443 return error; 444 } 445 446