| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
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 $ | |
| 978400d3 | 33 | * $DragonFly: src/sys/netproto/smb/smb_subr.c,v 1.30 2008/01/06 16:55:53 swildner Exp $ |
| 984263bc MD |
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> | |
| b1b4e5a6 | 47 | #include <sys/signal2.h> |
| 984263bc MD |
48 | #include <sys/wait.h> |
| 49 | #include <sys/unistd.h> | |
| 50 | ||
| 51 | #include <machine/stdarg.h> | |
| 52 | ||
| 53 | #include <sys/iconv.h> | |
| 54 | ||
| 1f2de5d4 MD |
55 | #include "smb.h" |
| 56 | #include "smb_conn.h" | |
| 57 | #include "smb_rq.h" | |
| 58 | #include "smb_subr.h" | |
| 984263bc MD |
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 | |
| dadab5e9 | 67 | smb_makescred(struct smb_cred *scred, struct thread *td, struct ucred *cred) |
| 984263bc | 68 | { |
| dadab5e9 MD |
69 | scred->scr_td = td; |
| 70 | if (td && td->td_proc) { | |
| 71 | scred->scr_cred = cred ? cred : td->td_proc->p_ucred; | |
| 984263bc | 72 | } else { |
| 984263bc MD |
73 | scred->scr_cred = cred ? cred : NULL; |
| 74 | } | |
| 75 | } | |
| 76 | ||
| 77 | int | |
| dadab5e9 | 78 | smb_proc_intr(struct thread *td) |
| 984263bc MD |
79 | { |
| 80 | sigset_t tmpset; | |
| dadab5e9 | 81 | struct proc *p; |
| 08f2f1bb | 82 | struct lwp *lp; |
| 984263bc | 83 | |
| ae10516a | 84 | if (td == NULL || (p = td->td_proc) == NULL) |
| 984263bc | 85 | return 0; |
| 08f2f1bb | 86 | lp = td->td_lwp; |
| aa6c3de6 | 87 | tmpset = lwp_sigpend(lp); |
| 08f2f1bb | 88 | SIGSETNAND(tmpset, lp->lwp_sigmask); |
| 984263bc | 89 | SIGSETNAND(tmpset, p->p_sigignore); |
| 08f2f1bb | 90 | if (SIGNOTEMPTY(tmpset) && SMB_SIGMASK(tmpset)) |
| 984263bc MD |
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; | |
| efda3bd0 | 102 | p = kmalloc(len, M_SMBSTR, M_WAITOK); |
| 984263bc MD |
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 | } | |
| efda3bd0 | 128 | p = kmalloc(len, M_SMBSTR, M_WAITOK); |
| 984263bc MD |
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; | |
| efda3bd0 | 143 | p = kmalloc(len, M_SMBSTR, M_WAITOK); |
| 984263bc MD |
144 | if (copyin(umem, p, len) == 0) |
| 145 | return p; | |
| efda3bd0 | 146 | kfree(p, M_SMBSTR); |
| 984263bc MD |
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; | |
| efda3bd0 | 160 | p = kmalloc(len, M_SMBSTR, M_WAITOK); |
| 984263bc MD |
161 | bcopy(umem, p, len); |
| 162 | return p; | |
| 163 | } | |
| 164 | ||
| 165 | void | |
| 166 | smb_strfree(char *s) | |
| 167 | { | |
| efda3bd0 | 168 | kfree(s, M_SMBSTR); |
| 984263bc MD |
169 | } |
| 170 | ||
| 171 | void | |
| 172 | smb_memfree(void *s) | |
| 173 | { | |
| efda3bd0 | 174 | kfree(s, M_SMBSTR); |
| 984263bc MD |
175 | } |
| 176 | ||
| 177 | void * | |
| 178 | smb_zmalloc(unsigned long size, struct malloc_type *type, int flags) | |
| 179 | { | |
| 180 | ||
| efda3bd0 | 181 | return kmalloc(size, type, flags | M_ZERO); |
| 984263bc MD |
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; | |
| a6ec04bc | 198 | kprintf("d="); |
| 984263bc MD |
199 | while(m) { |
| 200 | p=mtod(m,char *); | |
| 201 | len=m->m_len; | |
| a6ec04bc | 202 | kprintf("(%d)",len); |
| 984263bc | 203 | while(len--){ |
| a6ec04bc | 204 | kprintf("%02x ",((int)*(p++)) & 0xff); |
| 984263bc MD |
205 | } |
| 206 | m=m->m_next; | |
| 207 | }; | |
| a6ec04bc | 208 | kprintf("\n"); |
| 984263bc MD |
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 | |
| 973c11b9 | 310 | smb_copy_iconv(struct mbchain *mbp, c_caddr_t src, caddr_t dst, size_t len) |
| 984263bc | 311 | { |
| 973c11b9 | 312 | size_t outlen = len; |
| 984263bc MD |
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 | ||
| 984263bc MD |
362 | /* |
| 363 | * Create a kernel process/thread/whatever. It shares it's address space | |
| 364 | * with proc0 - ie: kernel only. | |
| 64053d25 MD |
365 | * |
| 366 | * XXX only the SMB protocol uses this, we should convert this mess to a | |
| 367 | * pure thread when possible. | |
| 984263bc MD |
368 | */ |
| 369 | int | |
| 370 | kthread_create2(void (*func)(void *), void *arg, | |
| 371 | struct proc **newpp, int flags, const char *fmt, ...) | |
| 372 | { | |
| 373 | int error; | |
| e2565a42 | 374 | __va_list ap; |
| 984263bc | 375 | struct proc *p2; |
| bb3cd951 | 376 | struct lwp *lp2; |
| 984263bc | 377 | |
| 08f2f1bb | 378 | error = fork1(&lwp0, RFMEM | RFFDG | RFPROC | flags, &p2); |
| 984263bc MD |
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 */ | |
| 344ad853 | 387 | p2->p_flag |= P_SYSTEM; |
| b1b4e5a6 | 388 | p2->p_sigacts->ps_flag |= PS_NOCLDWAIT; |
| 984263bc | 389 | |
| 08f2f1bb | 390 | lp2 = ONLY_LWP_IN_PROC(p2); |
| bb3cd951 | 391 | |
| 984263bc | 392 | /* set up arg0 for 'ps', et al */ |
| e2565a42 | 393 | __va_start(ap, fmt); |
| 379210cb | 394 | kvsnprintf(p2->p_comm, sizeof(p2->p_comm), fmt, ap); |
| e2565a42 | 395 | __va_end(ap); |
| 984263bc MD |
396 | |
| 397 | /* call the processes' main()... */ | |
| 973c11b9 MD |
398 | cpu_set_fork_handler(lp2, |
| 399 | (void (*)(void *, struct trapframe *))func, arg); | |
| 08f2f1bb | 400 | start_forked_proc(&lwp0, p2); |
| 984263bc MD |
401 | |
| 402 | return 0; | |
| 403 | } | |
| 404 | ||
| 64053d25 MD |
405 | void |
| 406 | kthread_exit2(void) | |
| 407 | { | |
| 408 | exit1(0); | |
| 409 | } | |
| 410 | ||
| 8a8d5d85 MD |
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 | */ | |
| 984263bc | 416 | int |
| 8886b1fc | 417 | smb_sleep(void *chan, struct smb_slock *sl, int slpflags, const char *wmesg, int timo) |
| 984263bc MD |
418 | { |
| 419 | int error; | |
| 420 | ||
| fcf5f48c MD |
421 | if (sl) { |
| 422 | crit_enter(); | |
| 423 | tsleep_interlock(chan); | |
| 8886b1fc | 424 | smb_sl_unlock(sl); |
| fcf5f48c MD |
425 | error = tsleep(chan, slpflags, wmesg, timo); |
| 426 | if ((slpflags & PDROP) == 0) | |
| 427 | smb_sl_lock(sl); | |
| 428 | crit_exit(); | |
| 429 | } else { | |
| 430 | error = tsleep(chan, slpflags, wmesg, timo); | |
| 431 | } | |
| 984263bc MD |
432 | return error; |
| 433 | } | |
| 8a8d5d85 | 434 |