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/signal2.h> 48 #include <sys/wait.h> 49 #include <sys/unistd.h> 50 51 #include <machine/stdarg.h> 52 53 #include <sys/iconv.h> 54 55 #include "smb.h" 56 #include "smb_conn.h" 57 #include "smb_rq.h" 58 #include "smb_subr.h" 59 60 MALLOC_DEFINE(M_SMBDATA, "SMBDATA", "Misc netsmb data"); 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++ = htoles(*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, int len) 311 { 312 int outlen = len; 313 314 return iconv_conv((struct iconv_drv*)mbp->mb_udata, &src, &len, &dst, &outlen); 315 } 316 317 int 318 smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src, 319 int size, int caseopt) 320 { 321 struct iconv_drv *dp = vcp->vc_toserver; 322 323 if (size == 0) 324 return 0; 325 if (dp == NULL) { 326 return mb_put_mem(mbp, src, size, MB_MSYSTEM); 327 } 328 mbp->mb_copy = smb_copy_iconv; 329 mbp->mb_udata = dp; 330 return mb_put_mem(mbp, src, size, MB_MCUSTOM); 331 } 332 333 int 334 smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src, 335 int caseopt) 336 { 337 int error; 338 339 error = smb_put_dmem(mbp, vcp, src, strlen(src), caseopt); 340 if (error) 341 return error; 342 return mb_put_uint8(mbp, 0); 343 } 344 345 int 346 smb_put_asunistring(struct smb_rq *rqp, const char *src) 347 { 348 struct mbchain *mbp = &rqp->sr_rq; 349 struct iconv_drv *dp = rqp->sr_vc->vc_toserver; 350 u_char c; 351 int error; 352 353 while (*src) { 354 iconv_convmem(dp, &c, src++, 1); 355 error = mb_put_uint16le(mbp, c); 356 if (error) 357 return error; 358 } 359 return mb_put_uint16le(mbp, 0); 360 } 361 362 /* 363 * Create a kernel process/thread/whatever. It shares it's address space 364 * with proc0 - ie: kernel only. 365 * 366 * XXX only the SMB protocol uses this, we should convert this mess to a 367 * pure thread when possible. 368 */ 369 int 370 kthread_create2(void (*func)(void *), void *arg, 371 struct proc **newpp, int flags, const char *fmt, ...) 372 { 373 int error; 374 __va_list ap; 375 struct proc *p2; 376 struct lwp *lp2; 377 378 error = fork1(&lwp0, RFMEM | RFFDG | RFPROC | flags, &p2); 379 if (error) 380 return error; 381 382 /* save a global descriptor, if desired */ 383 if (newpp != NULL) 384 *newpp = p2; 385 386 /* this is a non-swapped system process */ 387 p2->p_flag |= P_SYSTEM; 388 p2->p_sigacts->ps_flag |= PS_NOCLDWAIT; 389 390 lp2 = ONLY_LWP_IN_PROC(p2); 391 392 /* set up arg0 for 'ps', et al */ 393 __va_start(ap, fmt); 394 kvsnprintf(p2->p_comm, sizeof(p2->p_comm), fmt, ap); 395 __va_end(ap); 396 397 /* call the processes' main()... */ 398 cpu_set_fork_handler(lp2, (void (*)(void *))func, arg); 399 start_forked_proc(&lwp0, p2); 400 401 return 0; 402 } 403 404 void 405 kthread_exit2(void) 406 { 407 exit1(0); 408 } 409 410 /* 411 * smb_sleep() icky compat routine. Leave the token held through the tsleep 412 * to interlock against the sleep. Remember that the token could be lost 413 * since we blocked, so reget or release as appropriate. 414 */ 415 int 416 smb_sleep(void *chan, struct smb_slock *sl, int slpflags, const char *wmesg, int timo) 417 { 418 int error; 419 420 if (sl) { 421 crit_enter(); 422 tsleep_interlock(chan); 423 smb_sl_unlock(sl); 424 error = tsleep(chan, slpflags, wmesg, timo); 425 if ((slpflags & PDROP) == 0) 426 smb_sl_lock(sl); 427 crit_exit(); 428 } else { 429 error = tsleep(chan, slpflags, wmesg, timo); 430 } 431 return error; 432 } 433 434