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 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/kernel.h> 31 #include <sys/clock.h> 32 #include <sys/malloc.h> 33 #include <sys/time.h> 34 #include <sys/vnode.h> 35 #include <sys/sysctl.h> 36 #include <sys/iconv.h> 37 38 #include <netsmb/smb.h> 39 #include <netsmb/smb_conn.h> 40 #include <netsmb/smb_subr.h> 41 #include <netsmb/smb_rq.h> 42 #include <netsmb/smb_dev.h> 43 44 #include <fs/smbfs/smbfs.h> 45 #include <fs/smbfs/smbfs_node.h> 46 #include <fs/smbfs/smbfs_subr.h> 47 48 MALLOC_DEFINE(M_SMBFSDATA, "smbfs_data", "SMBFS private data"); 49 MALLOC_DEFINE(M_SMBFSCRED, "smbfs_cred", "SMBFS cred data"); 50 51 void 52 smb_time_local2server(struct timespec *tsp, int tzoff, u_long *seconds) 53 { 54 *seconds = tsp->tv_sec - tzoff * 60 /*- tz_minuteswest * 60 - 55 (wall_cmos_clock ? adjkerntz : 0)*/; 56 } 57 58 void 59 smb_time_server2local(u_long seconds, int tzoff, struct timespec *tsp) 60 { 61 tsp->tv_sec = seconds + tzoff * 60; 62 } 63 64 /* 65 * Number of seconds between 1970 and 1601 year 66 */ 67 static int64_t DIFF1970TO1601 = 11644473600ULL; 68 69 /* 70 * Time from server comes as UTC, so no need to use tz 71 */ 72 void 73 smb_time_NT2local(int64_t nsec, int tzoff, struct timespec *tsp) 74 { 75 smb_time_server2local(nsec / 10000000 - DIFF1970TO1601, 0, tsp); 76 } 77 78 void 79 smb_time_local2NT(struct timespec *tsp, int tzoff, int64_t *nsec) 80 { 81 u_long seconds; 82 83 smb_time_local2server(tsp, 0, &seconds); 84 *nsec = (((int64_t)(seconds) & ~1) + DIFF1970TO1601) * (int64_t)10000000; 85 } 86 87 void 88 smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp, 89 u_int16_t *dtp, u_int8_t *dhp) 90 { 91 struct timespec tt; 92 u_long t; 93 94 tt = *tsp; 95 smb_time_local2server(tsp, tzoff, &t); 96 tt.tv_sec = t; 97 timespec2fattime(&tt, 1, ddp, dtp, dhp); 98 } 99 100 void 101 smb_dos2unixtime(u_int dd, u_int dt, u_int dh, int tzoff, 102 struct timespec *tsp) 103 { 104 105 fattime2timespec(dd, dt, dh, 1, tsp); 106 smb_time_server2local(tsp->tv_sec, tzoff, tsp); 107 } 108 109 int 110 smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp, 111 const char *name, int nmlen) 112 { 113 int caseopt = SMB_CS_NONE; 114 int error; 115 116 if (SMB_UNICODE_STRINGS(vcp)) { 117 error = mb_put_padbyte(mbp); 118 if (error) 119 return error; 120 } 121 if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0) 122 caseopt |= SMB_CS_UPPER; 123 if (dnp != NULL) { 124 error = smb_put_dmem(mbp, vcp, dnp->n_rpath, dnp->n_rplen, 125 caseopt); 126 if (error) 127 return error; 128 if (name) { 129 /* Put the separator */ 130 if (SMB_UNICODE_STRINGS(vcp)) 131 error = mb_put_uint16le(mbp, '\\'); 132 else 133 error = mb_put_uint8(mbp, '\\'); 134 if (error) 135 return error; 136 /* Put the name */ 137 error = smb_put_dmem(mbp, vcp, name, nmlen, caseopt); 138 if (error) 139 return error; 140 } 141 } 142 /* Put NULL terminator. */ 143 if (SMB_UNICODE_STRINGS(vcp)) 144 error = mb_put_uint16le(mbp, 0); 145 else 146 error = mb_put_uint8(mbp, 0); 147 return error; 148 } 149 150 int 151 smbfs_fname_tolocal(struct smb_vc *vcp, char *name, int *nmlen, int caseopt) 152 { 153 int copt = (caseopt == SMB_CS_LOWER ? KICONV_FROM_LOWER : 154 (caseopt == SMB_CS_UPPER ? KICONV_FROM_UPPER : 0)); 155 int error = 0; 156 size_t ilen = *nmlen; 157 size_t olen; 158 char *ibuf = name; 159 char outbuf[SMB_MAXFNAMELEN]; 160 char *obuf = outbuf; 161 162 if (vcp->vc_tolocal) { 163 olen = sizeof(outbuf); 164 bzero(outbuf, sizeof(outbuf)); 165 166 /* 167 error = iconv_conv_case 168 (vcp->vc_tolocal, NULL, NULL, &obuf, &olen, copt); 169 if (error) return error; 170 */ 171 172 error = iconv_conv_case(vcp->vc_tolocal, 173 __DECONST(const char **, &ibuf), &ilen, &obuf, &olen, copt); 174 if (error && SMB_UNICODE_STRINGS(vcp)) { 175 /* 176 * If using unicode, leaving a file name as it was when 177 * convert fails will cause a problem because the file name 178 * will contain NULL. 179 * Here, put '?' and give converted file name. 180 */ 181 *obuf = '?'; 182 olen--; 183 error = 0; 184 } 185 if (!error) { 186 *nmlen = sizeof(outbuf) - olen; 187 memcpy(name, outbuf, *nmlen); 188 } 189 } 190 return error; 191 } 192 193 void * 194 smbfs_malloc_scred(void) 195 { 196 return (malloc(sizeof(struct smb_cred), M_SMBFSCRED, M_WAITOK)); 197 } 198 199 void 200 smbfs_free_scred(void *scred) 201 { 202 free(scred, M_SMBFSCRED); 203 } 204