1 /* 2 * Copyright (c) 2011 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 /* 25 * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/time.h> 31 #include <sys/kmem.h> 32 #include <sys/proc.h> 33 #include <sys/lock.h> 34 #include <sys/socket.h> 35 #include <sys/mount.h> 36 #include <sys/sunddi.h> 37 #include <sys/cmn_err.h> 38 #include <sys/atomic.h> 39 #include <sys/sdt.h> 40 41 #include <netsmb/smb_osdep.h> 42 43 #include <netsmb/smb.h> 44 #include <netsmb/smb2.h> 45 #include <netsmb/smb_conn.h> 46 #include <netsmb/smb_subr.h> 47 #include <netsmb/smb_tran.h> 48 #include <netsmb/smb_rq.h> 49 #include <netsmb/smb2_rq.h> 50 51 static const uint8_t SMB2_SIGNATURE[4] = SMB2_PROTOCOL_ID; 52 53 static int smb2_rq_enqueue(struct smb_rq *rqp); 54 static int smb2_rq_reply(struct smb_rq *rqp); 55 56 /* 57 * Given a request with it's body already composed, 58 * rewind to the start and fill in the SMB2 header. 59 * This is called when the request is enqueued, 60 * so we have the final message ID etc. 61 */ 62 void 63 smb2_rq_fillhdr(struct smb_rq *rqp) 64 { 65 struct mbchain mbtmp, *mbp = &mbtmp; 66 uint16_t creditcharge, creditrequest; 67 size_t len; 68 mblk_t *m; 69 70 ASSERT((rqp->sr2_nextcmd & 7) == 0); 71 if (rqp->sr2_nextcmd != 0) { 72 len = msgdsize(rqp->sr_rq.mb_top); 73 ASSERT((len & 7) == 0); 74 } 75 76 /* 77 * When sending negotiate, we don't technically know yet 78 * if the server handles SMB 2.1 or later and credits. 79 * Negotiate is supposed to set these to zero. 80 */ 81 if (rqp->sr2_command == SMB2_NEGOTIATE) { 82 creditcharge = creditrequest = 0; 83 } else { 84 creditcharge = rqp->sr2_creditcharge; 85 creditrequest = rqp->sr2_creditsrequested; 86 } 87 88 /* 89 * Fill in the SMB2 header using a dup of the first mblk, 90 * which points at the same data but has its own wptr, 91 * so we can rewind without trashing the message. 92 */ 93 m = dupb(rqp->sr_rq.mb_top); 94 m->b_wptr = m->b_rptr; /* rewind */ 95 mb_initm(mbp, m); 96 97 mb_put_mem(mbp, SMB2_SIGNATURE, 4, MB_MSYSTEM); 98 mb_put_uint16le(mbp, SMB2_HDR_SIZE); /* Struct Size */ 99 mb_put_uint16le(mbp, creditcharge); 100 mb_put_uint32le(mbp, 0); /* Status */ 101 mb_put_uint16le(mbp, rqp->sr2_command); 102 mb_put_uint16le(mbp, creditrequest); 103 mb_put_uint32le(mbp, rqp->sr2_rqflags); 104 mb_put_uint32le(mbp, rqp->sr2_nextcmd); 105 mb_put_uint64le(mbp, rqp->sr2_messageid); 106 107 mb_put_uint32le(mbp, rqp->sr_pid); /* Process ID */ 108 mb_put_uint32le(mbp, rqp->sr2_rqtreeid); /* Tree ID */ 109 mb_put_uint64le(mbp, rqp->sr2_rqsessionid); /* Session ID */ 110 /* The MAC signature is filled in by smb2_vc_sign() */ 111 112 /* This will free the mblk from dupb. */ 113 mb_done(mbp); 114 } 115 116 int 117 smb2_rq_simple(struct smb_rq *rqp) 118 { 119 return (smb2_rq_simple_timed(rqp, smb2_timo_default)); 120 } 121 122 /* 123 * Simple request-reply exchange 124 */ 125 int 126 smb2_rq_simple_timed(struct smb_rq *rqp, int timeout) 127 { 128 int error; 129 130 rqp->sr_flags &= ~SMBR_RESTART; 131 rqp->sr_timo = timeout; /* in seconds */ 132 rqp->sr_state = SMBRQ_NOTSENT; 133 134 error = smb2_rq_enqueue(rqp); 135 if (error == 0) 136 error = smb2_rq_reply(rqp); 137 138 return (error); 139 } 140 141 142 static int 143 smb2_rq_enqueue(struct smb_rq *rqp) 144 { 145 struct smb_vc *vcp = rqp->sr_vc; 146 struct smb_share *ssp = rqp->sr_share; 147 int error = 0; 148 149 ASSERT((vcp->vc_flags & SMBV_SMB2) != 0); 150 151 /* 152 * Normal requests may initiate a reconnect, 153 * and/or wait for state changes to finish. 154 * Some requests set the NORECONNECT flag 155 * to avoid all that (i.e. tree discon) 156 */ 157 if (rqp->sr_flags & SMBR_NORECONNECT) { 158 if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { 159 SMBSDEBUG("bad vc_state=%d\n", vcp->vc_state); 160 return (ENOTCONN); 161 } 162 if (ssp != NULL && 163 ((ssp->ss_flags & SMBS_CONNECTED) == 0)) 164 return (ENOTCONN); 165 goto ok_out; 166 } 167 168 /* 169 * If we're not connected, initiate a reconnect 170 * and/or wait for an existing one to finish. 171 */ 172 if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { 173 error = smb_iod_reconnect(vcp); 174 if (error != 0) 175 return (error); 176 } 177 178 /* 179 * If this request has a "share" object 180 * that needs a tree connect, do it now. 181 */ 182 if (ssp != NULL && (ssp->ss_flags & SMBS_CONNECTED) == 0) { 183 error = smb_share_tcon(ssp, rqp->sr_cred); 184 if (error) 185 return (error); 186 } 187 188 /* 189 * We now know what UID + TID to use. 190 * Store them in the request. 191 */ 192 ok_out: 193 rqp->sr2_rqsessionid = vcp->vc2_session_id; 194 rqp->sr2_rqtreeid = ssp ? ssp->ss2_tree_id : SMB2_TID_UNKNOWN; 195 error = smb2_iod_addrq(rqp); 196 197 return (error); 198 } 199 200 /* 201 * Used by the IOD thread during connection setup, 202 * and for smb2_echo after network timeouts. Note that 203 * unlike smb2_rq_simple, callers must check sr_error. 204 */ 205 int 206 smb2_rq_internal(struct smb_rq *rqp, int timeout) 207 { 208 struct smb_vc *vcp = rqp->sr_vc; 209 int error; 210 211 ASSERT((vcp->vc_flags & SMBV_SMB2) != 0); 212 213 rqp->sr_flags &= ~SMBR_RESTART; 214 rqp->sr_timo = timeout; /* in seconds */ 215 rqp->sr_state = SMBRQ_NOTSENT; 216 217 /* 218 * In-line smb2_rq_enqueue(rqp) here, as we don't want it 219 * trying to reconnect etc. for an internal request. 220 */ 221 rqp->sr2_rqsessionid = vcp->vc2_session_id; 222 rqp->sr2_rqtreeid = SMB2_TID_UNKNOWN; 223 rqp->sr_flags |= SMBR_INTERNAL; 224 error = smb2_iod_addrq(rqp); 225 if (error != 0) 226 return (error); 227 228 /* 229 * In-line a variant of smb2_rq_reply(rqp) here as we may 230 * need to do custom parsing for SMB1-to-SMB2 negotiate. 231 */ 232 if (rqp->sr_timo == SMBNOREPLYWAIT) { 233 smb_iod_removerq(rqp); 234 return (0); 235 } 236 237 error = smb_iod_waitrq_int(rqp); 238 if (error) 239 return (error); 240 241 /* 242 * If the request was signed, validate the 243 * signature on the response. 244 */ 245 if (rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) { 246 error = smb2_rq_verify(rqp); 247 if (error) 248 return (error); 249 } 250 251 /* 252 * Parse the SMB2 header. 253 */ 254 error = smb2_rq_parsehdr(rqp); 255 256 /* 257 * Skip the error translation smb2_rq_reply does. 258 * Callers of this expect "raw" NT status. 259 */ 260 261 return (error); 262 } 263 264 /* 265 * Wait for a reply to this request, then parse it. 266 */ 267 static int 268 smb2_rq_reply(struct smb_rq *rqp) 269 { 270 int error; 271 272 if (rqp->sr_timo == SMBNOREPLYWAIT) { 273 smb_iod_removerq(rqp); 274 return (0); 275 } 276 277 error = smb_iod_waitrq(rqp); 278 if (error) 279 return (error); 280 281 /* 282 * If the request was signed, validate the 283 * signature on the response. 284 */ 285 if (rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) { 286 error = smb2_rq_verify(rqp); 287 if (error) 288 return (error); 289 } 290 291 /* 292 * Parse the SMB2 header 293 */ 294 error = smb2_rq_parsehdr(rqp); 295 if (error != 0) 296 return (error); 297 298 if (rqp->sr_error != 0) { 299 error = smb_maperr32(rqp->sr_error); 300 } 301 302 if (error != 0) { 303 /* 304 * Do a special check for STATUS_BUFFER_OVERFLOW; 305 * it's not an error. 306 */ 307 if (rqp->sr_error == NT_STATUS_BUFFER_OVERFLOW) { 308 /* 309 * Don't report it as an error to our caller; 310 * they can look at rqp->sr_error if they 311 * need to know whether we got a 312 * STATUS_BUFFER_OVERFLOW. 313 */ 314 rqp->sr_flags |= SMBR_MOREDATA; 315 error = 0; 316 } 317 } else { 318 rqp->sr_flags &= ~SMBR_MOREDATA; 319 } 320 321 return (error); 322 } 323 324 /* 325 * Parse the SMB 2+ Header 326 */ 327 int 328 smb2_rq_parsehdr(struct smb_rq *rqp) 329 { 330 struct mdchain *mdp = &rqp->sr_rp; 331 uint32_t protocol_id; 332 uint16_t length = 0; 333 uint16_t credit_charge; 334 uint16_t command; 335 uint64_t message_id = 0; 336 int error = 0; 337 338 /* Get Protocol ID */ 339 md_get_uint32le(mdp, &protocol_id); 340 341 /* Get/Check structure size is 64 */ 342 md_get_uint16le(mdp, &length); 343 if (length != 64) 344 return (EBADRPC); 345 346 md_get_uint16le(mdp, &credit_charge); 347 md_get_uint32le(mdp, &rqp->sr_error); 348 md_get_uint16le(mdp, &command); 349 md_get_uint16le(mdp, &rqp->sr2_rspcreditsgranted); 350 md_get_uint32le(mdp, &rqp->sr2_rspflags); 351 md_get_uint32le(mdp, &rqp->sr2_rspnextcmd); 352 md_get_uint64le(mdp, &message_id); 353 354 if ((rqp->sr2_rspflags & SMB2_FLAGS_ASYNC_COMMAND) == 0) { 355 /* 356 * Sync Header 357 */ 358 359 /* Get Process ID */ 360 md_get_uint32le(mdp, &rqp->sr2_rsppid); 361 362 /* Get Tree ID */ 363 md_get_uint32le(mdp, &rqp->sr2_rsptreeid); 364 } else { 365 /* 366 * Async Header 367 */ 368 369 /* Get Async ID */ 370 md_get_uint64le(mdp, &rqp->sr2_rspasyncid); 371 } 372 373 /* Get Session ID */ 374 error = md_get_uint64le(mdp, &rqp->sr2_rspsessionid); 375 if (error) 376 return (error); 377 378 /* Skip MAC Signature */ 379 error = md_get_mem(mdp, NULL, 16, MB_MSYSTEM); 380 381 return (error); 382 } 383