1/* 2 * Copyright (c) 2000-2001 Boris Popov 3 * All rights reserved. 4 * 5 * Portions Copyright (C) 2001 - 2012 Apple Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Boris Popov. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35#include <sys/smb_apple.h> 36#include <netsmb/smb.h> 37#include <netsmb/smb_2.h> 38#include <netsmb/smb_conn.h> 39#include <netsmb/smb_rq.h> 40#include <netsmb/smb_dev.h> 41#include <netsmb/smb_converter.h> 42 43int 44smb_usr_negotiate(struct smbioc_negotiate *vspec, vfs_context_t context, 45 struct smb_dev *sdp, int searchOnly) 46{ 47 struct smb_vc *vcp; 48 int error; 49 uint32_t usersMaxBufferLen = vspec->ioc_negotiate_token_len; 50 51 /* Convert any pointers over to using user_addr_t */ 52 if (! vfs_context_is64bit (context)) { 53 vspec->ioc_kern_saddr = CAST_USER_ADDR_T(vspec->ioc_saddr); 54 vspec->ioc_kern_laddr = CAST_USER_ADDR_T(vspec->ioc_laddr); 55 } 56 /* Now do the real work */ 57 error = smb_sm_negotiate(vspec, context, &sdp->sd_vc, sdp, searchOnly); 58 if (error) { 59 /* We always return the error in the structure, we never fail the iocl from here */ 60 vspec->ioc_errno = error; 61 return 0; 62 } 63 64 vcp = sdp->sd_vc; 65 /* Return to the user the server's capablilities */ 66 vspec->ioc_ret_caps = VC_CAPS(vcp); 67 /* Return to the user the vc flags */ 68 vspec->ioc_ret_vc_flags = vcp->vc_flags; 69 70 /* If we got a server provide init token copy that back to the caller. */ 71 vspec->ioc_negotiate_token_len = vcp->negotiate_tokenlen; 72 if ((vcp->negotiate_token) && (usersMaxBufferLen >= vcp->negotiate_tokenlen)) { 73 user_addr_t uaddr = vspec->ioc_negotiate_token; 74 error = copyout(vcp->negotiate_token, uaddr, (size_t)vcp->negotiate_tokenlen); 75 vspec->ioc_errno = error; 76 } 77 /* We are sharing the vc return the user name if there is one */ 78 if (vspec->ioc_extra_flags & SMB_SHARING_VC) { 79 if (vcp->vc_username) { 80 strlcpy(vspec->ioc_user, vcp->vc_username, sizeof(vspec->ioc_user)); 81 } 82 /* Return the size of the client and server principal name */ 83 vspec->ioc_max_client_size = vcp->vc_gss.gss_cpn_len; 84 vspec->ioc_max_target_size = vcp->vc_gss.gss_spn_len; 85 } 86 87 return error; 88} 89 90/* 91 * Connect to the resource specified by smbioc_ossn structure. 92 * It may either find an existing connection or try to establish a new one. 93 * If no errors occured smb_vc returned locked and referenced. 94 * 95 * Called from user land so we always have a reference on the share. 96 */ 97int 98smb_usr_simplerequest(struct smb_share *share, struct smbioc_rq *dp, 99 vfs_context_t context) 100{ 101 struct smb_rq rq, *rqp = &rq; 102 struct mbchain *mbp; 103 struct mdchain *mdp; 104 int32_t response_size; 105 int error; 106 107 switch (dp->ioc_cmd) { 108 case SMB_COM_CLOSE_AND_TREE_DISC: 109 case SMB_COM_TREE_CONNECT: 110 case SMB_COM_TREE_DISCONNECT: 111 case SMB_COM_NEGOTIATE: 112 case SMB_COM_SESSION_SETUP_ANDX: 113 case SMB_COM_LOGOFF_ANDX: 114 case SMB_COM_TREE_CONNECT_ANDX: 115 return EPERM; 116 } 117 /* Take the 32 bit world pointers and convert them to user_addr_t. */ 118 if (! vfs_context_is64bit (context)) { 119 dp->ioc_kern_twords = CAST_USER_ADDR_T(dp->ioc_twords); 120 dp->ioc_kern_tbytes = CAST_USER_ADDR_T(dp->ioc_tbytes); 121 dp->ioc_kern_rpbuf = CAST_USER_ADDR_T(dp->ioc_rpbuf); 122 } 123 124 error = smb_rq_init(rqp, SSTOCP(share), dp->ioc_cmd, dp->ioc_flags2, context); 125 if (error) 126 return error; 127 smb_rq_getrequest(rqp, &mbp); 128 smb_rq_wstart(rqp); 129 error = mb_put_user_mem(mbp, dp->ioc_kern_twords, dp->ioc_twc * 2, 0, context); 130 if (error) 131 goto bad; 132 smb_rq_wend(rqp); 133 smb_rq_bstart(rqp); 134 error = mb_put_user_mem(mbp, dp->ioc_kern_tbytes, dp->ioc_tbc, 0, context); 135 if (error) 136 goto bad; 137 smb_rq_bend(rqp); 138 error = smb_rq_simple(rqp); 139 if (error) 140 goto bad; 141 smb_rq_getreply(rqp, &mdp); 142 /* 143 * Amount of data left in the response buffer. 144 * Should include size of word count field + any word count data + size of 145 * byte count field + any byte count data 146 */ 147 response_size = (int32_t)md_get_size(mdp); 148 /* Make sure we have room in the users buffer */ 149 if (response_size > dp->ioc_rpbufsz) { 150 error = EBADRPC; 151 goto bad; 152 } 153 /* Copy the response into the users buffer */ 154 error = md_get_user_mem(mdp, dp->ioc_kern_rpbuf, response_size, 0, context); 155 if (error) 156 goto bad; 157 158 dp->ioc_rpbufsz = response_size; 159 160bad: 161 /* 162 * Returning an error to the IOCTL code means no other information in the 163 * structure will be updated. The nsmb_dev_ioctl routine should only return 164 * unexpected internal errors. We now always return the nt status code and 165 * the errno in the ioc structure. Any internal smb error is store in the errno 166 * field or if we get a nt status code then it holds the mapped error number. 167 */ 168 dp->ioc_ntstatus = rqp->sr_ntstatus; 169 dp->ioc_errno = error; 170 dp->ioc_flags = rqp->sr_rpflags; 171 dp->ioc_flags2 = rqp->sr_rpflags2; 172 smb_rq_done(rqp); 173 return 0; 174 175} 176 177int 178smb_cpdatain(struct mbchain *mbp, user_addr_t data, int len, vfs_context_t context) 179{ 180 int error; 181 182 if (len == 0) 183 return 0; 184 error = mb_init(mbp); 185 if (! error) 186 error = mb_put_user_mem(mbp, data, len, 0, context); 187 return error; 188} 189 190/* 191* Called from user land so we always have a reference on the share. 192*/ 193int 194smb_usr_t2request(struct smb_share *share, struct smbioc_t2rq *dp, vfs_context_t context) 195{ 196 struct smb_t2rq t2, *t2p = &t2; 197 struct mdchain *mdp; 198 int error; 199 uint16_t len; 200 201 if (dp->ioc_setupcnt > SMB_MAXSETUPWORDS) 202 return EINVAL; 203 204 error = smb_t2_init(t2p, SSTOCP(share), dp->ioc_setup, dp->ioc_setupcnt, context); 205 if (error) { 206 return error; 207 } 208 209 len = t2p->t2_setupcount = dp->ioc_setupcnt; 210 if (len > 1) 211 t2p->t2_setupdata = dp->ioc_setup; 212 213 /* Take the 32 bit world pointers and convert them to user_addr_t. */ 214 if (! vfs_context_is64bit (context)) { 215 dp->ioc_kern_name = CAST_USER_ADDR_T(dp->ioc_name); 216 dp->ioc_kern_tparam = CAST_USER_ADDR_T(dp->ioc_tparam); 217 dp->ioc_kern_tdata = CAST_USER_ADDR_T(dp->ioc_tdata); 218 dp->ioc_kern_rparam = CAST_USER_ADDR_T(dp->ioc_rparam); 219 dp->ioc_kern_rdata = CAST_USER_ADDR_T(dp->ioc_rdata); 220 } 221 222 /* ioc_name_len includes the null byte, ioc_kern_name is a c-style string */ 223 if (dp->ioc_kern_name && dp->ioc_name_len) { 224 t2p->t_name = smb_memdupin(dp->ioc_kern_name, dp->ioc_name_len); 225 if (t2p->t_name == NULL) { 226 error = ENOMEM; 227 goto bad; 228 } 229 } 230 t2p->t2_maxscount = 0; 231 t2p->t2_maxpcount = dp->ioc_rparamcnt; 232 t2p->t2_maxdcount = dp->ioc_rdatacnt; 233 234 error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_kern_tparam, dp->ioc_tparamcnt, context); 235 if (! error) 236 error = smb_cpdatain(&t2p->t2_tdata, dp->ioc_kern_tdata, dp->ioc_tdatacnt, context); 237 if (error) { 238 goto bad; 239 } 240 241 error = smb_t2_request(t2p); 242 /* 243 * We now convert all non SMB_FLAGS2_ERR_STATUS errors into ntstatus 244 * error codes, we only deal with ntstatus error here. 245 */ 246 dp->ioc_ntstatus = t2p->t2_ntstatus; 247 dp->ioc_flags2 = t2p->t2_sr_rpflags2; 248 if (error) { 249 goto bad; 250 } 251 mdp = &t2p->t2_rparam; 252 if (mdp->md_top) { 253 len = m_fixhdr(mdp->md_top); 254 if (len > dp->ioc_rparamcnt) { 255 error = EMSGSIZE; 256 goto bad; 257 } 258 dp->ioc_rparamcnt = len; 259 error = md_get_user_mem(mdp, dp->ioc_kern_rparam, len, 0, context); 260 if (error) { 261 goto bad; 262 } 263 } else 264 dp->ioc_rparamcnt = 0; 265 mdp = &t2p->t2_rdata; 266 if (mdp->md_top) { 267 len = m_fixhdr(mdp->md_top); 268 if (len > dp->ioc_rdatacnt) { 269 error = EMSGSIZE; 270 goto bad; 271 } 272 dp->ioc_rdatacnt = len; 273 error = md_get_user_mem(mdp, dp->ioc_kern_rdata, len, 0, context); 274 } else 275 dp->ioc_rdatacnt = 0; 276bad: 277 SMB_FREE(t2p->t_name, M_SMBSTR); 278 smb_t2_done(t2p); 279 return error; 280} 281 282/* 283 * Converts UTF8 string to a network style STRING. The network STRING returned 284 * may be ASCII or UTF16, depending on what was negotiated with the server. The 285 * lower level routines will handle any byte swapping issue and will set the 286 * precomosed flag. The only flag support currently is UTF_SFM_CONVERSIONS. 287 */ 288int smb_usr_convert_path_to_network(struct smb_vc *vc, struct smbioc_path_convert * dp) 289{ 290 size_t ntwrk_len = (size_t)dp->ioc_dest_len; 291 char *network = NULL; 292 char *utf8str = NULL; 293 int error; 294 295 utf8str = smb_memdupin(dp->ioc_kern_src, dp->ioc_src_len); 296 if (utf8str) { 297 SMB_MALLOC(network, char *, ntwrk_len, M_SMBSTR, M_WAITOK | M_ZERO); 298 } 299 300 if ((utf8str == NULL) || (network == NULL)) { 301 error = ENOMEM; 302 goto done; 303 } 304 error = smb_convert_path_to_network(utf8str, dp->ioc_src_len, network, &ntwrk_len, 305 '\\', (int)dp->ioc_flags, SMB_UNICODE_STRINGS(vc)); 306 if (error) { 307 SMBERROR("converter failed : %d\n", error); 308 SMBDEBUG("utf8str = %s src len = %d dest len = %d\n", utf8str, 309 (int)dp->ioc_src_len, (int)dp->ioc_dest_len); 310 goto done; 311 } 312 313 error = copyout(network, dp->ioc_kern_dest, ntwrk_len); 314 if (error) { 315 SMBERROR("copyout failed : %d\n", error); 316 smb_hexdump(__FUNCTION__, "dest buffer: ", (u_char *)network, ntwrk_len); 317 goto done; 318 } 319 320 dp->ioc_dest_len = (uint32_t)ntwrk_len; 321 322done: 323 if (utf8str) 324 SMB_FREE(utf8str, M_SMBSTR); 325 if (network) 326 SMB_FREE(network, M_SMBSTR); 327 return error; 328} 329 330/* 331 * Converts a network style STRING to a UTF8 string. The network STRING can be 332 * formatted as an ASCII or UTF16 string. If the network STRING is in UTF16 format 333 * then this routine expects it to be decomosed. The only flag support currently 334 * is UTF_SFM_CONVERSIONS. 335 */ 336int smb_usr_convert_network_to_path(struct smb_vc *vc, struct smbioc_path_convert * dp) 337{ 338 size_t utf8str_len = (size_t)dp->ioc_dest_len; 339 char *network = NULL; 340 char *utf8str = NULL; 341 int error; 342 343 network = smb_memdupin(dp->ioc_kern_src, dp->ioc_src_len); 344 if (network) { 345 SMB_MALLOC(utf8str, char *, utf8str_len, M_SMBSTR, M_WAITOK | M_ZERO); 346 } 347 348 if ((utf8str == NULL) || (network == NULL)) { 349 error = ENOMEM; 350 goto done; 351 } 352 353 error = smb_convert_network_to_path(network, dp->ioc_src_len, utf8str, 354 &utf8str_len, '\\', (int)dp->ioc_flags, 355 SMB_UNICODE_STRINGS(vc)); 356 if (error) { 357 SMBERROR("converter failed : %d\n", error); 358 smb_hexdump(__FUNCTION__, "source buffer: ", (u_char *)network, dp->ioc_src_len); 359 goto done; 360 } 361 362 error = copyout(utf8str, dp->ioc_kern_dest, utf8str_len); 363 if (error) { 364 SMBERROR("copyout failed : %d\n", error); 365 SMBDEBUG("utf8str = %s src len = %d dest len = %d\n", utf8str, 366 (int)dp->ioc_src_len, (int)dp->ioc_dest_len); 367 goto done; 368 } 369 dp->ioc_dest_len = (uint32_t)utf8str_len; 370 371done: 372 if (utf8str) 373 SMB_FREE(utf8str, M_SMBSTR); 374 if (network) 375 SMB_FREE(network, M_SMBSTR); 376 return error; 377} 378 379/* 380 * They are setting the network user identity that was obtain by lsa. Currently 381 * we only support adding the sid in the future we may want the account name 382 * and domian name. 383 */ 384int smb_usr_set_network_identity(struct smb_vc *vcp, struct smbioc_ntwrk_identity *ntwrkID) 385{ 386 if (vcp->vc_flags & SMBV_NETWORK_SID) { 387 /* Currently we only allow it to be set once */ 388 return EEXIST; 389 } 390 391 if (ntwrkID->ioc_ntsid_len != sizeof(ntsid_t)) { 392 /* Needs to be the correct size */ 393 return EINVAL; 394 } 395 memcpy(&vcp->vc_ntwrk_sid, &ntwrkID->ioc_ntsid, (size_t)ntwrkID->ioc_ntsid_len); 396 vcp->vc_flags |= SMBV_NETWORK_SID; 397 return 0; 398} 399 400/* 401 * Called from user land so we always have a reference on the share. 402 */ 403int 404smb_usr_fsctl(struct smb_share *share, struct smbioc_fsctl *fsctl, vfs_context_t context) 405{ 406 struct smb_ntrq * ntp = NULL; 407 int error = 0; 408 409 if (fsctl->ioc_tdatacnt > INT_MAX) { 410 error = EINVAL; 411 goto done; 412 } 413 414 fsctl->ioc_errno = 0; 415 fsctl->ioc_ntstatus = 0; 416 417 /* Take the 32 bit world pointers and convert them to user_addr_t. */ 418 if (! vfs_context_is64bit (context)) { 419 fsctl->ioc_kern_tdata = CAST_USER_ADDR_T(fsctl->ioc_tdata); 420 fsctl->ioc_kern_rdata = CAST_USER_ADDR_T(fsctl->ioc_rdata); 421 } 422 423 error = smb_nt_alloc(SSTOCP(share), NT_TRANSACT_IOCTL, context, &ntp); 424 if (error) { 425 goto done; 426 } 427 428 /* The NT_TRANSACT_IOCTL setup structure is: 429 * uint32_t FunctionCode 430 * uint16_t FID 431 * uint8_t IsFctl 432 * uint8_t IsFlags 433 */ 434 mb_init(&ntp->nt_tsetup); 435 mb_put_uint32le(&ntp->nt_tsetup, fsctl->ioc_fsctl); 436 mb_put_uint16le(&ntp->nt_tsetup, fsctl->ioc_fh); 437 mb_put_uint8(&ntp->nt_tsetup, 1); 438 mb_put_uint8(&ntp->nt_tsetup, 0); 439 440 /* The fsctl arguments go in the transmit data. */ 441 if (fsctl->ioc_tdatacnt) { 442 mb_init(&ntp->nt_tdata); 443 error = mb_put_user_mem(&ntp->nt_tdata, fsctl->ioc_kern_tdata, 444 fsctl->ioc_tdatacnt, 0, context); 445 if (error) { 446 goto done; 447 } 448 } 449 450 /* We don't expect any returned params from NT_TRANSACT_IOCTL. */ 451 ntp->nt_maxpcount = 0; 452 ntp->nt_maxdcount = fsctl->ioc_rdatacnt; 453 454 fsctl->ioc_errno = smb_nt_request(ntp); 455 fsctl->ioc_ntstatus = ntp->nt_status; 456 457 if (fsctl->ioc_errno) { 458 error = 0; 459 goto done; 460 } 461 462 /* The data buffer wasn't big enough. Caller will have to retry. */ 463 if (ntp->nt_flags & SMBT2_MOREDATA) { 464 fsctl->ioc_errno = ENOSPC; 465 error = 0; 466 goto done; 467 } 468 469 if (ntp->nt_rdata.md_top) { 470 size_t datalen = m_fixhdr(ntp->nt_rdata.md_top); 471 if (datalen > fsctl->ioc_rdatacnt) { 472 SMBERROR("datalen(%u) > ioc_rdatacnt(%u)", 473 (unsigned)datalen, (unsigned)fsctl->ioc_rdatacnt); 474 error = EMSGSIZE; 475 goto done; 476 } 477 478 fsctl->ioc_rdatacnt = (uint32_t)datalen; 479 error = md_get_user_mem(&ntp->nt_rdata, fsctl->ioc_kern_rdata, 480 (uint32_t)datalen, 0, context); 481 if (error) { 482 SMBERROR("md_get_user_mem failed with %d", error); 483 goto done; 484 } 485 } else { 486 fsctl->ioc_rdatacnt = 0; 487 } 488 489done: 490 if (ntp) { 491 smb_nt_done(ntp); 492 } 493 494 return error; 495} 496 497