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