1d167cf6fSWarner Losh /*- 2d122d784SJoel Dahl * Copyright (c) 2000-2001 Boris Popov 3681a5bbeSBoris Popov * All rights reserved. 4681a5bbeSBoris Popov * 5681a5bbeSBoris Popov * Redistribution and use in source and binary forms, with or without 6681a5bbeSBoris Popov * modification, are permitted provided that the following conditions 7681a5bbeSBoris Popov * are met: 8681a5bbeSBoris Popov * 1. Redistributions of source code must retain the above copyright 9681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer. 10681a5bbeSBoris Popov * 2. Redistributions in binary form must reproduce the above copyright 11681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer in the 12681a5bbeSBoris Popov * documentation and/or other materials provided with the distribution. 13681a5bbeSBoris Popov * 14681a5bbeSBoris Popov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15681a5bbeSBoris Popov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16681a5bbeSBoris Popov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17681a5bbeSBoris Popov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18681a5bbeSBoris Popov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19681a5bbeSBoris Popov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20681a5bbeSBoris Popov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21681a5bbeSBoris Popov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22681a5bbeSBoris Popov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23681a5bbeSBoris Popov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24681a5bbeSBoris Popov * SUCH DAMAGE. 25681a5bbeSBoris Popov * 26681a5bbeSBoris Popov * $FreeBSD$ 27681a5bbeSBoris Popov */ 28681a5bbeSBoris Popov #include <sys/param.h> 29681a5bbeSBoris Popov #include <sys/systm.h> 30681a5bbeSBoris Popov #include <sys/kernel.h> 313c925ad2SPoul-Henning Kamp #include <sys/clock.h> 32681a5bbeSBoris Popov #include <sys/malloc.h> 33681a5bbeSBoris Popov #include <sys/time.h> 34681a5bbeSBoris Popov #include <sys/vnode.h> 35681a5bbeSBoris Popov #include <sys/sysctl.h> 36681a5bbeSBoris Popov #include <sys/iconv.h> 37681a5bbeSBoris Popov 38681a5bbeSBoris Popov #include <netsmb/smb.h> 39681a5bbeSBoris Popov #include <netsmb/smb_conn.h> 40681a5bbeSBoris Popov #include <netsmb/smb_subr.h> 41681a5bbeSBoris Popov #include <netsmb/smb_rq.h> 42681a5bbeSBoris Popov #include <netsmb/smb_dev.h> 43681a5bbeSBoris Popov 44681a5bbeSBoris Popov #include <fs/smbfs/smbfs.h> 45681a5bbeSBoris Popov #include <fs/smbfs/smbfs_node.h> 46681a5bbeSBoris Popov #include <fs/smbfs/smbfs_subr.h> 47681a5bbeSBoris Popov 485bb84bc8SRobert Watson MALLOC_DEFINE(M_SMBFSDATA, "smbfs_data", "SMBFS private data"); 49681a5bbeSBoris Popov 50681a5bbeSBoris Popov void 51681a5bbeSBoris Popov smb_time_local2server(struct timespec *tsp, int tzoff, u_long *seconds) 52681a5bbeSBoris Popov { 5391f1c2b3SPoul-Henning Kamp *seconds = tsp->tv_sec - tzoff * 60 /*- tz_minuteswest * 60 - 54681a5bbeSBoris Popov (wall_cmos_clock ? adjkerntz : 0)*/; 55681a5bbeSBoris Popov } 56681a5bbeSBoris Popov 57681a5bbeSBoris Popov void 58681a5bbeSBoris Popov smb_time_server2local(u_long seconds, int tzoff, struct timespec *tsp) 59681a5bbeSBoris Popov { 60681a5bbeSBoris Popov tsp->tv_sec = seconds + tzoff * 60; 6191f1c2b3SPoul-Henning Kamp /*+ tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0)*/; 62681a5bbeSBoris Popov } 63681a5bbeSBoris Popov 64681a5bbeSBoris Popov /* 65681a5bbeSBoris Popov * Number of seconds between 1970 and 1601 year 66681a5bbeSBoris Popov */ 671493ed41SEric Anholt static int64_t DIFF1970TO1601 = 11644473600ULL; 68681a5bbeSBoris Popov 69681a5bbeSBoris Popov /* 70681a5bbeSBoris Popov * Time from server comes as UTC, so no need to use tz 71681a5bbeSBoris Popov */ 72681a5bbeSBoris Popov void 73681a5bbeSBoris Popov smb_time_NT2local(int64_t nsec, int tzoff, struct timespec *tsp) 74681a5bbeSBoris Popov { 75681a5bbeSBoris Popov smb_time_server2local(nsec / 10000000 - DIFF1970TO1601, 0, tsp); 76681a5bbeSBoris Popov } 77681a5bbeSBoris Popov 78681a5bbeSBoris Popov void 79681a5bbeSBoris Popov smb_time_local2NT(struct timespec *tsp, int tzoff, int64_t *nsec) 80681a5bbeSBoris Popov { 81681a5bbeSBoris Popov u_long seconds; 82681a5bbeSBoris Popov 83681a5bbeSBoris Popov smb_time_local2server(tsp, 0, &seconds); 84681a5bbeSBoris Popov *nsec = (((int64_t)(seconds) & ~1) + DIFF1970TO1601) * (int64_t)10000000; 85681a5bbeSBoris Popov } 86681a5bbeSBoris Popov 87681a5bbeSBoris Popov void 88681a5bbeSBoris Popov smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp, 89681a5bbeSBoris Popov u_int16_t *dtp, u_int8_t *dhp) 90681a5bbeSBoris Popov { 913c925ad2SPoul-Henning Kamp struct timespec tt; 923c925ad2SPoul-Henning Kamp u_long t; 93681a5bbeSBoris Popov 943c925ad2SPoul-Henning Kamp tt = *tsp; 95681a5bbeSBoris Popov smb_time_local2server(tsp, tzoff, &t); 963c925ad2SPoul-Henning Kamp tt.tv_sec = t; 973c925ad2SPoul-Henning Kamp timespec2fattime(&tt, 1, ddp, dtp, dhp); 98681a5bbeSBoris Popov } 99681a5bbeSBoris Popov 100681a5bbeSBoris Popov void 101681a5bbeSBoris Popov smb_dos2unixtime(u_int dd, u_int dt, u_int dh, int tzoff, 102681a5bbeSBoris Popov struct timespec *tsp) 103681a5bbeSBoris Popov { 104681a5bbeSBoris Popov 1053c925ad2SPoul-Henning Kamp fattime2timespec(dd, dt, dh, 1, tsp); 1063c925ad2SPoul-Henning Kamp smb_time_server2local(tsp->tv_sec, tzoff, tsp); 107681a5bbeSBoris Popov } 108681a5bbeSBoris Popov 109681a5bbeSBoris Popov static int 110681a5bbeSBoris Popov smb_fphelp(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *np, 111681a5bbeSBoris Popov int caseopt) 112681a5bbeSBoris Popov { 113681a5bbeSBoris Popov struct smbmount *smp= np->n_mount; 114681a5bbeSBoris Popov struct smbnode **npp = smp->sm_npstack; 115681a5bbeSBoris Popov int i, error = 0; 116681a5bbeSBoris Popov 117681a5bbeSBoris Popov /* simple_lock(&smp->sm_npslock);*/ 118681a5bbeSBoris Popov i = 0; 119681a5bbeSBoris Popov while (np->n_parent) { 120681a5bbeSBoris Popov if (i++ == SMBFS_MAXPATHCOMP) { 121681a5bbeSBoris Popov /* simple_unlock(&smp->sm_npslock);*/ 122681a5bbeSBoris Popov return ENAMETOOLONG; 123681a5bbeSBoris Popov } 124681a5bbeSBoris Popov *npp++ = np; 12535c5de54STim J. Robbins if ((np->n_flag & NREFPARENT) == 0) 12635c5de54STim J. Robbins break; 12711de0c59STim J. Robbins np = VTOSMB(np->n_parent); 128681a5bbeSBoris Popov } 129681a5bbeSBoris Popov /* if (i == 0) 130681a5bbeSBoris Popov return smb_put_dmem(mbp, vcp, "\\", 2, caseopt);*/ 131681a5bbeSBoris Popov while (i--) { 132681a5bbeSBoris Popov np = *--npp; 133*41f1dcccSKevin Lo if (SMB_UNICODE_STRINGS(vcp)) 134*41f1dcccSKevin Lo error = mb_put_uint16le(mbp, '\\'); 135*41f1dcccSKevin Lo else 136681a5bbeSBoris Popov error = mb_put_uint8(mbp, '\\'); 137681a5bbeSBoris Popov if (error) 138681a5bbeSBoris Popov break; 139681a5bbeSBoris Popov error = smb_put_dmem(mbp, vcp, np->n_name, np->n_nmlen, caseopt); 140681a5bbeSBoris Popov if (error) 141681a5bbeSBoris Popov break; 142681a5bbeSBoris Popov } 143681a5bbeSBoris Popov /* simple_unlock(&smp->sm_npslock);*/ 144681a5bbeSBoris Popov return error; 145681a5bbeSBoris Popov } 146681a5bbeSBoris Popov 147681a5bbeSBoris Popov int 148681a5bbeSBoris Popov smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp, 149681a5bbeSBoris Popov const char *name, int nmlen) 150681a5bbeSBoris Popov { 151681a5bbeSBoris Popov int caseopt = SMB_CS_NONE; 152681a5bbeSBoris Popov int error; 153681a5bbeSBoris Popov 154*41f1dcccSKevin Lo if (SMB_UNICODE_STRINGS(vcp)) { 155*41f1dcccSKevin Lo error = mb_put_padbyte(mbp); 156*41f1dcccSKevin Lo if (error) 157*41f1dcccSKevin Lo return error; 158*41f1dcccSKevin Lo } 159681a5bbeSBoris Popov if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0) 160681a5bbeSBoris Popov caseopt |= SMB_CS_UPPER; 161681a5bbeSBoris Popov if (dnp != NULL) { 162681a5bbeSBoris Popov error = smb_fphelp(mbp, vcp, dnp, caseopt); 163681a5bbeSBoris Popov if (error) 164681a5bbeSBoris Popov return error; 165681a5bbeSBoris Popov } 166681a5bbeSBoris Popov if (name) { 167*41f1dcccSKevin Lo if (SMB_UNICODE_STRINGS(vcp)) 168*41f1dcccSKevin Lo error = mb_put_uint16le(mbp, '\\'); 169*41f1dcccSKevin Lo else 170681a5bbeSBoris Popov error = mb_put_uint8(mbp, '\\'); 171681a5bbeSBoris Popov if (error) 172681a5bbeSBoris Popov return error; 173681a5bbeSBoris Popov error = smb_put_dmem(mbp, vcp, name, nmlen, caseopt); 174681a5bbeSBoris Popov if (error) 175681a5bbeSBoris Popov return error; 176681a5bbeSBoris Popov } 177681a5bbeSBoris Popov error = mb_put_uint8(mbp, 0); 178*41f1dcccSKevin Lo if (SMB_UNICODE_STRINGS(vcp) && error == 0) 179*41f1dcccSKevin Lo error = mb_put_uint8(mbp, 0); 180681a5bbeSBoris Popov return error; 181681a5bbeSBoris Popov } 182681a5bbeSBoris Popov 183681a5bbeSBoris Popov int 1844ebd3ea1STakanori Watanabe smbfs_fname_tolocal(struct smb_vc *vcp, char *name, int *nmlen, int caseopt) 185681a5bbeSBoris Popov { 1864ebd3ea1STakanori Watanabe int copt = (caseopt == SMB_CS_LOWER ? KICONV_FROM_LOWER : 1874ebd3ea1STakanori Watanabe (caseopt == SMB_CS_UPPER ? KICONV_FROM_UPPER : 0)); 1884ebd3ea1STakanori Watanabe int error = 0; 1891e8a6960STakanori Watanabe size_t ilen = *nmlen; 1901e8a6960STakanori Watanabe size_t olen; 1914ebd3ea1STakanori Watanabe char *ibuf = name; 1924ebd3ea1STakanori Watanabe char outbuf[SMB_MAXFNAMELEN]; 1934ebd3ea1STakanori Watanabe char *obuf = outbuf; 1944ebd3ea1STakanori Watanabe 1954ebd3ea1STakanori Watanabe if (vcp->vc_tolocal) { 1964ebd3ea1STakanori Watanabe olen = sizeof(outbuf); 1974ebd3ea1STakanori Watanabe bzero(outbuf, sizeof(outbuf)); 1984ebd3ea1STakanori Watanabe 1994ebd3ea1STakanori Watanabe /* 2004ebd3ea1STakanori Watanabe error = iconv_conv_case 2014ebd3ea1STakanori Watanabe (vcp->vc_tolocal, NULL, NULL, &obuf, &olen, copt); 2024ebd3ea1STakanori Watanabe if (error) return error; 2034ebd3ea1STakanori Watanabe */ 2044ebd3ea1STakanori Watanabe 2054ebd3ea1STakanori Watanabe error = iconv_conv_case 2064ebd3ea1STakanori Watanabe (vcp->vc_tolocal, (const char **)&ibuf, &ilen, &obuf, &olen, copt); 207*41f1dcccSKevin Lo if (error && SMB_UNICODE_STRINGS(vcp)) { 208*41f1dcccSKevin Lo /* 209*41f1dcccSKevin Lo * If using unicode, leaving a file name as it was when 210*41f1dcccSKevin Lo * convert fails will cause a problem because the file name 211*41f1dcccSKevin Lo * will contain NULL. 212*41f1dcccSKevin Lo * Here, put '?' and give converted file name. 213*41f1dcccSKevin Lo */ 214*41f1dcccSKevin Lo *obuf = '?'; 215*41f1dcccSKevin Lo olen--; 216*41f1dcccSKevin Lo error = 0; 217*41f1dcccSKevin Lo } 2184ebd3ea1STakanori Watanabe if (!error) { 2194ebd3ea1STakanori Watanabe *nmlen = sizeof(outbuf) - olen; 2204ebd3ea1STakanori Watanabe memcpy(name, outbuf, *nmlen); 2214ebd3ea1STakanori Watanabe } 2224ebd3ea1STakanori Watanabe } 2234ebd3ea1STakanori Watanabe return error; 224681a5bbeSBoris Popov } 225