/* * SMBNetFsGetServerInfo */ int32_t SMBNetFsGetServerInfo(CFURLRef url, SMBHANDLE inConnection, CFDictionaryRef openOptions, CFDictionaryRef *serverParms) { int error = 0; void *hContext = NULL; SMBServerContext(inConnection, &hContext); error = smb_get_server_info(hContext, url, openOptions, serverParms); return error; }
static int GetRootShareConnection(struct smb_ctx *ctx, const char *url, uint32_t authFlags, const char * clientPrincipal, uint32_t clientNameType, uint32_t maxTimer) { CFDictionaryRef serverParams = NULL; CFDictionaryRef sessionInfo = NULL; CFMutableDictionaryRef openOptions; int error = 0; time_t start_time = time(NULL); openOptions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (!openOptions) { smb_log_info("%s: Couldn't create open options for %s", ASL_LEVEL_ERR, __FUNCTION__, url); error = ENOMEM; goto done; } #ifdef SMBDEBUG_REMOUNT /* This is only needed for testing and should be remove once we have autofs hooked up */ CFDictionarySetValue(openOptions, kNetFSForceNewSessionKey, kCFBooleanTrue); #endif // SMBDEBUG_REMOUNT /* Never touch the user home directory */ CFDictionarySetValue(openOptions, kNetFSNoUserPreferencesKey, kCFBooleanTrue); /* * If they have a loopback in the referral we always allow it, no way for * us to decided what is correct at this point. */ CFDictionarySetValue(openOptions, kNetFSAllowLoopbackKey, kCFBooleanTrue); /* * Do a get server info call first to determine the if the server supports * the security we need. Also needed it to make sure we have the correct * server principal name. */ while (difftime(time(NULL), start_time) < maxTimer ) { error = smb_get_server_info(ctx, NULL, openOptions, &serverParams); if (!error) { break; } smb_log_info("%s: get server info failed %d, sleeping one second, have %d seconds left.", ASL_LEVEL_DEBUG, __FUNCTION__, error, maxTimer - (int)difftime(time(NULL), start_time)); sleep(1); /* Wait one second before trying again */ } if (error) { smb_log_info("%s: get server info failed from %s with %d", ASL_LEVEL_ERR, __FUNCTION__, url, error); goto done; } /* * We should check the server params and make sure this server supports * the same auth method as the old server. Doesn't really make any difference * we should fail in the open if they don't support the correct auth. */ /* * Set up the authorization using the same auth method that was use in the * original mount. */ if (authFlags & (SMBV_GUEST_ACCESS | SMBV_SFS_ACCESS | SMBV_PRIV_GUEST_ACCESS)) { CFDictionarySetValue( openOptions, kNetFSUseGuestKey, kCFBooleanTrue); } else { CFMutableDictionaryRef authInfoDict; authInfoDict = CreateAuthDictionary(ctx, authFlags, clientPrincipal, clientNameType); if (!authInfoDict) { smb_log_info("%s: Creating authorization dictionary failed for %s", ASL_LEVEL_ERR, __FUNCTION__, url); error = ENOMEM; goto done; } CFDictionarySetValue( openOptions, kNetFSUseAuthenticationInfoKey, kCFBooleanTrue); CFDictionarySetValue(openOptions, kNetFSAuthenticationInfoKey, authInfoDict); CFRelease(authInfoDict); } error = smb_open_session(ctx, NULL, openOptions, &sessionInfo); if (error) { smb_log_info("%s: open session failed from url %s with %d", ASL_LEVEL_ERR, __FUNCTION__, url, error); goto done; } error = smb_share_connect(ctx); if (error) { smb_log_info("%s: share connect failed from url %s with %d", ASL_LEVEL_ERR, __FUNCTION__, url, error); goto done; } done: if (sessionInfo) { CFRelease(sessionInfo); } if (serverParams) { CFRelease(serverParams); } if (openOptions) { CFRelease(openOptions); } return error; }
NTSTATUS SMBOpenServerEx( const char * targetServer, SMBHANDLE * outConnection, uint64_t options) { NTSTATUS status; int err; void * hContext; CFMutableDictionaryRef netfsOptions = NULL; CFDictionaryRef ServerParams = NULL; *outConnection = NULL; status = SMBLibraryInit(); if (!NT_SUCCESS(status)) { goto done; } netfsOptions = SMBCreateDefaultOptions(options); if (netfsOptions == NULL) { status = STATUS_NO_MEMORY; goto done; } status = SMBAllocateServer(outConnection, targetServer); if (!NT_SUCCESS(status)) { goto done; } status = SMBServerContext(*outConnection, &hContext); if (!NT_SUCCESS(status)) { goto done; } err = smb_get_server_info(hContext, NULL, netfsOptions, &ServerParams); if (err) { /* XXX map real NTSTATUS code */ status = STATUS_CONNECTION_REFUSED; errno = err; goto done; } /* * They didn't set the force new session option and we have a shared session, * then we are done. We have a connection and we are authenticated. */ if (!(options & kSMBOptionForceNewSession) && (((struct smb_ctx *)hContext)->ct_vc_shared)) { goto authDone; } /* * They have guest as the username in the url, then they want us to * force guest access. */ if (((struct smb_ctx *)hContext)->ct_setup.ioc_userflags & SMBV_GUEST_ACCESS) { options |= kSMBOptionUseGuestOnlyAuth; } /* Connect using Guest Access only */ if (options & kSMBOptionUseGuestOnlyAuth) { status = SMBServerConnect(*outConnection, NULL, netfsOptions, kSMBAuthTypeGuest); goto authDone; } /* Connect using Anonymous Access only */ if (options & kSMBOptionUseAnonymousOnlyAuth) { status = SMBServerConnect(*outConnection, NULL, netfsOptions, kSMBAuthTypeAnonymous); goto authDone; } /* Attempt an authenticated connect, could be kerberos or ntlm. */ status = SMBServerConnect(*outConnection, NULL, netfsOptions, kSMBAuthTypeAuthenticated); if (NT_SUCCESS(status)) { goto authDone; } /* See if we need to prompt for a password */ if (SMBPasswordPrompt(*outConnection, options)) { /* Attempt an authenticated connect again , could be kerberos or ntlm. */ status = SMBServerConnect(*outConnection, NULL, netfsOptions, kSMBAuthTypeAuthenticated); if (NT_SUCCESS(status)) { goto authDone; } } /* Kerberos and NTLM failed, attempt Guest access if option set */ if (options & kSMBOptionAllowGuestAuth) { status = SMBServerConnect(*outConnection, NULL, netfsOptions, kSMBAuthTypeGuest); if (NT_SUCCESS(status)) { goto authDone; } } /* Kerberos and NTLM failed, attempt Anonymous access if option set */ if (options & kSMBOptionAllowAnonymousAuth) { status = SMBServerConnect(*outConnection, NULL, netfsOptions, kSMBAuthTypeAnonymous); if (NT_SUCCESS(status)) { goto authDone; } } authDone: if (!NT_SUCCESS(status)) { goto done; } if (options & kSMBOptionSessionOnly) { goto done; } /* * If the target doesn't contain a share name, let's assume that the * caller means IPC$, unless a share name is required. */ if (!((struct smb_ctx *)hContext)->ct_origshare) { err = smb_ctx_setshare(hContext, "IPC$"); if (err) { if (err == ENAMETOOLONG) { status = STATUS_NAME_TOO_LONG; } else { status = STATUS_NO_MEMORY; } errno = err; goto done; } } /* OK, now we have a virtual circuit but no tree connection yet. */ err = smb_share_connect((*outConnection)->context); if (err) { status = STATUS_BAD_NETWORK_NAME; errno = err; goto done; } status = STATUS_SUCCESS; done: if (netfsOptions) { CFRelease(netfsOptions); } if (ServerParams) { CFRelease(ServerParams); } if ((!NT_SUCCESS(status)) && *outConnection) { SMBReleaseServer(*outConnection); *outConnection = NULL; } return status; }