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