1/* 2 * Copyright (c) 2011 - 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/* 25 * Fun with FIDs 26 * (1) SMB2 uses two uint64_t of fid_persistent and fid_volatile 27 * (2) SMB1 uses a single uint16_t for the FID 28 * (3) User space functions use a single uint64_t for the FID 29 * 30 * Solution: All functions will pass around a single uint64_t FID. 31 * (1) SMB2 will map the uint64_t FID to the two uint64_t SMB2 FID. This will 32 * done at the very last layer when the SMB2 packets are being built and 33 * in the code that parses out the reply packet. 34 * (2) SMB1 will just saves its uint16_t FID inside the uint64_t and will just 35 * assign it or read it to/from a uint16_t temp value. 36 * (3) User space functions will remain unchanged and continue to use a 37 * uint64_t regardless of whether they are using SMB1 or SMB2. This will 38 * also make reconnect "invisible" to the user level since a reconnect will 39 * just update the mapping table. 40 * 41 */ 42 43//#include <sys/msfscc.h> 44#include <sys/smb_apple.h> 45#include <sys/param.h> 46#include <sys/kauth.h> 47 48#include <netsmb/smb.h> 49#include <netsmb/smb_2.h> 50#include <netsmb/smb_packets_2.h> 51#include <netsmb/smb_rq.h> 52#include <netsmb/smb_rq_2.h> 53#include <netsmb/smb_conn.h> 54#include <netsmb/smb_conn_2.h> 55#include <netsmb/smb_tran.h> 56#include <netsmb/smb_gss.h> 57#include <netsmb/smb_fid.h> 58#include <smbfs/smbfs_subr.h> 59#include <smbfs/smbfs_subr_2.h> 60#include <smbfs/smbfs_node.h> 61#include <netsmb/smb_converter.h> 62 63static void smb_fid_insert_new_node(struct smb_share *share, SMB_FID_NODE *node); 64static uint32_t smb_fid_one_at_a_time(uint8_t *key, uint32_t len); 65 66/* smb_fid_count_all() is used for Debugging */ 67uint64_t 68smb_fid_count_all(struct smb_share *share) 69{ 70 FID_HASH_TABLE_SLOT *slotPtr; 71 SMB_FID_NODE *node, *temp_node; 72 uint32_t table_index; 73 uint64_t count = 0; 74 75 if (share == NULL) { 76 SMBERROR("share is null\n"); 77 return (0); 78 } 79 80 smb_fid_table_lock(share); 81 82 for (table_index = 0; table_index < SMB_FID_TABLE_SIZE; table_index += 1) { 83 slotPtr = &share->ss_fid_table[table_index]; 84 if (slotPtr == NULL) { 85 continue; 86 } 87 88 LIST_FOREACH_SAFE(node, &slotPtr->fid_list, link, temp_node) { 89 count++; 90 } 91 } 92 93 smb_fid_table_unlock(share); 94 95 return count; 96} 97 98void 99smb_fid_delete_all(struct smb_share *share) 100{ 101 FID_HASH_TABLE_SLOT *slotPtr; 102 SMB_FID_NODE *node, *temp_node; 103 uint32_t table_index; 104 105 if (share == NULL) { 106 SMBERROR("share is null\n"); 107 return; 108 } 109 110 smb_fid_table_lock(share); 111 112 for (table_index = 0; table_index < SMB_FID_TABLE_SIZE; table_index += 1) { 113 slotPtr = &share->ss_fid_table[table_index]; 114 if (slotPtr == NULL) { 115 continue; 116 } 117 118 LIST_FOREACH_SAFE(node, &slotPtr->fid_list, link, temp_node) { 119 LIST_REMOVE(node, link); 120 SMB_FREE(node, M_TEMP); 121 } 122 } 123 124 smb_fid_table_unlock(share); 125} 126 127int 128smb_fid_get_kernel_fid(struct smb_share *share, SMBFID fid, int remove_fid, 129 SMB2FID *smb2_fid) 130{ 131 FID_HASH_TABLE_SLOT *slotPtr; 132 SMB_FID_NODE *node; 133 uint32_t table_index, iter; 134 uint32_t found_it = 0; 135 int error = EINVAL; 136 137 /* cant put it into smp because that is NULL for DCERPC calls to srvsvc */ 138 139 if (share == NULL) { 140 SMBERROR("share is null\n"); 141 return EINVAL; 142 }; 143 144 /* handle compound requests */ 145 if (fid == 0xffffffffffffffff) { 146 smb2_fid->fid_persistent = 0xffffffffffffffff; 147 smb2_fid->fid_volatile = 0xffffffffffffffff; 148 return (0); 149 } 150 151 smb_fid_table_lock(share); 152 153 /* calculate the slot */ 154 table_index = fid & SMB_FID_TABLE_MASK; 155 if (table_index >= SMB_FID_TABLE_SIZE) { 156 SMBERROR("Bad table_index: %u for fid %llx\n", table_index, fid); 157 goto exit; 158 }; 159 160 slotPtr = &share->ss_fid_table[table_index]; 161 if (slotPtr == NULL) { 162 SMBERROR("slotPtr is null for table_index %u, fid %llx\n", 163 table_index, fid); 164 goto exit; 165 }; 166 167 iter = 0; 168 LIST_FOREACH(node, &slotPtr->fid_list, link) { 169 if (node->fid == fid) { 170 *smb2_fid = node->smb2_fid; 171 found_it = 1; 172 173 if (remove_fid == 1) { 174 /*SMBERROR("remove smb2 fid %llx %llx -> fid %llx\n", 175 node->smb2_fid.fid_persistent, 176 node->smb2_fid.fid_volatile, 177 fid);*/ 178 LIST_REMOVE(node, link); 179 SMB_FREE(node, M_TEMP); 180 } 181 break; 182 } 183 iter++; 184 } 185 186 if (iter >= share->ss_fid_max_iter) { 187 share->ss_fid_max_iter = iter; 188 } 189 190 if (found_it == 1) { 191 /*SMBERROR("fid %llx -> smb2 fid %llx %llx\n", 192 fid, 193 smb2_fid->fid_persistent, 194 smb2_fid->fid_volatile);*/ 195 error = 0; 196 } 197 else { 198 SMBERROR("No smb2 fid found for fid %llx\n", fid); 199 } 200exit: 201 smb_fid_table_unlock(share); 202 return (error); 203} 204 205int 206smb_fid_get_user_fid(struct smb_share *share, SMB2FID smb2_fid, SMBFID *ret_fid) 207{ 208 uint64_t fid, val1, val2; 209 SMB_FID_NODE *node; 210 int error = EINVAL; 211 212 if (share == NULL) { 213 SMBERROR("share is null\n"); 214 return EINVAL; 215 }; 216 217 smb_fid_table_lock(share); 218 219 val1 = smb_fid_one_at_a_time((uint8_t *)&smb2_fid.fid_persistent, 220 sizeof(smb2_fid.fid_persistent)); 221 val2 = smb_fid_one_at_a_time((uint8_t *)&smb2_fid.fid_volatile, 222 sizeof(smb2_fid.fid_volatile)); 223 224 fid = (val1 << 32) | val2; 225 226 SMB_MALLOC(node, SMB_FID_NODE *, sizeof(SMB_FID_NODE), M_TEMP, M_WAITOK); 227 if (node != NULL) { 228 node->fid = fid; 229 node->smb2_fid = smb2_fid; 230 231 // insert our new node into the hash table 232 smb_fid_insert_new_node(share, node); 233 /*SMBERROR("insert smb2 fid %llx %llx -> fid %llx\n", 234 smb2_fid.fid_persistent, 235 smb2_fid.fid_volatile, 236 fid);*/ 237 *ret_fid = fid; 238 error = 0; 239 } 240 else { 241 SMBERROR("malloc failed\n"); 242 error = ENOMEM; 243 } 244 245 smb_fid_table_unlock(share); 246 return (error); 247} 248 249static void 250smb_fid_insert_new_node(struct smb_share *share, SMB_FID_NODE *node) 251{ 252 FID_HASH_TABLE_SLOT *slotPtr; 253 uint32_t table_index; 254 255 // calculate the slot 256 table_index = node->fid & SMB_FID_TABLE_MASK; 257 DBG_ASSERT(table_index < SMB_FID_TABLE_SIZE); 258 259 slotPtr = &share->ss_fid_table[table_index]; 260 261 if (LIST_EMPTY(&slotPtr->fid_list)) { 262 } 263 else { 264 share->ss_fid_collisions++; 265 } 266 LIST_INSERT_HEAD(&slotPtr->fid_list, node, link); 267 share->ss_fid_inserted++; 268} 269 270/* A quick little hash function 271 * Written by Bob Jenkins, and put in the public domain 272 * See http://burtleburtle.net/bob/hash/doobs.html 273 */ 274static uint32_t 275smb_fid_one_at_a_time(uint8_t *key, uint32_t len) 276{ 277 uint32_t hash, i; 278 279 for (hash = 0, i = 0; i < len; ++i) 280 { 281 hash += key[i]; 282 hash += (hash << 10); 283 hash ^= (hash >> 6); 284 } 285 hash += (hash << 3); 286 hash ^= (hash >> 11); 287 hash += (hash << 15); 288 return (hash); 289} 290 291 292