1 /* 2 * Copyright (c) 2000, 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 * $Id: file.c,v 1.4 2004/12/13 00:25:21 lindak Exp $ 33 */ 34 35 /* 36 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 37 * Use is subject to license terms. 38 * 39 * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 40 */ 41 42 #include <sys/param.h> 43 #include <sys/ioctl.h> 44 #include <sys/time.h> 45 #include <sys/mount.h> 46 #include <fcntl.h> 47 #include <ctype.h> 48 #include <errno.h> 49 #include <stdio.h> 50 #include <string.h> 51 #include <strings.h> 52 #include <stdlib.h> 53 #include <pwd.h> 54 #include <grp.h> 55 #include <unistd.h> 56 #include <libintl.h> 57 58 #include <sys/types.h> 59 #include <sys/file.h> 60 61 #include <netsmb/smb.h> 62 #include <netsmb/smb_lib.h> 63 64 #include "private.h" 65 66 /* 67 * It's not actually necessary to call the CLOSEFH ioctl, but doing it 68 * makes debugging a little easier. If we were to skip the ioctl, 69 * nsmb_close would cleanup the handle, here or in process exit. 70 */ 71 int 72 smb_fh_close(int fd) 73 { 74 (void) nsmb_ioctl(fd, SMBIOC_CLOSEFH, NULL); 75 return (nsmb_close(fd)); 76 } 77 78 int 79 smb_fh_ntcreate( 80 struct smb_ctx *ctx, char *path, 81 int req_acc, int efattr, int share_acc, 82 int open_disp, int create_opts) 83 { 84 smbioc_ntcreate_t ioc; 85 int err, nmlen; 86 int new_fd = -1; 87 int32_t from_fd; 88 89 nmlen = strlen(path); 90 if (nmlen >= SMBIOC_MAX_NAME) { 91 err = EINVAL; 92 goto errout; 93 } 94 95 /* 96 * Will represent this SMB-level open as a new 97 * open device handle. Get one, then duplicate 98 * the driver session and tree bindings. 99 */ 100 new_fd = smb_open_driver(); 101 if (new_fd < 0) { 102 err = errno; 103 goto errout; 104 } 105 from_fd = ctx->ct_dev_fd; 106 if (nsmb_ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) { 107 err = errno; 108 goto errout; 109 } 110 111 /* 112 * Do the SMB-level open with the new dev handle. 113 */ 114 bzero(&ioc, sizeof (ioc)); 115 strlcpy(ioc.ioc_name, path, SMBIOC_MAX_NAME); 116 ioc.ioc_req_acc = req_acc; 117 ioc.ioc_efattr = efattr; 118 ioc.ioc_share_acc = share_acc; 119 ioc.ioc_open_disp = open_disp; 120 ioc.ioc_creat_opts = create_opts; 121 if (nsmb_ioctl(new_fd, SMBIOC_NTCREATE, &ioc) == -1) { 122 err = errno; 123 goto errout; 124 } 125 126 return (new_fd); 127 128 errout: 129 if (new_fd != -1) 130 nsmb_close(new_fd); 131 errno = err; 132 return (-1); 133 } 134 135 /* 136 * Conveinence wrapper for smb_fh_ntcreate 137 * Converts Unix-style open call to NTCreate. 138 */ 139 int 140 smb_fh_open(struct smb_ctx *ctx, const char *path, int oflag) 141 { 142 int mode, open_disp, req_acc, share_acc; 143 char *p, *ntpath = NULL; 144 int fd = -1; 145 146 /* 147 * Convert Unix path to NT (backslashes) 148 */ 149 ntpath = strdup(path); 150 if (ntpath == NULL) 151 return (-1); /* errno was set */ 152 for (p = ntpath; *p; p++) 153 if (*p == '/') 154 *p = '\\'; 155 156 /* 157 * Map O_RDONLY, O_WRONLY, O_RDWR 158 * to FREAD, FWRITE 159 */ 160 mode = (oflag & 3) + 1; 161 162 /* 163 * Compute requested access, share access. 164 */ 165 req_acc = ( 166 STD_RIGHT_READ_CONTROL_ACCESS | 167 STD_RIGHT_SYNCHRONIZE_ACCESS); 168 share_acc = NTCREATEX_SHARE_ACCESS_NONE; 169 if (mode & FREAD) { 170 req_acc |= ( 171 SA_RIGHT_FILE_READ_DATA | 172 SA_RIGHT_FILE_READ_EA | 173 SA_RIGHT_FILE_READ_ATTRIBUTES); 174 share_acc |= NTCREATEX_SHARE_ACCESS_READ; 175 } 176 if (mode & FWRITE) { 177 req_acc |= ( 178 SA_RIGHT_FILE_WRITE_DATA | 179 SA_RIGHT_FILE_APPEND_DATA | 180 SA_RIGHT_FILE_WRITE_EA | 181 SA_RIGHT_FILE_WRITE_ATTRIBUTES); 182 share_acc |= NTCREATEX_SHARE_ACCESS_WRITE; 183 } 184 185 /* 186 * Compute open disposition 187 */ 188 if (oflag & FCREAT) { 189 /* Creat if necessary. */ 190 if (oflag & FEXCL) { 191 /* exclusive */ 192 open_disp = NTCREATEX_DISP_CREATE; 193 } else if (oflag & FTRUNC) 194 open_disp = NTCREATEX_DISP_OVERWRITE_IF; 195 else 196 open_disp = NTCREATEX_DISP_OPEN_IF; 197 } else { 198 /* Not creating. */ 199 if (oflag & FTRUNC) 200 open_disp = NTCREATEX_DISP_OVERWRITE; 201 else 202 open_disp = NTCREATEX_DISP_OPEN; 203 } 204 205 fd = smb_fh_ntcreate(ctx, ntpath, 206 req_acc, SMB_EFA_NORMAL, share_acc, open_disp, 207 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE); 208 209 free(ntpath); 210 return (fd); 211 } 212 213 int 214 smb_fh_read(int fd, off64_t offset, size_t count, 215 char *dst) 216 { 217 struct smbioc_rw rwrq; 218 219 bzero(&rwrq, sizeof (rwrq)); 220 rwrq.ioc_base = dst; 221 rwrq.ioc_cnt = count; 222 rwrq.ioc_offset = offset; 223 if (nsmb_ioctl(fd, SMBIOC_READ, &rwrq) == -1) { 224 return (-1); 225 } 226 return (rwrq.ioc_cnt); 227 } 228 229 int 230 smb_fh_write(int fd, off64_t offset, size_t count, 231 const char *src) 232 { 233 struct smbioc_rw rwrq; 234 235 bzero(&rwrq, sizeof (rwrq)); 236 rwrq.ioc_base = (char *)src; 237 rwrq.ioc_cnt = count; 238 rwrq.ioc_offset = offset; 239 if (nsmb_ioctl(fd, SMBIOC_WRITE, &rwrq) == -1) { 240 return (-1); 241 } 242 return (rwrq.ioc_cnt); 243 } 244 245 /* 246 * Do a TRANSACT_NAMED_PIPE, which is basically just a 247 * pipe write and pipe read, all in one round trip. 248 * 249 * tdlen, tdata describe the data to send. 250 * rdlen, rdata on input describe the receive buffer, 251 * and on output *rdlen is the received length. 252 */ 253 int 254 smb_fh_xactnp(int fd, 255 int tdlen, const char *tdata, /* transmit */ 256 int *rdlen, char *rdata, /* receive */ 257 int *more) 258 { 259 smbioc_xnp_t ioc; 260 261 /* this gets copyin & copyout */ 262 bzero(&ioc, sizeof (ioc)); 263 ioc.ioc_tdlen = tdlen; 264 ioc.ioc_rdlen = *rdlen; 265 ioc.ioc_more = 0; 266 ioc.ioc_tdata = (char *)tdata; 267 ioc.ioc_rdata = rdata; 268 269 if (nsmb_ioctl(fd, SMBIOC_XACTNP, &ioc) == -1) { 270 *rdlen = 0; 271 return (-1); 272 } 273 274 *rdlen = ioc.ioc_rdlen; 275 *more = ioc.ioc_more; 276 277 return (0); 278 } 279