Beispiel #1
0
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);
    }
}
Beispiel #2
0
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());
}
Beispiel #3
0
    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);
    }
Beispiel #4
0
rpc_mempool::rpc_mempool()
: ptrs(10)
{
#if MEMPOOL_DEBUG
    SMBLogInfo("constructing rpc_mempool at %p", ASL_LEVEL_DEBUG, this);
#endif
    ptrs.resize(0);
}
Beispiel #5
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;
    }
}
Beispiel #6
0
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;
}
Beispiel #7
0
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;
}
Beispiel #8
0
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);
}
Beispiel #9
0
// 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;
}
Beispiel #10
0
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;
}
Beispiel #11
0
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);
}
Beispiel #12
0
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;
}
Beispiel #13
0
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;
}
Beispiel #14
0
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;
}