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