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