1c398230bSWarner Losh /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3fe267a55SPedro F. Giffuni * 4681a5bbeSBoris Popov * Copyright (c) 2000-2001 Boris Popov 5681a5bbeSBoris Popov * All rights reserved. 6681a5bbeSBoris Popov * 7681a5bbeSBoris Popov * Redistribution and use in source and binary forms, with or without 8681a5bbeSBoris Popov * modification, are permitted provided that the following conditions 9681a5bbeSBoris Popov * are met: 10681a5bbeSBoris Popov * 1. Redistributions of source code must retain the above copyright 11681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer. 12681a5bbeSBoris Popov * 2. Redistributions in binary form must reproduce the above copyright 13681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer in the 14681a5bbeSBoris Popov * documentation and/or other materials provided with the distribution. 15681a5bbeSBoris Popov * 16681a5bbeSBoris Popov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17681a5bbeSBoris Popov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18681a5bbeSBoris Popov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19681a5bbeSBoris Popov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20681a5bbeSBoris Popov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21681a5bbeSBoris Popov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22681a5bbeSBoris Popov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23681a5bbeSBoris Popov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24681a5bbeSBoris Popov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25681a5bbeSBoris Popov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26681a5bbeSBoris Popov * SUCH DAMAGE. 27681a5bbeSBoris Popov */ 28ab0de15bSDavid E. O'Brien 29681a5bbeSBoris Popov #include <sys/param.h> 30681a5bbeSBoris Popov #include <sys/systm.h> 31a30d4b32SMike Barcroft #include <sys/endian.h> 32681a5bbeSBoris Popov #include <sys/kernel.h> 33681a5bbeSBoris Popov #include <sys/malloc.h> 34681a5bbeSBoris Popov #include <sys/proc.h> 35681a5bbeSBoris Popov #include <sys/lock.h> 36681a5bbeSBoris Popov #include <sys/sysctl.h> 37681a5bbeSBoris Popov #include <sys/socket.h> 38681a5bbeSBoris Popov #include <sys/signalvar.h> 39681a5bbeSBoris Popov #include <sys/mbuf.h> 40681a5bbeSBoris Popov 41681a5bbeSBoris Popov #include <sys/iconv.h> 42681a5bbeSBoris Popov 43681a5bbeSBoris Popov #include <netsmb/smb.h> 44681a5bbeSBoris Popov #include <netsmb/smb_conn.h> 45681a5bbeSBoris Popov #include <netsmb/smb_rq.h> 46681a5bbeSBoris Popov #include <netsmb/smb_subr.h> 47681a5bbeSBoris Popov 48d745c852SEd Schouten static MALLOC_DEFINE(M_SMBDATA, "SMBDATA", "Misc netsmb data"); 49d745c852SEd Schouten static MALLOC_DEFINE(M_SMBSTR, "SMBSTR", "netsmb string data"); 50681a5bbeSBoris Popov MALLOC_DEFINE(M_SMBTEMP, "SMBTEMP", "Temp netsmb data"); 51681a5bbeSBoris Popov 52681a5bbeSBoris Popov smb_unichar smb_unieol = 0; 53681a5bbeSBoris Popov 54681a5bbeSBoris Popov void 55fce6fbfaSBoris Popov smb_makescred(struct smb_cred *scred, struct thread *td, struct ucred *cred) 56681a5bbeSBoris Popov { 57fce6fbfaSBoris Popov if (td) { 58fce6fbfaSBoris Popov scred->scr_td = td; 59a854ed98SJohn Baldwin scred->scr_cred = cred ? cred : td->td_ucred; 60681a5bbeSBoris Popov } else { 61fce6fbfaSBoris Popov scred->scr_td = NULL; 62681a5bbeSBoris Popov scred->scr_cred = cred ? cred : NULL; 63681a5bbeSBoris Popov } 64681a5bbeSBoris Popov } 65681a5bbeSBoris Popov 66681a5bbeSBoris Popov int 674093529dSJeff Roberson smb_td_intr(struct thread *td) 68681a5bbeSBoris Popov { 694093529dSJeff Roberson struct proc *p; 70681a5bbeSBoris Popov sigset_t tmpset; 71681a5bbeSBoris Popov 724093529dSJeff Roberson if (td == NULL) 73681a5bbeSBoris Popov return 0; 744093529dSJeff Roberson 754093529dSJeff Roberson p = td->td_proc; 76fbbad444STim J. Robbins PROC_LOCK(p); 771d9c5696SJuli Mallett tmpset = p->p_siglist; 784093529dSJeff Roberson SIGSETOR(tmpset, td->td_siglist); 794093529dSJeff Roberson SIGSETNAND(tmpset, td->td_sigmask); 8090af4afaSJohn Baldwin mtx_lock(&p->p_sigacts->ps_mtx); 8190af4afaSJohn Baldwin SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore); 8290af4afaSJohn Baldwin mtx_unlock(&p->p_sigacts->ps_mtx); 834093529dSJeff Roberson if (SIGNOTEMPTY(td->td_siglist) && SMB_SIGMASK(tmpset)) { 84fbbad444STim J. Robbins PROC_UNLOCK(p); 85681a5bbeSBoris Popov return EINTR; 86fbbad444STim J. Robbins } 87fbbad444STim J. Robbins PROC_UNLOCK(p); 88681a5bbeSBoris Popov return 0; 89681a5bbeSBoris Popov } 90681a5bbeSBoris Popov 91681a5bbeSBoris Popov char * 92681a5bbeSBoris Popov smb_strdup(const char *s) 93681a5bbeSBoris Popov { 94681a5bbeSBoris Popov char *p; 95a67b22d6SChristian S.J. Peron size_t len; 96681a5bbeSBoris Popov 97681a5bbeSBoris Popov len = s ? strlen(s) + 1 : 1; 98a163d034SWarner Losh p = malloc(len, M_SMBSTR, M_WAITOK); 99681a5bbeSBoris Popov if (s) 100681a5bbeSBoris Popov bcopy(s, p, len); 101681a5bbeSBoris Popov else 102681a5bbeSBoris Popov *p = 0; 103681a5bbeSBoris Popov return p; 104681a5bbeSBoris Popov } 105681a5bbeSBoris Popov 106681a5bbeSBoris Popov /* 107681a5bbeSBoris Popov * duplicate string from a user space. 108681a5bbeSBoris Popov */ 109681a5bbeSBoris Popov char * 110a67b22d6SChristian S.J. Peron smb_strdupin(char *s, size_t maxlen) 111681a5bbeSBoris Popov { 11251bcc337SConrad Meyer char *p; 113a67b22d6SChristian S.J. Peron int error; 114681a5bbeSBoris Popov 11551bcc337SConrad Meyer p = malloc(maxlen + 1, M_SMBSTR, M_WAITOK); 11651bcc337SConrad Meyer error = copyinstr(s, p, maxlen + 1, NULL); 117ed9e2ed4SChristian S.J. Peron if (error) { 118ed9e2ed4SChristian S.J. Peron free(p, M_SMBSTR); 119ed9e2ed4SChristian S.J. Peron return (NULL); 120ed9e2ed4SChristian S.J. Peron } 121681a5bbeSBoris Popov return p; 122681a5bbeSBoris Popov } 123681a5bbeSBoris Popov 124681a5bbeSBoris Popov /* 125681a5bbeSBoris Popov * duplicate memory block from a user space. 126681a5bbeSBoris Popov */ 127681a5bbeSBoris Popov void * 128a67b22d6SChristian S.J. Peron smb_memdupin(void *umem, size_t len) 129681a5bbeSBoris Popov { 130681a5bbeSBoris Popov char *p; 131681a5bbeSBoris Popov 132681a5bbeSBoris Popov if (len > 8 * 1024) 133681a5bbeSBoris Popov return NULL; 134a163d034SWarner Losh p = malloc(len, M_SMBSTR, M_WAITOK); 135681a5bbeSBoris Popov if (copyin(umem, p, len) == 0) 136681a5bbeSBoris Popov return p; 137681a5bbeSBoris Popov free(p, M_SMBSTR); 138681a5bbeSBoris Popov return NULL; 139681a5bbeSBoris Popov } 140681a5bbeSBoris Popov 141681a5bbeSBoris Popov /* 142681a5bbeSBoris Popov * duplicate memory block in the kernel space. 143681a5bbeSBoris Popov */ 144681a5bbeSBoris Popov void * 145681a5bbeSBoris Popov smb_memdup(const void *umem, int len) 146681a5bbeSBoris Popov { 147681a5bbeSBoris Popov char *p; 148681a5bbeSBoris Popov 149681a5bbeSBoris Popov if (len > 8 * 1024) 150681a5bbeSBoris Popov return NULL; 151a163d034SWarner Losh p = malloc(len, M_SMBSTR, M_WAITOK); 152681a5bbeSBoris Popov bcopy(umem, p, len); 153681a5bbeSBoris Popov return p; 154681a5bbeSBoris Popov } 155681a5bbeSBoris Popov 156681a5bbeSBoris Popov void 157681a5bbeSBoris Popov smb_strfree(char *s) 158681a5bbeSBoris Popov { 159681a5bbeSBoris Popov free(s, M_SMBSTR); 160681a5bbeSBoris Popov } 161681a5bbeSBoris Popov 162681a5bbeSBoris Popov void 163681a5bbeSBoris Popov smb_memfree(void *s) 164681a5bbeSBoris Popov { 165681a5bbeSBoris Popov free(s, M_SMBSTR); 166681a5bbeSBoris Popov } 167681a5bbeSBoris Popov 168681a5bbeSBoris Popov void * 169a67b22d6SChristian S.J. Peron smb_zmalloc(size_t size, struct malloc_type *type, int flags) 170681a5bbeSBoris Popov { 171681a5bbeSBoris Popov 172681a5bbeSBoris Popov return malloc(size, type, flags | M_ZERO); 173681a5bbeSBoris Popov } 174681a5bbeSBoris Popov 175681a5bbeSBoris Popov void 176681a5bbeSBoris Popov smb_strtouni(u_int16_t *dst, const char *src) 177681a5bbeSBoris Popov { 178681a5bbeSBoris Popov while (*src) { 1790adb6d7aSRobert Drehmel *dst++ = htole16(*src++); 180681a5bbeSBoris Popov } 181681a5bbeSBoris Popov *dst = 0; 182681a5bbeSBoris Popov } 183681a5bbeSBoris Popov 184681a5bbeSBoris Popov #ifdef SMB_SOCKETDATA_DEBUG 185681a5bbeSBoris Popov void 186681a5bbeSBoris Popov m_dumpm(struct mbuf *m) { 187681a5bbeSBoris Popov char *p; 188a67b22d6SChristian S.J. Peron size_t len; 189681a5bbeSBoris Popov printf("d="); 190681a5bbeSBoris Popov while(m) { 191681a5bbeSBoris Popov p=mtod(m,char *); 192681a5bbeSBoris Popov len=m->m_len; 193a67b22d6SChristian S.J. Peron printf("(%zu)",len); 194681a5bbeSBoris Popov while(len--){ 195681a5bbeSBoris Popov printf("%02x ",((int)*(p++)) & 0xff); 196681a5bbeSBoris Popov } 197681a5bbeSBoris Popov m=m->m_next; 19874b8d63dSPedro F. Giffuni } 199681a5bbeSBoris Popov printf("\n"); 200681a5bbeSBoris Popov } 201681a5bbeSBoris Popov #endif 202681a5bbeSBoris Popov 203681a5bbeSBoris Popov int 204681a5bbeSBoris Popov smb_maperror(int eclass, int eno) 205681a5bbeSBoris Popov { 206681a5bbeSBoris Popov if (eclass == 0 && eno == 0) 207681a5bbeSBoris Popov return 0; 208681a5bbeSBoris Popov switch (eclass) { 209681a5bbeSBoris Popov case ERRDOS: 210681a5bbeSBoris Popov switch (eno) { 211681a5bbeSBoris Popov case ERRbadfunc: 212681a5bbeSBoris Popov case ERRbadmcb: 213681a5bbeSBoris Popov case ERRbadenv: 214681a5bbeSBoris Popov case ERRbadformat: 215681a5bbeSBoris Popov case ERRrmuns: 216681a5bbeSBoris Popov return EINVAL; 217681a5bbeSBoris Popov case ERRbadfile: 218681a5bbeSBoris Popov case ERRbadpath: 219681a5bbeSBoris Popov case ERRremcd: 220681a5bbeSBoris Popov case 66: /* nt returns it when share not available */ 221fe98760eSBoris Popov case 67: /* observed from nt4sp6 when sharename wrong */ 222681a5bbeSBoris Popov return ENOENT; 223681a5bbeSBoris Popov case ERRnofids: 224681a5bbeSBoris Popov return EMFILE; 225681a5bbeSBoris Popov case ERRnoaccess: 226681a5bbeSBoris Popov case ERRbadshare: 227681a5bbeSBoris Popov return EACCES; 228681a5bbeSBoris Popov case ERRbadfid: 229681a5bbeSBoris Popov return EBADF; 230681a5bbeSBoris Popov case ERRnomem: 231681a5bbeSBoris Popov return ENOMEM; /* actually remote no mem... */ 232681a5bbeSBoris Popov case ERRbadmem: 233681a5bbeSBoris Popov return EFAULT; 234681a5bbeSBoris Popov case ERRbadaccess: 235681a5bbeSBoris Popov return EACCES; 236681a5bbeSBoris Popov case ERRbaddata: 237681a5bbeSBoris Popov return E2BIG; 238681a5bbeSBoris Popov case ERRbaddrive: 239681a5bbeSBoris Popov case ERRnotready: /* nt */ 240681a5bbeSBoris Popov return ENXIO; 241681a5bbeSBoris Popov case ERRdiffdevice: 242681a5bbeSBoris Popov return EXDEV; 243681a5bbeSBoris Popov case ERRnofiles: 244681a5bbeSBoris Popov return 0; /* eeof ? */ 245681a5bbeSBoris Popov return ETXTBSY; 246681a5bbeSBoris Popov case ERRlock: 247681a5bbeSBoris Popov return EDEADLK; 248681a5bbeSBoris Popov case ERRfilexists: 249681a5bbeSBoris Popov return EEXIST; 250681a5bbeSBoris Popov case 123: /* dunno what is it, but samba maps as noent */ 251681a5bbeSBoris Popov return ENOENT; 252681a5bbeSBoris Popov case 145: /* samba */ 253681a5bbeSBoris Popov return ENOTEMPTY; 254834340aeSBoris Popov case ERRnotlocked: 255834340aeSBoris Popov return 0; /* file become unlocked */ 256681a5bbeSBoris Popov case 183: 257681a5bbeSBoris Popov return EEXIST; 258af9b5e8fSBoris Popov case ERRquota: 259af9b5e8fSBoris Popov return EDQUOT; 260681a5bbeSBoris Popov } 261681a5bbeSBoris Popov break; 262681a5bbeSBoris Popov case ERRSRV: 263681a5bbeSBoris Popov switch (eno) { 264681a5bbeSBoris Popov case ERRerror: 265681a5bbeSBoris Popov return EINVAL; 266681a5bbeSBoris Popov case ERRbadpw: 267af9b5e8fSBoris Popov case ERRpasswordExpired: 268681a5bbeSBoris Popov return EAUTH; 269681a5bbeSBoris Popov case ERRaccess: 270681a5bbeSBoris Popov return EACCES; 271681a5bbeSBoris Popov case ERRinvnid: 272681a5bbeSBoris Popov return ENETRESET; 273681a5bbeSBoris Popov case ERRinvnetname: 274681a5bbeSBoris Popov SMBERROR("NetBIOS name is invalid\n"); 275681a5bbeSBoris Popov return EAUTH; 276681a5bbeSBoris Popov case 3: /* reserved and returned */ 277681a5bbeSBoris Popov return EIO; 278af9b5e8fSBoris Popov case ERRaccountExpired: 279af9b5e8fSBoris Popov case ERRbadClient: 280af9b5e8fSBoris Popov case ERRbadLogonTime: 281681a5bbeSBoris Popov return EPERM; 282af9b5e8fSBoris Popov case ERRnosupport: 283af9b5e8fSBoris Popov return EBADRPC; 284681a5bbeSBoris Popov } 285681a5bbeSBoris Popov break; 286681a5bbeSBoris Popov case ERRHRD: 287681a5bbeSBoris Popov switch (eno) { 288681a5bbeSBoris Popov case ERRnowrite: 289681a5bbeSBoris Popov return EROFS; 290681a5bbeSBoris Popov case ERRbadunit: 291681a5bbeSBoris Popov return ENODEV; 292681a5bbeSBoris Popov case ERRnotready: 293681a5bbeSBoris Popov case ERRbadcmd: 294681a5bbeSBoris Popov case ERRdata: 295681a5bbeSBoris Popov return EIO; 296681a5bbeSBoris Popov case ERRbadreq: 297681a5bbeSBoris Popov return EBADRPC; 298681a5bbeSBoris Popov case ERRbadshare: 299681a5bbeSBoris Popov return ETXTBSY; 300681a5bbeSBoris Popov case ERRlock: 301681a5bbeSBoris Popov return EDEADLK; 302681a5bbeSBoris Popov } 303681a5bbeSBoris Popov break; 304681a5bbeSBoris Popov } 305681a5bbeSBoris Popov SMBERROR("Unmapped error %d:%d\n", eclass, eno); 306681a5bbeSBoris Popov return EBADRPC; 307681a5bbeSBoris Popov } 308681a5bbeSBoris Popov 309681a5bbeSBoris Popov static int 310080e3a63SR. Imura smb_copy_iconv(struct mbchain *mbp, c_caddr_t src, caddr_t dst, 311080e3a63SR. Imura size_t *srclen, size_t *dstlen) 312681a5bbeSBoris Popov { 313080e3a63SR. Imura int error; 314080e3a63SR. Imura size_t inlen = *srclen, outlen = *dstlen; 315681a5bbeSBoris Popov 316080e3a63SR. Imura error = iconv_conv((struct iconv_drv*)mbp->mb_udata, &src, &inlen, 317080e3a63SR. Imura &dst, &outlen); 318080e3a63SR. Imura if (inlen != *srclen || outlen != *dstlen) { 319080e3a63SR. Imura *srclen -= inlen; 320080e3a63SR. Imura *dstlen -= outlen; 321080e3a63SR. Imura return 0; 322080e3a63SR. Imura } else 323080e3a63SR. Imura return error; 324681a5bbeSBoris Popov } 325681a5bbeSBoris Popov 326681a5bbeSBoris Popov int 327681a5bbeSBoris Popov smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src, 328a67b22d6SChristian S.J. Peron size_t size, int caseopt) 329681a5bbeSBoris Popov { 330681a5bbeSBoris Popov struct iconv_drv *dp = vcp->vc_toserver; 331681a5bbeSBoris Popov 332681a5bbeSBoris Popov if (size == 0) 333681a5bbeSBoris Popov return 0; 334681a5bbeSBoris Popov if (dp == NULL) { 335681a5bbeSBoris Popov return mb_put_mem(mbp, src, size, MB_MSYSTEM); 336681a5bbeSBoris Popov } 337681a5bbeSBoris Popov mbp->mb_copy = smb_copy_iconv; 338681a5bbeSBoris Popov mbp->mb_udata = dp; 33941f1dcccSKevin Lo if (SMB_UNICODE_STRINGS(vcp)) 34041f1dcccSKevin Lo mb_put_padbyte(mbp); 341681a5bbeSBoris Popov return mb_put_mem(mbp, src, size, MB_MCUSTOM); 342681a5bbeSBoris Popov } 343681a5bbeSBoris Popov 344681a5bbeSBoris Popov int 345681a5bbeSBoris Popov smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src, 346681a5bbeSBoris Popov int caseopt) 347681a5bbeSBoris Popov { 348681a5bbeSBoris Popov int error; 349681a5bbeSBoris Popov 350681a5bbeSBoris Popov error = smb_put_dmem(mbp, vcp, src, strlen(src), caseopt); 351681a5bbeSBoris Popov if (error) 352681a5bbeSBoris Popov return error; 35341f1dcccSKevin Lo if (SMB_UNICODE_STRINGS(vcp)) 35441f1dcccSKevin Lo return mb_put_uint16le(mbp, 0); 355681a5bbeSBoris Popov return mb_put_uint8(mbp, 0); 356681a5bbeSBoris Popov } 357681a5bbeSBoris Popov 358681a5bbeSBoris Popov int 359681a5bbeSBoris Popov smb_put_asunistring(struct smb_rq *rqp, const char *src) 360681a5bbeSBoris Popov { 361681a5bbeSBoris Popov struct mbchain *mbp = &rqp->sr_rq; 362681a5bbeSBoris Popov struct iconv_drv *dp = rqp->sr_vc->vc_toserver; 363681a5bbeSBoris Popov u_char c; 364681a5bbeSBoris Popov int error; 365681a5bbeSBoris Popov 366681a5bbeSBoris Popov while (*src) { 367681a5bbeSBoris Popov iconv_convmem(dp, &c, src++, 1); 368681a5bbeSBoris Popov error = mb_put_uint16le(mbp, c); 369681a5bbeSBoris Popov if (error) 370681a5bbeSBoris Popov return error; 371681a5bbeSBoris Popov } 372681a5bbeSBoris Popov return mb_put_uint16le(mbp, 0); 373681a5bbeSBoris Popov } 374