1139823Simp/*- 275374Sbp * Copyright (c) 2000-2001 Boris Popov 375374Sbp * All rights reserved. 475374Sbp * 575374Sbp * Redistribution and use in source and binary forms, with or without 675374Sbp * modification, are permitted provided that the following conditions 775374Sbp * are met: 875374Sbp * 1. Redistributions of source code must retain the above copyright 975374Sbp * notice, this list of conditions and the following disclaimer. 1075374Sbp * 2. Redistributions in binary form must reproduce the above copyright 1175374Sbp * notice, this list of conditions and the following disclaimer in the 1275374Sbp * documentation and/or other materials provided with the distribution. 1375374Sbp * 1475374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1575374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1675374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1775374Sbp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1875374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1975374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2075374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2175374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2275374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2375374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2475374Sbp * SUCH DAMAGE. 2575374Sbp */ 26116189Sobrien 27116189Sobrien#include <sys/cdefs.h> 28116189Sobrien__FBSDID("$FreeBSD$"); 29116189Sobrien 3075374Sbp#include <sys/param.h> 3175374Sbp#include <sys/systm.h> 3295533Smike#include <sys/endian.h> 3375374Sbp#include <sys/kernel.h> 3475374Sbp#include <sys/malloc.h> 3575374Sbp#include <sys/proc.h> 3675374Sbp#include <sys/lock.h> 3775374Sbp#include <sys/sysctl.h> 3875374Sbp#include <sys/socket.h> 3975374Sbp#include <sys/signalvar.h> 4075374Sbp#include <sys/mbuf.h> 4175374Sbp 4275374Sbp#include <sys/iconv.h> 4375374Sbp 4475374Sbp#include <netsmb/smb.h> 4575374Sbp#include <netsmb/smb_conn.h> 4675374Sbp#include <netsmb/smb_rq.h> 4775374Sbp#include <netsmb/smb_subr.h> 4875374Sbp 49227293Sedstatic MALLOC_DEFINE(M_SMBDATA, "SMBDATA", "Misc netsmb data"); 50227293Sedstatic MALLOC_DEFINE(M_SMBSTR, "SMBSTR", "netsmb string data"); 5175374SbpMALLOC_DEFINE(M_SMBTEMP, "SMBTEMP", "Temp netsmb data"); 5275374Sbp 5375374Sbpsmb_unichar smb_unieol = 0; 5475374Sbp 5575374Sbpvoid 5687192Sbpsmb_makescred(struct smb_cred *scred, struct thread *td, struct ucred *cred) 5775374Sbp{ 5887192Sbp if (td) { 5987192Sbp scred->scr_td = td; 6091406Sjhb scred->scr_cred = cred ? cred : td->td_ucred; 6175374Sbp } else { 6287192Sbp scred->scr_td = NULL; 6375374Sbp scred->scr_cred = cred ? cred : NULL; 6475374Sbp } 6575374Sbp} 6675374Sbp 6775374Sbpint 68112888Sjeffsmb_td_intr(struct thread *td) 6975374Sbp{ 70112888Sjeff struct proc *p; 7175374Sbp sigset_t tmpset; 7275374Sbp 73112888Sjeff if (td == NULL) 7475374Sbp return 0; 75112888Sjeff 76112888Sjeff p = td->td_proc; 77110849Stjr PROC_LOCK(p); 78104306Sjmallett tmpset = p->p_siglist; 79112888Sjeff SIGSETOR(tmpset, td->td_siglist); 80112888Sjeff SIGSETNAND(tmpset, td->td_sigmask); 81114983Sjhb mtx_lock(&p->p_sigacts->ps_mtx); 82114983Sjhb SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore); 83114983Sjhb mtx_unlock(&p->p_sigacts->ps_mtx); 84112888Sjeff if (SIGNOTEMPTY(td->td_siglist) && SMB_SIGMASK(tmpset)) { 85110849Stjr PROC_UNLOCK(p); 8675374Sbp return EINTR; 87110849Stjr } 88110849Stjr PROC_UNLOCK(p); 8975374Sbp return 0; 9075374Sbp} 9175374Sbp 9275374Sbpchar * 9375374Sbpsmb_strdup(const char *s) 9475374Sbp{ 9575374Sbp char *p; 96217174Scsjp size_t len; 9775374Sbp 9875374Sbp len = s ? strlen(s) + 1 : 1; 99111119Simp p = malloc(len, M_SMBSTR, M_WAITOK); 10075374Sbp if (s) 10175374Sbp bcopy(s, p, len); 10275374Sbp else 10375374Sbp *p = 0; 10475374Sbp return p; 10575374Sbp} 10675374Sbp 10775374Sbp/* 10875374Sbp * duplicate string from a user space. 10975374Sbp */ 11075374Sbpchar * 111217174Scsjpsmb_strdupin(char *s, size_t maxlen) 11275374Sbp{ 11375374Sbp char *p, bt; 114217174Scsjp int error; 115217174Scsjp size_t len; 11675374Sbp 117217174Scsjp len = 0; 11875374Sbp for (p = s; ;p++) { 11975374Sbp if (copyin(p, &bt, 1)) 12075374Sbp return NULL; 12175374Sbp len++; 12275374Sbp if (maxlen && len > maxlen) 12375374Sbp return NULL; 12475374Sbp if (bt == 0) 12575374Sbp break; 12675374Sbp } 127111119Simp p = malloc(len, M_SMBSTR, M_WAITOK); 128154434Scsjp error = copyin(s, p, len); 129154434Scsjp if (error) { 130154434Scsjp free(p, M_SMBSTR); 131154434Scsjp return (NULL); 132154434Scsjp } 13375374Sbp return p; 13475374Sbp} 13575374Sbp 13675374Sbp/* 13775374Sbp * duplicate memory block from a user space. 13875374Sbp */ 13975374Sbpvoid * 140217174Scsjpsmb_memdupin(void *umem, size_t len) 14175374Sbp{ 14275374Sbp char *p; 14375374Sbp 14475374Sbp if (len > 8 * 1024) 14575374Sbp return NULL; 146111119Simp p = malloc(len, M_SMBSTR, M_WAITOK); 14775374Sbp if (copyin(umem, p, len) == 0) 14875374Sbp return p; 14975374Sbp free(p, M_SMBSTR); 15075374Sbp return NULL; 15175374Sbp} 15275374Sbp 15375374Sbp/* 15475374Sbp * duplicate memory block in the kernel space. 15575374Sbp */ 15675374Sbpvoid * 15775374Sbpsmb_memdup(const void *umem, int len) 15875374Sbp{ 15975374Sbp char *p; 16075374Sbp 16175374Sbp if (len > 8 * 1024) 16275374Sbp return NULL; 163111119Simp p = malloc(len, M_SMBSTR, M_WAITOK); 16475374Sbp if (p == NULL) 16575374Sbp return NULL; 16675374Sbp bcopy(umem, p, len); 16775374Sbp return p; 16875374Sbp} 16975374Sbp 17075374Sbpvoid 17175374Sbpsmb_strfree(char *s) 17275374Sbp{ 17375374Sbp free(s, M_SMBSTR); 17475374Sbp} 17575374Sbp 17675374Sbpvoid 17775374Sbpsmb_memfree(void *s) 17875374Sbp{ 17975374Sbp free(s, M_SMBSTR); 18075374Sbp} 18175374Sbp 18275374Sbpvoid * 183217174Scsjpsmb_zmalloc(size_t size, struct malloc_type *type, int flags) 18475374Sbp{ 18575374Sbp 18675374Sbp return malloc(size, type, flags | M_ZERO); 18775374Sbp} 18875374Sbp 18975374Sbpvoid 19075374Sbpsmb_strtouni(u_int16_t *dst, const char *src) 19175374Sbp{ 19275374Sbp while (*src) { 193107940Srobert *dst++ = htole16(*src++); 19475374Sbp } 19575374Sbp *dst = 0; 19675374Sbp} 19775374Sbp 19875374Sbp#ifdef SMB_SOCKETDATA_DEBUG 19975374Sbpvoid 20075374Sbpm_dumpm(struct mbuf *m) { 20175374Sbp char *p; 202217174Scsjp size_t len; 20375374Sbp printf("d="); 20475374Sbp while(m) { 20575374Sbp p=mtod(m,char *); 20675374Sbp len=m->m_len; 207217174Scsjp printf("(%zu)",len); 20875374Sbp while(len--){ 20975374Sbp printf("%02x ",((int)*(p++)) & 0xff); 21075374Sbp } 21175374Sbp m=m->m_next; 21275374Sbp }; 21375374Sbp printf("\n"); 21475374Sbp} 21575374Sbp#endif 21675374Sbp 21775374Sbpint 21875374Sbpsmb_maperror(int eclass, int eno) 21975374Sbp{ 22075374Sbp if (eclass == 0 && eno == 0) 22175374Sbp return 0; 22275374Sbp switch (eclass) { 22375374Sbp case ERRDOS: 22475374Sbp switch (eno) { 22575374Sbp case ERRbadfunc: 22675374Sbp case ERRbadmcb: 22775374Sbp case ERRbadenv: 22875374Sbp case ERRbadformat: 22975374Sbp case ERRrmuns: 23075374Sbp return EINVAL; 23175374Sbp case ERRbadfile: 23275374Sbp case ERRbadpath: 23375374Sbp case ERRremcd: 23475374Sbp case 66: /* nt returns it when share not available */ 23582046Sbp case 67: /* observed from nt4sp6 when sharename wrong */ 23675374Sbp return ENOENT; 23775374Sbp case ERRnofids: 23875374Sbp return EMFILE; 23975374Sbp case ERRnoaccess: 24075374Sbp case ERRbadshare: 24175374Sbp return EACCES; 24275374Sbp case ERRbadfid: 24375374Sbp return EBADF; 24475374Sbp case ERRnomem: 24575374Sbp return ENOMEM; /* actually remote no mem... */ 24675374Sbp case ERRbadmem: 24775374Sbp return EFAULT; 24875374Sbp case ERRbadaccess: 24975374Sbp return EACCES; 25075374Sbp case ERRbaddata: 25175374Sbp return E2BIG; 25275374Sbp case ERRbaddrive: 25375374Sbp case ERRnotready: /* nt */ 25475374Sbp return ENXIO; 25575374Sbp case ERRdiffdevice: 25675374Sbp return EXDEV; 25775374Sbp case ERRnofiles: 25875374Sbp return 0; /* eeof ? */ 25975374Sbp return ETXTBSY; 26075374Sbp case ERRlock: 26175374Sbp return EDEADLK; 26275374Sbp case ERRfilexists: 26375374Sbp return EEXIST; 26475374Sbp case 123: /* dunno what is it, but samba maps as noent */ 26575374Sbp return ENOENT; 26675374Sbp case 145: /* samba */ 26775374Sbp return ENOTEMPTY; 268163992Sbp case ERRnotlocked: 269163992Sbp return 0; /* file become unlocked */ 27075374Sbp case 183: 27175374Sbp return EEXIST; 27294914Sbp case ERRquota: 27394914Sbp return EDQUOT; 27475374Sbp } 27575374Sbp break; 27675374Sbp case ERRSRV: 27775374Sbp switch (eno) { 27875374Sbp case ERRerror: 27975374Sbp return EINVAL; 28075374Sbp case ERRbadpw: 28194914Sbp case ERRpasswordExpired: 28275374Sbp return EAUTH; 28375374Sbp case ERRaccess: 28475374Sbp return EACCES; 28575374Sbp case ERRinvnid: 28675374Sbp return ENETRESET; 28775374Sbp case ERRinvnetname: 28875374Sbp SMBERROR("NetBIOS name is invalid\n"); 28975374Sbp return EAUTH; 29075374Sbp case 3: /* reserved and returned */ 29175374Sbp return EIO; 29294914Sbp case ERRaccountExpired: 29394914Sbp case ERRbadClient: 29494914Sbp case ERRbadLogonTime: 29575374Sbp return EPERM; 29694914Sbp case ERRnosupport: 29794914Sbp return EBADRPC; 29875374Sbp } 29975374Sbp break; 30075374Sbp case ERRHRD: 30175374Sbp switch (eno) { 30275374Sbp case ERRnowrite: 30375374Sbp return EROFS; 30475374Sbp case ERRbadunit: 30575374Sbp return ENODEV; 30675374Sbp case ERRnotready: 30775374Sbp case ERRbadcmd: 30875374Sbp case ERRdata: 30975374Sbp return EIO; 31075374Sbp case ERRbadreq: 31175374Sbp return EBADRPC; 31275374Sbp case ERRbadshare: 31375374Sbp return ETXTBSY; 31475374Sbp case ERRlock: 31575374Sbp return EDEADLK; 31675374Sbp } 31775374Sbp break; 31875374Sbp } 31975374Sbp SMBERROR("Unmapped error %d:%d\n", eclass, eno); 32075374Sbp return EBADRPC; 32175374Sbp} 32275374Sbp 32375374Sbpstatic int 324148517Simurasmb_copy_iconv(struct mbchain *mbp, c_caddr_t src, caddr_t dst, 325148517Simura size_t *srclen, size_t *dstlen) 32675374Sbp{ 327148517Simura int error; 328148517Simura size_t inlen = *srclen, outlen = *dstlen; 32975374Sbp 330148517Simura error = iconv_conv((struct iconv_drv*)mbp->mb_udata, &src, &inlen, 331148517Simura &dst, &outlen); 332148517Simura if (inlen != *srclen || outlen != *dstlen) { 333148517Simura *srclen -= inlen; 334148517Simura *dstlen -= outlen; 335148517Simura return 0; 336148517Simura } else 337148517Simura return error; 33875374Sbp} 33975374Sbp 34075374Sbpint 34175374Sbpsmb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src, 342217174Scsjp size_t size, int caseopt) 34375374Sbp{ 34475374Sbp struct iconv_drv *dp = vcp->vc_toserver; 34575374Sbp 34675374Sbp if (size == 0) 34775374Sbp return 0; 34875374Sbp if (dp == NULL) { 34975374Sbp return mb_put_mem(mbp, src, size, MB_MSYSTEM); 35075374Sbp } 35175374Sbp mbp->mb_copy = smb_copy_iconv; 35275374Sbp mbp->mb_udata = dp; 353227650Skevlo if (SMB_UNICODE_STRINGS(vcp)) 354227650Skevlo mb_put_padbyte(mbp); 35575374Sbp return mb_put_mem(mbp, src, size, MB_MCUSTOM); 35675374Sbp} 35775374Sbp 35875374Sbpint 35975374Sbpsmb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src, 36075374Sbp int caseopt) 36175374Sbp{ 36275374Sbp int error; 36375374Sbp 36475374Sbp error = smb_put_dmem(mbp, vcp, src, strlen(src), caseopt); 36575374Sbp if (error) 36675374Sbp return error; 367227650Skevlo if (SMB_UNICODE_STRINGS(vcp)) 368227650Skevlo return mb_put_uint16le(mbp, 0); 36975374Sbp return mb_put_uint8(mbp, 0); 37075374Sbp} 37175374Sbp 37275374Sbpint 37375374Sbpsmb_put_asunistring(struct smb_rq *rqp, const char *src) 37475374Sbp{ 37575374Sbp struct mbchain *mbp = &rqp->sr_rq; 37675374Sbp struct iconv_drv *dp = rqp->sr_vc->vc_toserver; 37775374Sbp u_char c; 37875374Sbp int error; 37975374Sbp 38075374Sbp while (*src) { 38175374Sbp iconv_convmem(dp, &c, src++, 1); 38275374Sbp error = mb_put_uint16le(mbp, c); 38375374Sbp if (error) 38475374Sbp return error; 38575374Sbp } 38675374Sbp return mb_put_uint16le(mbp, 0); 38775374Sbp} 388