1/* 2 * Copyright (c) 2008 - 2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include "smbclient.h" 25#include "smbclient_private.h" 26#include "ntstatus.h" 27 28#include <netsmb/smbio.h> 29#include <netsmb/upi_mbuf.h> 30#include <netsmb/smb_lib.h> 31#include <sys/smb_byte_order.h> 32#include <sys/mchain.h> 33#include <netsmb/rq.h> 34#include <netsmb/smb_converter.h> 35#include <netsmb/smbio_2.h> 36 37/* 38 * Note: These are the user space APIs into the SMB client. They take in 39 * args and calls the coresponding function smbio_ to do the ioctl call 40 * into the kernel and parse out the results. 41 */ 42 43/* 44 * Forward declare SMBQueryDir since its declared in smbclient_internal.h 45 * If we ever make this public and move it into smbclient.h, then we can 46 * remove this forward declaration. 47 */ 48NTSTATUS SMBQueryDir(SMBHANDLE inConnection, 49 uint8_t file_info_class, 50 uint8_t flags, 51 uint32_t file_index, 52 SMBFID fid, 53 const char * name, 54 uint32_t name_len, 55 char * rcv_output_buffer, 56 uint32_t rcv_max_output_len, 57 uint32_t * rcv_output_len, 58 uint32_t * query_dir_reply_len); 59 60 61static NTSTATUS 62SMBMapError (int error) 63{ 64 /* Is it a Posix error? If so, map it to a NT status */ 65 if ((error >= EPERM) && (error <= ELAST)) { 66 /* remap it to NT status */ 67 switch (error) { 68 case EOVERFLOW: 69 return STATUS_BUFFER_OVERFLOW; 70 case ENOMEM: 71 return STATUS_NO_MEMORY; 72 case EINVAL: 73 return STATUS_INVALID_PARAMETER; 74 case ENOTSUP: 75 return STATUS_NOT_IMPLEMENTED; 76 case ENOENT: 77 return STATUS_OBJECT_NAME_NOT_FOUND; 78 default: 79 smb_log_info("%s: unmapped syserr = %s", 80 ASL_LEVEL_DEBUG, 81 __FUNCTION__, 82 strerror(error)); 83 return STATUS_UNSUCCESSFUL; 84 } 85 } 86 87 /* Must already be a NT Status */ 88 return (error); 89} 90 91 92NTSTATUS 93SMBCreateFile( 94 SMBHANDLE inConnection, 95 const char * lpFileName, 96 uint32_t dwDesiredAccess, 97 uint32_t dwShareMode, 98 void * lpSecurityAttributes, 99 uint32_t dwCreateDisposition, 100 uint32_t dwFlagsAndAttributes, 101 SMBFID * phFile) 102{ 103#pragma unused(lpSecurityAttributes) 104 struct open_inparms inparms; 105 void * hContext; 106 SMBFID fid; 107 int err; 108 NTSTATUS status; 109 110 status = SMBServerContext(inConnection, &hContext); 111 if (!NT_SUCCESS(status)) { 112 return status; 113 } 114 memset(&inparms, 0, sizeof(inparms)); 115 inparms.rights = dwDesiredAccess; 116 inparms.attrs = SMB_EFA_NORMAL; 117 inparms.shareMode = dwShareMode; 118 inparms.disp = dwCreateDisposition; 119 inparms.createOptions = dwFlagsAndAttributes; 120 121 err = smb2io_ntcreatex(hContext, lpFileName, NULL, &inparms, NULL, &fid); 122 status = SMBMapError(err); 123 if (!NT_SUCCESS(status)) { 124 return status; 125 } 126 127 *phFile = fid; 128 return STATUS_SUCCESS; 129} 130 131 132NTSTATUS 133SMBCreateNamedStreamFile( 134 SMBHANDLE inConnection, 135 const char * lpFileName, 136 const char * lpFileStreamName, 137 uint32_t dwDesiredAccess, 138 uint32_t dwShareMode, 139 void * lpSecurityAttributes, 140 uint32_t dwCreateDisposition, 141 uint32_t dwFlagsAndAttributes, 142 SMBFID * phFile) 143{ 144#pragma unused(lpSecurityAttributes) 145 struct open_inparms inparms; 146 void * hContext; 147 SMBFID fid; 148 int err; 149 NTSTATUS status; 150 151 status = SMBServerContext(inConnection, &hContext); 152 if (!NT_SUCCESS(status)) { 153 return status; 154 } 155 memset(&inparms, 0, sizeof(inparms)); 156 inparms.rights = dwDesiredAccess; 157 inparms.attrs = SMB_EFA_NORMAL; 158 inparms.shareMode = dwShareMode; 159 inparms.disp = dwCreateDisposition; 160 inparms.createOptions = dwFlagsAndAttributes; 161 162 err = smb2io_ntcreatex(hContext, lpFileName, lpFileStreamName, &inparms, 163 NULL, &fid); 164 status = SMBMapError(err); 165 if (!NT_SUCCESS(status)) { 166 return status; 167 } 168 169 *phFile = fid; 170 return STATUS_SUCCESS; 171} 172 173NTSTATUS 174SMBTransactMailSlot( 175 SMBHANDLE inConnection, 176 const char *MailSlot, 177 const void *sndParamBuffer, 178 size_t sndParamBufferSize, 179 void *rcvParamBuffer, 180 size_t *rcvParamBufferSize, 181 void *rcvDataBuffer, 182 size_t *rcvDataBufferSize) 183{ 184 NTSTATUS status; 185 void * hContext; 186 int error; 187 188 status = SMBServerContext(inConnection, &hContext); 189 if (!NT_SUCCESS(status)) { 190 return status; 191 } 192 193 error = smbio_transact(hContext, NULL, 0, MailSlot, 194 sndParamBuffer, sndParamBufferSize, 195 NULL, 0, 196 rcvParamBuffer, rcvParamBufferSize, 197 rcvDataBuffer, rcvDataBufferSize); 198 if (error) { 199 errno = error; 200 /* XXX map real NTSTATUS code */ 201 return (error == EOVERFLOW) ? STATUS_BUFFER_OVERFLOW : STATUS_UNEXPECTED_IO_ERROR; 202 } 203 204 return STATUS_SUCCESS; 205} 206 207NTSTATUS 208SMBTransactNamedPipe( 209 SMBHANDLE inConnection, 210 SMBFID hNamedPipe, 211 const void *inBuffer, 212 size_t inBufferSize, 213 void * outBuffer, 214 size_t outBufferSize, 215 size_t * bytesRead) 216{ 217 int error; 218 NTSTATUS status; 219 void * hContext; 220 const char *namePipe = "\\PIPE\\"; /* Always just pipe for us */ 221 uint64_t setup[2]; 222 223 status = SMBServerContext(inConnection, &hContext); 224 if (!NT_SUCCESS(status)) { 225 return status; 226 } 227 setup[0] = TRANS_TRANSACT_NAMED_PIPE; 228 setup[1] = hNamedPipe; 229 230 error = smb2io_transact(hContext, setup, 2, namePipe, NULL, 0, 231 inBuffer, inBufferSize, NULL, NULL, 232 outBuffer, &outBufferSize); 233 status = SMBMapError(error); 234 if (!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW)) { 235 return status; 236 } 237 238 *bytesRead = outBufferSize; 239 return STATUS_SUCCESS; 240} 241 242NTSTATUS 243SMBReadFile( 244 SMBHANDLE inConnection, 245 SMBFID hFile, 246 void * lpBuffer, 247 off_t nOffset, 248 size_t nNumberOfBytesToRead, 249 size_t *lpNumberOfBytesRead) 250{ 251 void * hContext; 252 NTSTATUS status; 253 int err; 254 uint32_t bytes_read = 0; 255 256 status = SMBServerContext(inConnection, &hContext); 257 if (!NT_SUCCESS(status)) { 258 return status; 259 } 260 261 err = smb2io_read(hContext, hFile, nOffset, 262 (uint32_t) nNumberOfBytesToRead, (char *) lpBuffer, 263 &bytes_read); 264 status = SMBMapError(err); 265 if (!NT_SUCCESS(status)) { 266 return status; 267 } 268 269 *lpNumberOfBytesRead = bytes_read; 270 return STATUS_SUCCESS; 271} 272 273NTSTATUS 274SMBDeviceIoControl( 275 SMBHANDLE inConnection, 276 SMBFID hDevice, 277 uint32_t dwIoControlCode, 278 const void *lpInBuffer, 279 size_t nInBufferSize, 280 void * lpOutBuffer, 281 size_t nOutBufferSize, 282 size_t * lpBytesReturned) 283{ 284 struct smb_ctx * ctx; 285 struct smbioc_fsctl args; 286 NTSTATUS status; 287 288 status = SMBServerContext(inConnection, (void **)&ctx); 289 if (!NT_SUCCESS(status)) { 290 return status; 291 } 292 293 if (hDevice > UINT16_MAX) { 294 /* No large file handle support until SMB 2/3 */ 295 return STATUS_INVALID_HANDLE; 296 } 297 298 if (nInBufferSize > INT_MAX || nOutBufferSize > INT_MAX) { 299 return STATUS_INVALID_PARAMETER; 300 } 301 302 bzero(&args, sizeof(args)); 303 args.ioc_version = SMB_IOC_STRUCT_VERSION; 304 args.ioc_fh = (smbfh)hDevice; 305 args.ioc_fsctl = dwIoControlCode; 306 args.ioc_tdatacnt = (uint32_t)nInBufferSize; 307 args.ioc_rdatacnt = (uint32_t)nOutBufferSize; 308 args.ioc_tdata = (void *)lpInBuffer; 309 args.ioc_rdata = (void *)lpOutBuffer; 310 311 if (smb_ioctl_call(ctx->ct_fd, SMBIOC_FSCTL, &args) == -1) { 312 /* XXX need to map errno */ 313 return STATUS_INVALID_DEVICE_REQUEST; 314 } 315 316 if (NT_SUCCESS(args.ioc_ntstatus)) { 317 if (args.ioc_errno) { 318 /* XXX need to map errno */ 319 return STATUS_UNEXPECTED_NETWORK_ERROR; 320 } 321 322 if (lpBytesReturned) { 323 /* Report updated response data size if the caller wants it. */ 324 *lpBytesReturned = (size_t)args.ioc_rdatacnt; 325 } 326 } 327 return args.ioc_ntstatus; 328} 329 330NTSTATUS 331SMBWriteFile( 332 SMBHANDLE inConnection, 333 SMBFID hFile, 334 const void *lpBuffer, 335 off_t nOffset, 336 size_t nNumberOfBytesToWrite, 337 size_t *lpNumberOfBytesWritten) 338{ 339 void * hContext; 340 NTSTATUS status; 341 int err; 342 uint32_t bytes_written = 0; 343 344 status = SMBServerContext(inConnection, &hContext); 345 if (!NT_SUCCESS(status)) { 346 return status; 347 } 348 349 err = smb2io_write(hContext, hFile, nOffset, 350 (uint32_t) nNumberOfBytesToWrite, (char *) lpBuffer, 351 &bytes_written); 352 status = SMBMapError(err); 353 if (!NT_SUCCESS(status)) { 354 return status; 355 } 356 357 *lpNumberOfBytesWritten = bytes_written; 358 return STATUS_SUCCESS; 359} 360 361NTSTATUS 362SMBCloseFile( 363 SMBHANDLE inConnection, 364 SMBFID hFile) 365{ 366 void * hContext; 367 NTSTATUS status; 368 int err; 369 370 status = SMBServerContext(inConnection, &hContext); 371 if (!NT_SUCCESS(status)) { 372 return status; 373 } 374 375 err = smb2io_close_file(hContext, hFile); 376 status = SMBMapError(err); 377 if (!NT_SUCCESS(status)) { 378 return status; 379 } 380 381 return STATUS_SUCCESS; 382} 383 384NTSTATUS 385SMBQueryDir( 386 SMBHANDLE inConnection, 387 uint8_t file_info_class, 388 uint8_t flags, 389 uint32_t file_index, 390 SMBFID fid, 391 const char * name, 392 uint32_t name_len, 393 char * rcv_output_buffer, 394 uint32_t rcv_max_output_len, 395 uint32_t * rcv_output_len, 396 uint32_t * query_dir_reply_len) 397{ 398 int error; 399 NTSTATUS status; 400 void * hContext; 401 402 status = SMBServerContext(inConnection, &hContext); 403 if (!NT_SUCCESS(status)) { 404 return status; 405 } 406 407 error = smb2io_query_dir(hContext, 408 file_info_class, 409 flags, 410 file_index, 411 fid, 412 name, name_len, 413 rcv_output_buffer, rcv_max_output_len, 414 rcv_output_len, query_dir_reply_len); 415 status = SMBMapError(error); 416 if (!NT_SUCCESS(status)) { 417 return status; 418 } 419 420 return STATUS_SUCCESS; 421} 422 423/* vim: set sw=4 ts=4 tw=79 et: */ 424