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.26 2007/02/03 17:05:58 corecode 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 <machine/stdarg.h> 51 52 #include <sys/iconv.h> 53 54 #include "smb.h" 55 #include "smb_conn.h" 56 #include "smb_rq.h" 57 #include "smb_subr.h" 58 59 MALLOC_DEFINE(M_SMBDATA, "SMBDATA", "Misc netsmb data"); 60 MALLOC_DEFINE(M_SMBSTR, "SMBSTR", "netsmb string data"); 61 MALLOC_DEFINE(M_SMBTEMP, "SMBTEMP", "Temp netsmb data"); 62 63 smb_unichar smb_unieol = 0; 64 65 void 66 smb_makescred(struct smb_cred *scred, struct thread *td, struct ucred *cred) 67 { 68 scred->scr_td = td; 69 if (td && td->td_proc) { 70 scred->scr_cred = cred ? cred : td->td_proc->p_ucred; 71 } else { 72 scred->scr_cred = cred ? cred : NULL; 73 } 74 } 75 76 int 77 smb_proc_intr(struct thread *td) 78 { 79 sigset_t tmpset; 80 struct proc *p; 81 struct lwp *lp; 82 83 if (td == NULL || (p = td->td_proc) == NULL) 84 return 0; 85 lp = td->td_lwp; 86 tmpset = p->p_siglist; 87 SIGSETOR(tmpset, lp->lwp_siglist); 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 if (p == NULL) 162 return NULL; 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, int len) 313 { 314 int 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 kthread_create2(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_flag |= P_SYSTEM; 390 p2->p_procsig->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 /* call the processes' main()... */ 400 cpu_set_fork_handler(lp2, func, arg); 401 start_forked_proc(&lwp0, p2); 402 403 return 0; 404 } 405 406 void 407 kthread_exit2(void) 408 { 409 exit1(0); 410 } 411 412 /* 413 * smb_sleep() icky compat routine. Leave the token held through the tsleep 414 * to interlock against the sleep. Remember that the token could be lost 415 * since we blocked, so reget or release as appropriate. 416 */ 417 int 418 smb_sleep(void *chan, struct smb_slock *sl, int slpflags, const char *wmesg, int timo) 419 { 420 int error; 421 422 if (sl) { 423 crit_enter(); 424 tsleep_interlock(chan); 425 smb_sl_unlock(sl); 426 error = tsleep(chan, slpflags, wmesg, timo); 427 if ((slpflags & PDROP) == 0) 428 smb_sl_lock(sl); 429 crit_exit(); 430 } else { 431 error = tsleep(chan, slpflags, wmesg, timo); 432 } 433 return error; 434 } 435 436