void SMBRemountServer(const void *inputBuffer, size_t inputBufferLen) { fsid_t fsid = *(fsid_t *)inputBuffer; if (inputBufferLen == sizeof(fsid)) { int error = smb_remount_with_fsid(fsid); if (error) { SMBLogInfo("%s: error = %d inputBuffer = %p or inputBufferLen = %zu", ASL_LEVEL_DEBUG, __FUNCTION__, error, inputBuffer, inputBufferLen); } } else { SMBLogInfo("%s: Bad inputBuffer = %p or inputBufferLen = %zu", ASL_LEVEL_DEBUG, __FUNCTION__, inputBuffer, inputBufferLen); } }
rpc_mempool::~rpc_mempool() { #if MEMPOOL_DEBUG SMBLogInfo("destroying rpc_mempool at %p", ASL_LEVEL_DEBUG, this); #endif std::for_each(ptrs.begin(), ptrs.end(), free_function()); }
void operator()(void * ptr) const { #if MEMPOOL_DEBUG SMBLogInfo("rpc_mempool(%llu): freeing ptr %p", ASL_LEVEL_DEBUG (unsigned long long)pthread_self(), ptr); #endif std::free(ptr); }
rpc_mempool::rpc_mempool() : ptrs(10) { #if MEMPOOL_DEBUG SMBLogInfo("constructing rpc_mempool at %p", ASL_LEVEL_DEBUG, this); #endif ptrs.resize(0); }
rpc_binding::rpc_binding(const char * string_binding) { error_status_t status; rpc_binding_from_string_binding((idl_char *)string_binding, &binding_handle, &status); if (status != rpc_s_ok) { SMBLogInfo("rpc_binding_from_string_binding failed on <%s> status %#08x", ASL_LEVEL_ERR, string_binding == NULL ? "nullstr" : string_binding, status); binding_handle = NULL; } }
void * rpc_mempool::alloc( size_t sz) { void * ptr = platform::allocate(NULL, sz); if (ptr) { ptrs.push_back(ptr); } #if MEMPOOL_DEBUG SMBLogInfo("rpc_mempool(%llu): allocated ptr %p for %u bytes", ASL_LEVEL_DEBUG, (unsigned long long)pthread_self(), ptr, (unsigned)sz); #endif return ptr; }
error_status_t rpc_exception_status( dcethread_exc * exc) { int status; status = dcethread_exc_getstatus(exc); if (status == -1) { SMBLogInfo("unexpected RPC exception: kind=%#x address=%p %s", ASL_LEVEL_DEBUG, exc->kind, exc->match.address, exc->name); return rpc_m_unexpected_exc; } return status; }
void rpc_mempool::free( void * ptr) { ptr_list_type::iterator which = std::find(ptrs.begin(), ptrs.end(), ptr); assert(which != ptrs.end()); ptrs.erase(which); #if MEMPOOL_DEBUG SMBLogInfo("rpc_mempool(%llu): freed ptr %p", ASL_LEVEL_DEBUG, (unsigned long long)pthread_self(), ptr); #endif free_function f; f(ptr); }
// Return an appropriate binding for the given ServerName. rpc_binding make_rpc_binding( const char * ServerName, const char * EndPoint) { char * binding_string = NULL; char * endpoint_string = NULL; uint32_t status; if (!EndPoint) { return rpc_binding(); } if (ServerName) { /* add in the "\pipe\" to the endpoint */ asprintf(&endpoint_string, "\\pipe\\%s]", EndPoint); rpc_string_binding_compose(NULL, (idl_char *) "ncacn_np", (idl_char *) ServerName, (idl_char *) endpoint_string, NULL, (idl_char **) &binding_string, &status); if (status != 0) { SMBLogInfo("rpc_string_binding_compose failed on <%s>:<%s> status %#08x", ASL_LEVEL_ERR, ServerName == NULL ? "nullstr" : ServerName, EndPoint == NULL ? "nullstr" : EndPoint, status); /* fallback to the old way instead */ asprintf(&binding_string, "ncacn_np:%s[%s]", ServerName, endpoint_string); } if (endpoint_string != NULL) { free(endpoint_string); } } else { rpc_string_binding_compose(NULL, (idl_char *) "ncalrpc", NULL, (idl_char *) EndPoint, NULL, (idl_char **) &binding_string, &status); if (status != 0) { SMBLogInfo("rpc_string_binding_compose failed on <%s> status %#08x", ASL_LEVEL_ERR, EndPoint == NULL ? "nullstr" : EndPoint, status); /* fallback to the old way instead */ asprintf(&binding_string, "ncalrpc:[%s]", EndPoint); } } if (!binding_string) { platform::invoke_new_handler(); } rpc_binding binding(binding_string); if (status == 0) { /* rpc_string_binding_compose worked */ if (binding_string != NULL) { rpc_string_free((idl_char **) &binding_string, &status); if (status != 0) { SMBLogInfo("rpc_string_free failed on <%s> status %#08x", ASL_LEVEL_ERR, binding_string == NULL ? "nullstr" : binding_string, status); } } } else { /* must have used asprintf */ if (binding_string != NULL) { free(binding_string); } } return binding; }
int smb_netshareenum(SMBHANDLE inConnection, CFDictionaryRef *outDict, int DiskAndPrintSharesOnly) { int error = 0; NTSTATUS status; SMBServerPropertiesV1 properties; CFMutableDictionaryRef shareDict = NULL; uint32_t ii; CFStringRef shareName, comments; u_int16_t shareType; struct statfs *fs = NULL; int fs_cnt = 0; fs = smb_getfsstat(&fs_cnt); shareDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (shareDict == NULL) { error = ENOMEM; goto done; } status = SMBGetServerProperties(inConnection, &properties, kPropertiesVersion, sizeof(properties)); if (!NT_SUCCESS(status)) { /* Should never happen */ error = errno; goto done; } /* Only use RPC if the server supports DCE/RPC and UNICODE */ if (properties.capabilities & SMB_CAP_RPC_REMOTE_APIS) { PSHARE_ENUM_STRUCT InfoStruct = NULL; NET_API_STATUS api_status; /* Try getting a list of shares with the SRVSVC RPC service. */ api_status = NetShareEnum(properties.serverName, 1, &InfoStruct); if (api_status == 0) { for (ii = 0; ii < InfoStruct->ShareInfo.Level1->EntriesRead; ii++) { shareType = OSSwapLittleToHostInt16(InfoStruct->ShareInfo.Level1->Buffer[ii].shi1_type); /* They only want the disk and printer shares */ if (DiskAndPrintSharesOnly && (shareType != SMB_ST_DISK) && (shareType != SMB_ST_PRINTER)) continue; shareName = convertToStringRef(InfoStruct->ShareInfo.Level1->Buffer[ii].shi1_netname, 1024, TRUE); if (shareName == NULL) { continue; } if (InfoStruct->ShareInfo.Level1->Buffer[ii].shi1_remark) { comments = convertToStringRef(InfoStruct->ShareInfo.Level1->Buffer[ii].shi1_remark, 1024, TRUE); } else { comments = NULL; } addShareToDictionary(inConnection, shareDict, shareName, comments, shareType, fs, fs_cnt); CFRelease(shareName); if (comments) { CFRelease(comments); } } NetApiBufferFree(InfoStruct); goto done; } SMBLogInfo("Looking up shares with RPC failed api_status = %d", ASL_LEVEL_DEBUG, api_status); } /* * OK, that didn't work - either they don't support RPC or we * got an error in either case try RAP if enabled (lanman_on pref is set). */ if (properties.internalFlags & kLanmanOn) { void *rBuffer = NULL; unsigned char *endBuffer; uint32_t rBufferSize = 0; struct smb_share_info_1 *shareInfo1; uint32_t entriesRead = 0; SMBLogInfo("Looking up shares RAP", ASL_LEVEL_DEBUG); /* Try getting a list of shares with the RAP protocol. */ error = RapNetShareEnum(inConnection, 1, &rBuffer, &rBufferSize, &entriesRead, NULL); if (error) { SMBLogInfo("Looking up shares with RAP failed, error=%d", ASL_LEVEL_DEBUG, error); goto done; } endBuffer = (unsigned char *)rBuffer + rBufferSize; for (shareInfo1 = (struct smb_share_info_1 *)rBuffer, ii = 0; (ii < entriesRead) && (((unsigned char *)shareInfo1 + sizeof(smb_share_info_1)) <= endBuffer); ii++, shareInfo1++) { shareInfo1->shi1_pad = 0; /* Just to be safe */ /* Note we need to swap this item */ shareType = OSSwapLittleToHostInt16(shareInfo1->shi1_type); shareName = convertToStringRef(shareInfo1->shi1_netname, sizeof(shareInfo1->shi1_netname), FALSE); if (shareName == NULL) { continue; } /* Assume we have no comments for this entry */ comments = NULL; /* * The shi1_remark gets swapped in the rap processing, someday we just * take another look at this an make it work the same for all values. */ if ((shareInfo1->shi1_remark != 0) && (shareInfo1->shi1_remark < rBufferSize)) { unsigned char *remarks = (unsigned char *)rBuffer + shareInfo1->shi1_remark; /* * Make sure the comments don't start pass the end of the buffer * and we have a comment. */ if ((remarks < endBuffer) && *remarks) { size_t maxlen = endBuffer - remarks; /* Now make sure the comment is a null terminate string */ maxlen = smb_strnlen((const char *)remarks, maxlen); remarks[maxlen] = 0; comments = convertToStringRef(remarks, maxlen, FALSE); } } addShareToDictionary(inConnection, shareDict, shareName, comments, shareType, fs, fs_cnt); CFRelease(shareName); if (comments) { CFRelease(comments); } } RapNetApiBufferFree(rBuffer); } done: if (fs) { free(fs); } if (error) { *outDict = NULL; if (shareDict) { CFRelease(shareDict); } } else { *outDict = shareDict; } return error; }
static void addShareToDictionary(SMBHANDLE inConnection, CFMutableDictionaryRef shareDict, CFStringRef shareName, CFStringRef comments, u_int16_t shareType, struct statfs *fs, int fs_cnt) { CFMutableDictionaryRef currDict = NULL; CFRange foundSlash; CFRange foundPercentSign; CFStringRef tempShareName1 = NULL; CFStringRef tempShareName2 = NULL; if (shareName == NULL) { return; } currDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (currDict == NULL) { /* Log error here, but keep going */ SMBLogInfo("addShareToDictionary: Couldn't create the dictionary!", ASL_LEVEL_DEBUG); return; } if (CFStringHasSuffix(shareName, CFSTR("$"))) { CFDictionarySetValue (currDict, kNetFSIsHiddenKey, kCFBooleanTrue); } if (comments) { CFDictionarySetValue (currDict, kNetCommentStrKey, comments); } switch (shareType) { case SMB_ST_DISK: CFDictionarySetValue (currDict, kNetShareTypeStrKey, CFSTR("Disk")); /* Now check to see if this share is already mounted */ if (fs) { /* We only care if its already mounted ignore any other errors for now */ if (SMBCheckForAlreadyMountedShare(inConnection, shareName, currDict, fs, fs_cnt) == EEXIST) { CFDictionarySetValue (currDict, kNetFSAlreadyMountedKey, kCFBooleanTrue); } else { CFDictionarySetValue (currDict, kNetFSAlreadyMountedKey, kCFBooleanFalse); } } break; case SMB_ST_PRINTER: CFDictionarySetValue (currDict, kNetShareTypeStrKey, CFSTR("Printer")); CFDictionarySetValue (currDict, kNetFSPrinterShareKey, kCFBooleanTrue); CFDictionarySetValue (currDict, kNetFSAlreadyMountedKey, kCFBooleanFalse); break; case SMB_ST_PIPE: CFDictionarySetValue (currDict, kNetShareTypeStrKey, CFSTR("Pipe")); CFDictionarySetValue (currDict, kNetFSAlreadyMountedKey, kCFBooleanFalse); break; case SMB_ST_COMM: CFDictionarySetValue (currDict, kNetShareTypeStrKey, CFSTR("Comm")); CFDictionarySetValue (currDict, kNetFSAlreadyMountedKey, kCFBooleanFalse); break; default: CFDictionarySetValue (currDict, kNetShareTypeStrKey, CFSTR("Unknown")); CFDictionarySetValue (currDict, kNetFSAlreadyMountedKey, kCFBooleanFalse); break; } CFDictionarySetValue (currDict, kNetFSHasPasswordKey, kCFBooleanFalse); /* Check for a '/' or '%' in the share name */ foundSlash = CFStringFind (shareName, CFSTR("/"), 0); foundPercentSign = CFStringFind (shareName, CFSTR("%"), 0); if ( (foundSlash.location != kCFNotFound) || (foundPercentSign.location != kCFNotFound) ) { /* found a '/' or '%' in the name, so set a disply name to be used */ CFDictionarySetValue (currDict, kNetFSDisplayNameKey, shareName); /* escape the vol name to get '/' converted to %2f and '%' to %25 */ tempShareName1 = CFURLCreateStringByAddingPercentEscapes(NULL, shareName, NULL, CFSTR("/%"), kCFStringEncodingUTF8); /* re-escape it leaving the '/' as %2f and '%' as %25 */ tempShareName2 = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL, tempShareName1, CFSTR("/%"), kCFStringEncodingUTF8); CFDictionarySetValue (shareDict, tempShareName2, currDict); CFRelease (tempShareName1); CFRelease (tempShareName2); } else { CFDictionarySetValue (shareDict, shareName, currDict); } CFRelease (currDict); }
CFStringRef SMBCreateNetBIOSName(CFStringRef proposedName) { CFMutableStringRef composedName; CFStringEncoding codepage; CFIndex nconverted = 0; CFIndex nused = 0; uint8_t name_buffer[NetBIOS_NAME_LEN]; if (proposedName == NULL) { return NULL; } codepage = getPrefsCodePage(); composedName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, proposedName); if (!composedName) { return NULL; } CFStringTrimWhitespace(composedName); CFStringUppercase(composedName, CFLocaleGetSystem()); nconverted = CFStringGetBytes(composedName, CFRangeMake(0, MIN((CFIndex)sizeof(name_buffer), CFStringGetLength(composedName))), codepage, 0 /* loss byte */, false /* no BOM */, name_buffer, sizeof(name_buffer), &nused); /* We expect the conversion above to always succeed, given that we * tried to remove anything that might not convert to a code page. */ if (nconverted == 0) { char buf[256]; buf[0] = '\0'; CFStringGetCString(composedName, buf, sizeof(buf), kCFStringEncodingUTF8); SMBLogInfo("failed to compose a NetBIOS name string from '%s'", ASL_LEVEL_DEBUG, buf); CFRelease(composedName); return NULL; } CFRelease(composedName); /* Null terminate for the benefit of CFStringCreate. Be careful to be * no more that 15 bytes, since the last byte is reserved for the name * type. */ name_buffer[MIN(nused, (CFIndex)sizeof(name_buffer) - 1)] = '\0'; composedName = CFStringCreateMutable(kCFAllocatorDefault, NetBIOS_NAME_LEN); if (composedName == NULL) { return NULL; } CFStringAppendCString(composedName, (const char *)name_buffer, codepage); return composedName; }
NET_API_STATUS NetShareGetInfo( const char * ServerName, const char * NetName, uint32_t Level, PSHARE_INFO * ShareInfo) { WCHAR * serverName = SMBConvertFromUTF8ToUTF16(ServerName, 1024, 0); WCHAR * netName = SMBConvertFromUTF8ToUTF16(NetName, 1024, 0); if (!serverName || !netName || !ShareInfo) { if (serverName) free(serverName); if (netName) free(netName); return ERROR_INVALID_PARAMETER; } rpc_binding binding = make_rpc_binding(ServerName, "srvsvc"); if (binding.get() == NULL) { SMBLogInfo("make_rpc_binding failed", ASL_LEVEL_DEBUG); if (serverName) { free(serverName); } if (netName) { free(netName); } return ERROR_INVALID_PARAMETER; } rpc_ss_allocator_t allocator; NET_API_STATUS api_status = NERR_Success; error_status_t rpc_status = rpc_s_ok; memset(&allocator, 0, sizeof(allocator)); std::pair<rpc_mempool *, SHARE_INFO *> result( allocate_rpc_mempool<SHARE_INFO>()); allocator.p_allocate = share_memalloc; allocator.p_free = share_memfree; allocator.p_context = (idl_void_p_t)result.first; rpc_ss_swap_client_alloc_free_ex(&allocator, &allocator); DCETHREAD_TRY api_status = NetrShareGetInfo( binding.get(), const_cast<WCHAR *>(serverName), const_cast<WCHAR *>(netName), Level, result.second, &rpc_status); DCETHREAD_CATCH_ALL(exc) /* * Unmarshalling a response with an unknown level will throw a * rpc_x_invalid_tag exception since the unknown level is not defined as * a union discriminator. */ rpc_status = rpc_exception_status(exc); DCETHREAD_ENDTRY free(serverName); free(netName); rpc_ss_swap_client_alloc_free_ex(&allocator, &allocator); if (rpc_status != rpc_s_ok) { SMBLogInfo("RPC to srvsrvc gave error %#08x", ASL_LEVEL_ERR, rpc_status); NetApiBufferFree(result.second); return RPC_S_PROTOCOL_ERROR; } if (api_status == NERR_Success) { *ShareInfo = result.second; } else { NetApiBufferFree(result.second); *ShareInfo = NULL; } return api_status; }
NET_API_STATUS NetShareEnum( const char * ServerName, uint32_t Level, PSHARE_ENUM_STRUCT * InfoStruct) { WCHAR * serverName = SMBConvertFromUTF8ToUTF16(ServerName, 1024, 0); if (!serverName || !InfoStruct) { if (serverName) free(serverName); return ERROR_INVALID_PARAMETER; } rpc_binding binding = make_rpc_binding(ServerName, "srvsvc"); if (binding.get() == NULL) { SMBLogInfo("make_rpc_binding failed", ASL_LEVEL_DEBUG); if (serverName) { free(serverName); } return ERROR_INVALID_PARAMETER; } rpc_ss_allocator_t allocator; NET_API_STATUS api_status = NERR_Success; error_status_t rpc_status = rpc_s_ok; memset(&allocator, 0, sizeof(allocator)); std::pair<rpc_mempool *, SHARE_ENUM_STRUCT *> result( allocate_rpc_mempool<SHARE_ENUM_STRUCT>()); DWORD entries = 0; DWORD resume = 0; allocator.p_allocate = share_memalloc; allocator.p_free = share_memfree; allocator.p_context = (idl_void_p_t)result.first; rpc_ss_swap_client_alloc_free_ex(&allocator, &allocator); result.second->Level = Level; /* * Windows requires a valid pointer for the ShareInfo union. It doesn't matter * which container type we choose here, since they all have the same binary * layout. */ result.second->ShareInfo.Level0 = (SHARE_INFO_0_CONTAINER *)result.first->alloc( sizeof(SHARE_INFO_0_CONTAINER)); result.second->ShareInfo.Level0->EntriesRead = 0; result.second->ShareInfo.Level0->Buffer = NULL; DCETHREAD_TRY api_status = NetrShareEnum( binding.get(), const_cast<WCHAR *>(serverName), result.second, 0xffffffff, &entries, &resume, &rpc_status); DCETHREAD_CATCH_ALL(exc) rpc_status = rpc_exception_status(exc); DCETHREAD_ENDTRY rpc_ss_swap_client_alloc_free_ex(&allocator, &allocator); free(serverName); if (rpc_status != rpc_s_ok) { SMBLogInfo("RPC to srvsrvc gave error %#08x", ASL_LEVEL_ERR, rpc_status); NetApiBufferFree(result.second); return RPC_S_PROTOCOL_ERROR; } if (api_status == NERR_Success) { *InfoStruct = result.second; } else { NetApiBufferFree(result.second); *InfoStruct = NULL; } return api_status; }