DWORD UmnSrvUpdateADGroupMember( PLW_EVENTLOG_CONNECTION pEventlog, HANDLE hReg, HKEY hGroups, long long PreviousRun, long long Now, PLSA_SECURITY_OBJECT pGroup, PCSTR pMember ) { DWORD dwError = 0; HKEY hKey = NULL; HKEY hMembers = NULL; DWORD dwNow = Now; PSTR pEncodedMember = NULL; PSTR pKeyName = NULL; PSTR pEncodedGroup = NULL; PSTR pMembersKeyName = NULL; dwError = LwURLEncodeString( pMember, &pEncodedMember); BAIL_ON_UMN_ERROR(dwError); dwError = LwURLEncodeString( pGroup->groupInfo.pszUnixName, &pEncodedGroup); BAIL_ON_UMN_ERROR(dwError); dwError = LwAllocateStringPrintf( &pKeyName, "%s\\Members\\%s", pEncodedGroup, pEncodedMember); BAIL_ON_UMN_ERROR(dwError); dwError = RegOpenKeyExA( hReg, hGroups, pKeyName, 0, KEY_ALL_ACCESS, &hKey); if (dwError == LWREG_ERROR_NO_SUCH_KEY_OR_VALUE) { UMN_LOG_INFO("Adding user member '%s' to group '%s' (gid %d)", pMember, pGroup->groupInfo.pszUnixName, pGroup->groupInfo.gid); dwError = LwAllocateStringPrintf( &pMembersKeyName, "%s\\Members", pEncodedGroup); BAIL_ON_UMN_ERROR(dwError); dwError = RegOpenKeyExA( hReg, hGroups, pMembersKeyName, 0, KEY_ALL_ACCESS, &hMembers); if (dwError == LWREG_ERROR_NO_SUCH_KEY_OR_VALUE) { // Previous run left registry in inconsistent state dwError = RegCreateKeyExA( hReg, hGroups, pMembersKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hMembers, NULL); BAIL_ON_UMN_ERROR(dwError); } BAIL_ON_UMN_ERROR(dwError); dwError = RegCreateKeyExA( hReg, hMembers, pEncodedMember, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL); BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvWriteGroupMemberEvent( pEventlog, Now, "AD Groups", PreviousRun, TRUE, //Add member FALSE, //Not gid change pMember, pGroup->groupInfo.gid, pGroup->groupInfo.pszUnixName); BAIL_ON_UMN_ERROR(dwError); } dwError = RegSetValueExA( hReg, hKey, "LastUpdated", 0, REG_DWORD, (PBYTE)&dwNow, sizeof(dwNow)); BAIL_ON_UMN_ERROR(dwError); cleanup: LW_SAFE_FREE_STRING(pEncodedGroup); LW_SAFE_FREE_STRING(pKeyName); LW_SAFE_FREE_STRING(pMembersKeyName); LW_SAFE_FREE_STRING(pEncodedMember); if (hKey) { RegCloseKey( hReg, hKey); } if (hMembers) { RegCloseKey( hReg, hMembers); } return dwError; error: goto cleanup; }
DWORD InstallWbclient( PCSTR pSmbdPath ) { DWORD error = 0; PSTR pSambaDir = NULL; PSTR pWbClient = NULL; PSTR pWbClientOriginal = NULL; PCSTR pLikewiseWbClient = LIBDIR "/" WBCLIENT_FILENAME; char pBuffer[1024] = { 0 }; error = GetWbclientDir( pSmbdPath, &pSambaDir); BAIL_ON_LSA_ERROR(error); error = LwAllocateStringPrintf( &pWbClient, "%s/%s", pSambaDir, WBCLIENT_FILENAME ); BAIL_ON_LSA_ERROR(error); if (readlink(pWbClient, pBuffer, sizeof(pBuffer)) < 0) { switch(errno) { // File does not exist case ENOENT: // Not a symbolic link case EINVAL: pBuffer[0] = 0; break; default: error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } } pBuffer[sizeof(pBuffer) - 1] = 0; if (!strcmp(pBuffer, pLikewiseWbClient)) { LW_RTL_LOG_INFO("Link %s already points to %s", pWbClient, pBuffer); // Already configured goto cleanup; } error = LwAllocateStringPrintf( &pWbClientOriginal, "%s.lwidentity.orig", pWbClient ); BAIL_ON_LSA_ERROR(error); if (!strcmp(pBuffer, pWbClientOriginal)) { if (unlink(pWbClient) < 0) { error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } } else { if (rename(pWbClient, pWbClientOriginal) < 0) { if (errno != ENOENT) { error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } } } if (symlink(pLikewiseWbClient, pWbClient) < 0) { error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } LW_RTL_LOG_INFO("Linked %s to %s", pWbClient, pLikewiseWbClient); cleanup: LW_SAFE_FREE_STRING(pSambaDir); LW_SAFE_FREE_STRING(pWbClient); LW_SAFE_FREE_STRING(pWbClientOriginal); return error; }
DWORD GetIdmapDir( PCSTR pSmbdPath, PSTR* ppDir ) { DWORD error = 0; PSTR pCommandLine = NULL; PCSTR ppArgs[] = { "/bin/sh", "-c", NULL, NULL }; PSTR pSambaLibdir = NULL; PSTR pDir = NULL; error = LwAllocateStringPrintf( &pCommandLine, "%s -b | grep MODULESDIR:", pSmbdPath ); BAIL_ON_LSA_ERROR(error); ppArgs[2] = pCommandLine; error = CaptureOutputWithStderr( "/bin/sh", ppArgs, &pSambaLibdir, NULL); if (error == ERROR_BAD_COMMAND) { // This version of smbd is older than 3.4. Try looking for the LIBDIR // instead. LW_SAFE_FREE_STRING(pCommandLine); error = LwAllocateStringPrintf( &pCommandLine, "%s -b | grep LIBDIR:", pSmbdPath ); BAIL_ON_LSA_ERROR(error); ppArgs[2] = pCommandLine; error = CaptureOutputWithStderr( "/bin/sh", ppArgs, &pSambaLibdir, NULL); } BAIL_ON_LSA_ERROR(error); LwStripWhitespace( pSambaLibdir, TRUE, TRUE); if (strstr(pSambaLibdir, ": ")) { char *pValueStart = strstr(pSambaLibdir, ": ") + 2; memmove( pSambaLibdir, pValueStart, strlen(pSambaLibdir) - (pValueStart - pSambaLibdir) + 1); } error = LwAllocateStringPrintf( &pDir, "%s/idmap", pSambaLibdir ); BAIL_ON_LSA_ERROR(error); cleanup: *ppDir = pDir; LW_SAFE_FREE_STRING(pCommandLine); LW_SAFE_FREE_STRING(pSambaLibdir); return error; }
int main( int argc, char *argv[] ) { enum { UNSET, SHOW_HELP, CHECK_VERSION, INSTALL, UNINSTALL } mode = UNSET; PCSTR pSmbdPath = NULL; PSTR pFoundSmbdPath = NULL; DWORD error = 0; DWORD argIndex = 0; LW_RTL_LOG_LEVEL logLevel = LW_RTL_LOG_LEVEL_ERROR; PCSTR pErrorSymbol = NULL; for (argIndex = 1; argIndex < argc; argIndex++) { if (!strcmp(argv[argIndex], "--check-version")) { if (mode == UNSET) { mode = CHECK_VERSION; } else { mode = SHOW_HELP; } } else if (!strcmp(argv[argIndex], "--install")) { if (mode == UNSET) { mode = INSTALL; } else { mode = SHOW_HELP; } } else if (!strcmp(argv[argIndex], "--uninstall")) { if (mode == UNSET) { mode = UNINSTALL; } else { mode = SHOW_HELP; } } else if (!strcmp(argv[argIndex], "--loglevel")) { argIndex++; if (argIndex >= argc) { error = ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(error); } if (!strcmp(argv[argIndex], "error")) { logLevel = LW_RTL_LOG_LEVEL_ERROR; } else if (!strcmp(argv[argIndex], "warning")) { logLevel = LW_RTL_LOG_LEVEL_WARNING; } else if (!strcmp(argv[argIndex], "info")) { logLevel = LW_RTL_LOG_LEVEL_INFO; } else if (!strcmp(argv[argIndex], "verbose")) { logLevel = LW_RTL_LOG_LEVEL_VERBOSE; } else if (!strcmp(argv[argIndex], "debug")) { logLevel = LW_RTL_LOG_LEVEL_DEBUG; } else { error = ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(error); } } else if (argIndex == argc - 1) { pSmbdPath = argv[2]; } else { mode = SHOW_HELP; } } if (mode == UNSET || mode == SHOW_HELP) { ShowUsage(argv[0]); goto cleanup; } LwRtlLogSetCallback(LogCallback, NULL); LwRtlLogSetLevel(logLevel); if (pSmbdPath == NULL) { error = FindFileInPath( "smbd", "/usr/sbin", &pFoundSmbdPath); BAIL_ON_LSA_ERROR(error); pSmbdPath = pFoundSmbdPath; } error = CheckSambaVersion(pSmbdPath); BAIL_ON_LSA_ERROR(error); if (mode == CHECK_VERSION) { fprintf(stderr, "Samba version supported\n"); } else if (mode == INSTALL) { error = InstallWbclient(pSmbdPath); BAIL_ON_LSA_ERROR(error); error = InstallLwiCompat(pSmbdPath); BAIL_ON_LSA_ERROR(error); error = SynchronizePassword( pSmbdPath); BAIL_ON_LSA_ERROR(error); fprintf(stderr, "Install successful\n"); } else if (mode == UNINSTALL) { error = UninstallWbclient(pSmbdPath); BAIL_ON_LSA_ERROR(error); error = UninstallLwiCompat(pSmbdPath); BAIL_ON_LSA_ERROR(error); error = DeletePassword( pSmbdPath); BAIL_ON_LSA_ERROR(error); fprintf(stderr, "Uninstall successful\n"); } else { fprintf(stderr, "Uninstall mode not implemented\n"); error = ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(error); } cleanup: LW_SAFE_FREE_STRING(pFoundSmbdPath); if (error) { pErrorSymbol = LwWin32ErrorToName(error); if (pErrorSymbol != NULL) { fprintf(stderr, "Error: %s\n", pErrorSymbol); } else { fprintf(stderr, "Unknown error\n"); } } return error; }
DWORD GetWbclientDir( PCSTR pSmbdPath, PSTR* ppDir ) { PCSTR ppBackupPaths[] = { "/usr/lib", "/usr/lib64", NULL, }; DWORD index = 0; DWORD error = 0; BOOLEAN exists = 0; PSTR pFoundPath = NULL; PSTR pCommandLine = NULL; PCSTR ppArgs[] = { "/bin/sh", "-c", NULL, NULL }; PSTR pSambaLibdir = NULL; *ppDir = NULL; // First see if libwbclient.so.0 is in Samba's libdir. There may be two // copies of libwbclient.so.0 because of different architectures. This will // identify which one is the primary one. error = LwAllocateStringPrintf( &pCommandLine, "%s -b | grep LIBDIR:", pSmbdPath ); BAIL_ON_LSA_ERROR(error); ppArgs[2] = pCommandLine; error = CaptureOutputWithStderr( "/bin/sh", ppArgs, &pSambaLibdir, NULL); BAIL_ON_LSA_ERROR(error); LwStripWhitespace( pSambaLibdir, TRUE, TRUE); if (strstr(pSambaLibdir, ": ")) { char *pValueStart = strstr(pSambaLibdir, ": ") + 2; memmove( pSambaLibdir, pValueStart, strlen(pSambaLibdir) - (pValueStart - pSambaLibdir) + 1); } error = FindFileInPath( WBCLIENT_FILENAME, pSambaLibdir, &pFoundPath); if (error == ERROR_FILE_NOT_FOUND) { // Fall back to trying the two standard system paths error = FindFileInPath( WBCLIENT_FILENAME, "/usr/lib:/usr/lib64", &pFoundPath); if (error == ERROR_FILE_NOT_FOUND) { error = 0; } } BAIL_ON_LSA_ERROR(error); if (pFoundPath) { pFoundPath[strlen(pFoundPath) - (sizeof(WBCLIENT_FILENAME) -1) - 1] = 0; *ppDir = pFoundPath; pFoundPath = NULL; goto cleanup; } // Could not find an existing libwbclient.so.0. This could be a Samba 3.0.x // build. Just stick the file in a system path. for (index = 0; ppBackupPaths[index]; index++) { error = LwCheckFileTypeExists( ppBackupPaths[index], LWFILE_DIRECTORY, &exists); BAIL_ON_LSA_ERROR(error); if (exists) { error = LwAllocateString(ppBackupPaths[index], ppDir); BAIL_ON_LSA_ERROR(error); goto cleanup; } } // Could not find the system library paths. error = ERROR_FILE_NOT_FOUND; BAIL_ON_LSA_ERROR(error); cleanup: LW_SAFE_FREE_STRING(pFoundPath); LW_SAFE_FREE_STRING(pCommandLine); LW_SAFE_FREE_STRING(pSambaLibdir); return error; }
static DWORD AddSambaLoadPath( IN HANDLE hReg ) { DWORD type = 0; HKEY hKey = NULL; DWORD error = 0; DWORD loadOrderSize = 0; PSTR pLoadOrder = NULL; DWORD newLoadOrderSize = 0; PSTR pNewLoadOrder = NULL; PCSTR pPos = NULL; error = LwRegOpenKeyExA( hReg, NULL, LSA_PSTORE_REG_KEY_PATH_PLUGINS, 0, KEY_WRITE, &hKey); BAIL_ON_LSA_ERROR(error); error = LwRegGetValueA( hReg, hKey, NULL, "LoadOrder", RRF_RT_REG_MULTI_SZ, &type, NULL, &loadOrderSize); if (error == LWREG_ERROR_NO_SUCH_KEY_OR_VALUE) { loadOrderSize = 1; error = LwAllocateMemory(loadOrderSize, (PVOID*) &pLoadOrder); BAIL_ON_LSA_ERROR(error); // pLoadOrder is already memset to 0 error = 0; } else { BAIL_ON_LSA_ERROR(error); error = LwAllocateMemory(loadOrderSize, (PVOID*) &pLoadOrder); BAIL_ON_LSA_ERROR(error); error = LwRegGetValueA( hReg, hKey, NULL, "LoadOrder", RRF_RT_REG_MULTI_SZ, &type, pLoadOrder, &loadOrderSize); BAIL_ON_LSA_ERROR(error); } pPos = pLoadOrder; while (pPos[0]) { if (!strcmp(pPos, PLUGIN_NAME)) { LW_RTL_LOG_INFO("Samba is already in the load order"); goto cleanup; } pPos += strlen(pPos) + 1; } newLoadOrderSize = loadOrderSize + strlen(PLUGIN_NAME) + 1; error = LwAllocateMemory(newLoadOrderSize, (PVOID*) &pNewLoadOrder); BAIL_ON_LSA_ERROR(error); memcpy(pNewLoadOrder, PLUGIN_NAME, strlen(PLUGIN_NAME) + 1); memcpy(pNewLoadOrder + strlen(PLUGIN_NAME) + 1, pLoadOrder, loadOrderSize); error = LwRegSetValueExA( hReg, hKey, "LoadOrder", 0, REG_MULTI_SZ, (const BYTE*)pNewLoadOrder, newLoadOrderSize); BAIL_ON_LSA_ERROR(error); cleanup: if (hKey != NULL) { LwRegCloseKey( hReg, hKey); } LW_SAFE_FREE_STRING(pLoadOrder); LW_SAFE_FREE_STRING(pNewLoadOrder); return error; }
DWORD SynchronizePassword( PCSTR pSmbdPath ) { DWORD error = 0; PSTR pSecretsPath = NULL; LW_HANDLE hLsa = NULL; PLSA_MACHINE_PASSWORD_INFO_A pPasswordInfo = NULL; PLSA_PSTORE_PLUGIN_DISPATCH pDispatch = NULL; PLSA_PSTORE_PLUGIN_CONTEXT pContext = NULL; HANDLE hReg = NULL; error = LwRegOpenServer(&hReg); BAIL_ON_LSA_ERROR(error); error = GetSecretsPath( pSmbdPath, &pSecretsPath); BAIL_ON_LSA_ERROR(error); error = RegUtilAddKey( hReg, LSA_PSTORE_REG_ROOT_KEY_PATH, NULL, LSA_PSTORE_REG_ROOT_KEY_RELATIVE_PATH_PLUGINS "\\" PLUGIN_NAME); BAIL_ON_LSA_ERROR(error); error = RegUtilSetValue( hReg, LSA_PSTORE_REG_ROOT_KEY_PATH, NULL, LSA_PSTORE_REG_ROOT_KEY_RELATIVE_PATH_PLUGINS "\\" PLUGIN_NAME, "SecretsPath", REG_SZ, pSecretsPath, strlen(pSecretsPath)); BAIL_ON_LSA_ERROR(error); error = RegUtilSetValue( hReg, HKEY_THIS_MACHINE, NULL, LSA_PSTORE_REG_ROOT_KEY_RELATIVE_PATH_PLUGINS "\\" PLUGIN_NAME, "Path", REG_SZ, PLUGIN_PATH, strlen(PLUGIN_PATH)); BAIL_ON_LSA_ERROR(error); error = AddSambaLoadPath(hReg); BAIL_ON_LSA_ERROR(error); error = LsaOpenServer( &hLsa); if (error) { LW_RTL_LOG_ERROR("Unable to contact lsassd"); } BAIL_ON_LSA_ERROR(error); error = LsaAdGetMachinePasswordInfo( hLsa, NULL, &pPasswordInfo); if (error == NERR_SetupNotJoined) { LW_RTL_LOG_ERROR("Unable to write machine password in secrets.tdb because Likewise is not joined. The password will be written to secrets.tdb on the next successful join attempt"); error = 0; } else { BAIL_ON_LSA_ERROR(error); error = LsaPstorePluginInitializeContext( LSA_PSTORE_PLUGIN_VERSION, PLUGIN_NAME, &pDispatch, &pContext); BAIL_ON_LSA_ERROR(error); error = pDispatch->SetPasswordInfoA( pContext, pPasswordInfo); BAIL_ON_LSA_ERROR(error); } cleanup: LW_SAFE_FREE_STRING(pSecretsPath); if (hLsa != NULL) { LsaCloseServer(hLsa); } if (hReg != NULL) { LwRegCloseServer(hReg); } if (pPasswordInfo != NULL) { LsaAdFreeMachinePasswordInfo(pPasswordInfo); } if (pContext) { pDispatch->Cleanup(pContext); } return error; }
DWORD LsaSrvGetStatus( HANDLE hServer, PCSTR pszTargetProvider, PLSASTATUS* ppLsaStatus ) { DWORD dwError = 0; BOOLEAN bInLock = FALSE; PLSA_AUTH_PROVIDER pProvider = NULL; DWORD dwProviderCount = 0; DWORD iCount = 0; DWORD dwStatusIndex = 0; HANDLE hProvider = (HANDLE)NULL; PLSASTATUS pLsaStatus = NULL; PLSA_AUTH_PROVIDER_STATUS pProviderOwnedStatus = NULL; BOOLEAN bFoundProvider = FALSE; PSTR pszTargetProviderName = NULL; PSTR pszTargetInstance = NULL; BAIL_ON_INVALID_POINTER(ppLsaStatus); dwError = LwAllocateMemory( sizeof(LSASTATUS), (PVOID*)&pLsaStatus); BAIL_ON_LSA_ERROR(dwError); pLsaStatus->dwUptime = (DWORD)difftime(time(NULL), gServerStartTime); dwError = LsaSrvGetLsassVersion( &pLsaStatus->lsassVersion); BAIL_ON_LSA_ERROR(dwError); dwError = LsaReadVersionFile( &pLsaStatus->productVersion); BAIL_ON_LSA_ERROR(dwError); if (pszTargetProvider) { dwError = LsaSrvGetTargetElements( pszTargetProvider, &pszTargetProviderName, &pszTargetInstance); BAIL_ON_LSA_ERROR(dwError); } ENTER_AUTH_PROVIDER_LIST_READER_LOCK(bInLock); if (pszTargetProviderName) { dwProviderCount = 1; } else { dwProviderCount = LsaGetNumberOfProviders_inlock(); } if (!dwProviderCount) { goto done; } dwError = LwAllocateMemory( dwProviderCount * sizeof(LSA_AUTH_PROVIDER_STATUS), (PVOID*)&pLsaStatus->pAuthProviderStatusList); BAIL_ON_LSA_ERROR(dwError); pLsaStatus->dwCount = dwProviderCount; dwError = LW_ERROR_NOT_HANDLED; for (pProvider = gpAuthProviderList, iCount = 0, dwStatusIndex = 0; pProvider; pProvider = pProvider->pNext, iCount++) { PLSA_AUTH_PROVIDER_STATUS pAuthProviderStatus = NULL; if (pszTargetProviderName) { if (!strcmp(pszTargetProviderName, pProvider->pszName)) { bFoundProvider = TRUE; } else { continue; } } dwError = LsaSrvOpenProvider( hServer, pProvider, pszTargetInstance, &hProvider); BAIL_ON_LSA_ERROR(dwError); pAuthProviderStatus = &pLsaStatus->pAuthProviderStatusList[dwStatusIndex++]; dwError = LwAllocateString( pProvider->pszName, &pAuthProviderStatus->pszId); BAIL_ON_LSA_ERROR(dwError); dwError = pProvider->pFnTable->pfnGetStatus( hProvider, &pProviderOwnedStatus); if (dwError == LW_ERROR_NOT_HANDLED) { dwError = 0; } else { BAIL_ON_LSA_ERROR(dwError); dwError = LsaSrvCopyProviderStatus( pProviderOwnedStatus, pAuthProviderStatus); BAIL_ON_LSA_ERROR(dwError); pProvider->pFnTable->pfnFreeStatus( pProviderOwnedStatus); pProviderOwnedStatus = NULL; } LsaSrvCloseProvider(pProvider, hProvider); hProvider = (HANDLE)NULL; } if (pszTargetProviderName && !bFoundProvider) { dwError = LW_ERROR_INVALID_AUTH_PROVIDER; BAIL_ON_LSA_ERROR(dwError); } done: *ppLsaStatus = pLsaStatus; cleanup: LW_SAFE_FREE_STRING(pszTargetProviderName); LW_SAFE_FREE_STRING(pszTargetInstance); if (pProvider != NULL && pProviderOwnedStatus) { pProvider->pFnTable->pfnFreeStatus( pProviderOwnedStatus); } if (hProvider != NULL) { LsaSrvCloseProvider(pProvider, hProvider); } LEAVE_AUTH_PROVIDER_LIST_READER_LOCK(bInLock); return dwError; error: LSA_LOG_ERROR_API_FAILED(hServer, dwError, "get lsass status"); if (ppLsaStatus) { *ppLsaStatus = NULL; } if (pLsaStatus) { LsaFreeStatus(pLsaStatus); } goto cleanup; }
DWORD NtlmServerInitializeSecurityContext( IN OPTIONAL NTLM_CRED_HANDLE hCredential, IN OPTIONAL const NTLM_CONTEXT_HANDLE hContext, IN OPTIONAL SEC_CHAR* pszTargetName, IN DWORD fContextReq, IN DWORD Reserved1, IN DWORD TargetDataRep, IN OPTIONAL const SecBuffer* pInput, IN DWORD Reserved2, IN OUT OPTIONAL PNTLM_CONTEXT_HANDLE phNewContext, OUT PSecBuffer pOutput, OUT PDWORD pfContextAttr, OUT OPTIONAL PTimeStamp ptsExpiry ) { DWORD dwError = LW_ERROR_SUCCESS; PNTLM_CREDENTIALS pCred = (PNTLM_CREDENTIALS)hCredential; PNTLM_CONTEXT pNtlmContext = NULL; PSTR pWorkstation = NULL; PSTR pDomain = NULL; PNTLM_CHALLENGE_MESSAGE pMessage = NULL; DWORD dwMessageSize ATTRIBUTE_UNUSED = 0; BOOLEAN bInLock = FALSE; pOutput->pvBuffer = NULL; if (hContext) { pNtlmContext = hContext; } if (!pNtlmContext) { if (pCred) { NTLM_LOCK_MUTEX(bInLock, &pCred->Mutex); dwError = NtlmGetNameInformation( pCred->pszDomainName, &pWorkstation, &pDomain, NULL, NULL); BAIL_ON_LSA_ERROR(dwError); NTLM_UNLOCK_MUTEX(bInLock, &pCred->Mutex); } else { dwError = NtlmGetNameInformation( NULL, &pWorkstation, &pDomain, NULL, NULL); BAIL_ON_LSA_ERROR(dwError); } // If we start with a NULL context, create a negotiate message dwError = NtlmCreateNegotiateContext( hCredential, fContextReq, pDomain, pWorkstation, (PBYTE)&gXpSpoof, //for now add OS ver info... config later &pNtlmContext, pOutput); BAIL_ON_LSA_ERROR(dwError); dwError = LW_WARNING_CONTINUE_NEEDED; } else { if (pInput->BufferType != SECBUFFER_TOKEN || pInput->cbBuffer == 0) { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } pMessage = pInput->pvBuffer; dwMessageSize = pInput->cbBuffer; dwError = NtlmCreateResponseContext( pMessage, hCredential, pNtlmContext->bDoAnonymous, &pNtlmContext, pOutput); BAIL_ON_LSA_ERROR(dwError); } *phNewContext = pNtlmContext; if (pfContextAttr) { NtlmGetContextInfo( pNtlmContext, NULL, pfContextAttr, NULL, NULL, NULL); } cleanup: if (pCred) { NTLM_UNLOCK_MUTEX(bInLock, &pCred->Mutex); } LW_SAFE_FREE_STRING(pWorkstation); LW_SAFE_FREE_STRING(pDomain); return dwError; error: LW_SAFE_FREE_MEMORY(pOutput->pvBuffer); pOutput->cbBuffer = 0; pOutput->BufferType = 0; // If this function has already succeed once, we MUST make sure phNewContext // is set so the caller can cleanup whatever context is remaining. It // could be the original negotiate context or a new response context but // either way it is vital that the caller get a context they can actually // cleanup ONCE they've received ANY context from this function. // // If hContext is NULL, that indicates this is the first time through this // call and we can safely release our context. if ( pNtlmContext && !hContext) { NtlmReleaseContext(&pNtlmContext); phNewContext = NULL; } goto cleanup; }
long PlugInShell_PeriodicTask(void) { long macError = eDSNoErr; bool isAcquired = false; BOOLEAN bMergeModeMCX = FALSE; BOOLEAN bEnableForceHomedirOnStartupDisk = FALSE; BOOLEAN bUseADUNCForHomeLocation = FALSE; BOOLEAN bAdminListChanged = FALSE; PSTR pszUNCProtocolForHomeLocation = NULL; PSTR pszAllowAdministrationBy = NULL; BOOLEAN bMergeAdmins = FALSE; BOOLEAN bIsStarted = FALSE; LWE_DS_FLAGS NewFlags = LWE_DS_FLAG_NO_OPTIONS_SET; PVOID pAllowAdminCheckData = NULL; PNETADAPTERINFO pTempNetInfo = NULL; // No enter/leave logging since function is called every 30 seconds // or so (on Mac OS X 10.4.7). GS_VERIFY_INITIALIZED(macError); GS_ACQUIRE_SHARED(); pthread_mutex_lock(&GlobalState.PeriodicTaskMutex); isAcquired = true; if (!GlobalState.pNetAdapterList) { /* Get the network adpater details - We only care about the ENetAddress info */ macError = LWGetNetAdapterList(true, &GlobalState.pNetAdapterList); GOTO_CLEANUP_ON_MACERROR(macError); pTempNetInfo = GlobalState.pNetAdapterList; while (pTempNetInfo) { LOG("Finally found a valid ethernet network adapter..."); LOG(" Name: %s", pTempNetInfo->pszName); LOG(" ENet: %s", pTempNetInfo->pszENetAddress ? pTempNetInfo->pszENetAddress : "----"); LOG(" IP: %s", pTempNetInfo->pszIPAddress ? pTempNetInfo->pszIPAddress : "----"); LOG(" Up: %s", pTempNetInfo->IsUp ? "yes" : "no"); LOG(" Running: %s", pTempNetInfo->IsRunning ? "yes" : "no"); pTempNetInfo = pTempNetInfo->pNext; } } if (GlobalState.IsStartupComplete == false) { // Re-verify that startup has completed successfully for lsass service. LOG("Re-verify that LSASS service is operational"); GetLsaStatus(&bIsStarted); if (bIsStarted) { LOG("LSASS service is now operational"); GlobalState.IsStartupComplete = true; } } macError = GetConfigurationSettings(&bMergeModeMCX, &bEnableForceHomedirOnStartupDisk, &bUseADUNCForHomeLocation, &pszUNCProtocolForHomeLocation, &pszAllowAdministrationBy, &bMergeAdmins); GOTO_CLEANUP_ON_MACERROR(macError); /* Make sure to preserve the flag that tells us this is Leopard or not */ if (GlobalState.Flags & LWE_DS_FLAG_IS_LEOPARD) { NewFlags = NewFlags | LWE_DS_FLAG_IS_LEOPARD;; } /* Make sure to preserve the flag that tells us this is Snow Leopard or not */ if (GlobalState.Flags & LWE_DS_FLAG_IS_SNOW_LEOPARD) { NewFlags = NewFlags | LWE_DS_FLAG_IS_SNOW_LEOPARD;; } /* See if MCX setting aggregation feature is to be supported */ if (bMergeModeMCX) { NewFlags = NewFlags | LWE_DS_FLAG_MERGE_MODE_MCX; if (GlobalState.Flags & LWE_DS_FLAG_MERGE_MODE_MCX == 0) { LOG("Merge mode MCX is now enabled. Settings from multiple Group Policy Objects will be merged for the AD user accounts at logon."); } } /* See if Force Home Directory On Startup Disk feature is to be supported */ if (bEnableForceHomedirOnStartupDisk) { NewFlags = NewFlags | LWE_DS_FLAG_FORCE_LOCAL_HOME_DIRECTORY_ON_STARTUP_DISK; if (GlobalState.Flags & LWE_DS_FLAG_FORCE_LOCAL_HOME_DIRECTORY_ON_STARTUP_DISK == 0) { LOG("Force Home Directory On Startup Disk is now enabled."); } } /* See if Use AD UNC for Home Location - SMB feature is to be supported */ if (bUseADUNCForHomeLocation) { if (pszUNCProtocolForHomeLocation && !strcmp(pszUNCProtocolForHomeLocation, "smb")) { NewFlags = NewFlags | LWE_DS_FLAG_USE_AD_UNC_FOR_HOME_LOCATION_SMB; } else if (pszUNCProtocolForHomeLocation && !strcmp(pszUNCProtocolForHomeLocation, "afp")) { /* See if Use AD UNC for Home Location - AFP feature is to be supported */ NewFlags = NewFlags | LWE_DS_FLAG_USE_AD_UNC_FOR_HOME_LOCATION_AFP; } else { NewFlags = NewFlags | LWE_DS_FLAG_USE_AD_UNC_FOR_HOME_LOCATION_SMB; } } if (pszAllowAdministrationBy) { if (GlobalState.pszCurrentAllowedAdminsList) { if (strcmp(GlobalState.pszCurrentAllowedAdminsList, pszAllowAdministrationBy)) { // Setting changed from one value to another bAdminListChanged = true; } // Release the former cached list LW_SAFE_FREE_STRING(GlobalState.pszCurrentAllowedAdminsList); } else { // Former empty value is to be updated to new bAdminListChanged = true; } // Now replace cached list GlobalState.pszCurrentAllowedAdminsList = pszAllowAdministrationBy; pszAllowAdministrationBy = NULL; if (bAdminListChanged) { macError = GetAccessCheckData(GlobalState.pszCurrentAllowedAdminsList, &pAllowAdminCheckData); if (macError) { if (macError == eDSAuthUnknownUser) { LOG("GetAccessCheckData(%s) failed with error: eDSAuthUnknownUser. AD user accounts will not be added to admin group (GID:80), since the list provided is incorrectly specified. This error suggests that you have a user or group that is not recognized by Likewise authentication daemon. Recommend checking that system administrator has enabled the items here in the Likewise cell that applies to this computer.", GlobalState.pszCurrentAllowedAdminsList); } else { LOG("Failed to GetAllowData(%s) with error: %d", GlobalState.pszCurrentAllowedAdminsList, macError); } LW_SAFE_FREE_STRING(GlobalState.pszCurrentAllowedAdminsList); GlobalState.pszCurrentAllowedAdminsList = NULL; pAllowAdminCheckData = NULL; macError = eDSNoErr; } else { LOG("AllowAdministrationBy updated to (%s)", GlobalState.pszCurrentAllowedAdminsList); } } } else { if (GlobalState.pszCurrentAllowedAdminsList) { // Former value being set to empty bAdminListChanged = true; LW_SAFE_FREE_STRING(GlobalState.pszCurrentAllowedAdminsList); GlobalState.pszCurrentAllowedAdminsList = NULL; LOG("AllowAdministrationBy updated to (not set)"); } } /* See if Merge Admins feature is to be supported */ if (bMergeAdmins) { NewFlags = NewFlags | LWE_DS_FLAG_DONT_REMOVE_LOCAL_ADMINS; if (GlobalState.Flags & LWE_DS_FLAG_DONT_REMOVE_LOCAL_ADMINS == 0) { LOG("Option to override allow-administration-by with local computer changes to the admin group is now enabled."); } } if (bAdminListChanged) { /* Now update the GlobalState to reflect new pAllowAdminCheckData */ GS_ACQUIRE_EXCLUSIVE_ADMIN_ACCESS_LIST(); if (GlobalState.pAllowAdminCheckData) { FreeAccessCheckData(GlobalState.pAllowAdminCheckData); GlobalState.pAllowAdminCheckData = NULL; } if (pAllowAdminCheckData) { GlobalState.pAllowAdminCheckData = pAllowAdminCheckData; pAllowAdminCheckData = NULL; } GS_RELEASE_ADMIN_ACCESS_LIST(); } /* Now update the GlobalState to reflect new flags */ GlobalState.Flags = NewFlags; if (GlobalState.fDomainControllerNotAvailable && (GlobalState.OfflineTimerCount < 5)) { GlobalState.OfflineTimerCount++; macError = eDSNoErr; goto cleanup; } GlobalState.fDomainControllerNotAvailable = false; GlobalState.OfflineTimerCount = 0; if (isAcquired) { pthread_mutex_unlock(&GlobalState.PeriodicTaskMutex); GS_RELEASE(); isAcquired = false; } macError = RefreshGPONodes(); if (macError) { LOG("Encountered error %d from refresh GPO nodes", macError); macError = eDSNoErr; } cleanup: if (pszUNCProtocolForHomeLocation) { LW_SAFE_FREE_STRING(pszUNCProtocolForHomeLocation); } if (pszAllowAdministrationBy) { LW_SAFE_FREE_STRING(pszAllowAdministrationBy); } if (isAcquired) { pthread_mutex_unlock(&GlobalState.PeriodicTaskMutex); GS_RELEASE(); } return macError; }
DWORD LsaSrvCopyProviderStatus( PLSA_AUTH_PROVIDER_STATUS pProviderOwnedStatus, PLSA_AUTH_PROVIDER_STATUS pTargetStatus ) { DWORD dwError = 0; pTargetStatus->mode = pProviderOwnedStatus->mode; LW_SAFE_FREE_STRING(pTargetStatus->pszCell); if (!LW_IS_NULL_OR_EMPTY_STR(pProviderOwnedStatus->pszCell)) { dwError = LwAllocateString( pProviderOwnedStatus->pszCell, &pTargetStatus->pszCell); BAIL_ON_LSA_ERROR(dwError); } LW_SAFE_FREE_STRING(pTargetStatus->pszDomain); if (!LW_IS_NULL_OR_EMPTY_STR(pProviderOwnedStatus->pszDomain)) { dwError = LwAllocateString( pProviderOwnedStatus->pszDomain, &pTargetStatus->pszDomain); BAIL_ON_LSA_ERROR(dwError); } LW_SAFE_FREE_STRING(pTargetStatus->pszDomainSid); if (!LW_IS_NULL_OR_EMPTY_STR(pProviderOwnedStatus->pszDomainSid)) { dwError = LwAllocateString( pProviderOwnedStatus->pszDomainSid, &pTargetStatus->pszDomainSid); BAIL_ON_LSA_ERROR(dwError); } LW_SAFE_FREE_STRING(pTargetStatus->pszForest); if (!LW_IS_NULL_OR_EMPTY_STR(pProviderOwnedStatus->pszForest)) { dwError = LwAllocateString( pProviderOwnedStatus->pszForest, &pTargetStatus->pszForest); BAIL_ON_LSA_ERROR(dwError); } LW_SAFE_FREE_STRING(pTargetStatus->pszId); if (!LW_IS_NULL_OR_EMPTY_STR(pProviderOwnedStatus->pszId)) { dwError = LwAllocateString( pProviderOwnedStatus->pszId, &pTargetStatus->pszId); BAIL_ON_LSA_ERROR(dwError); } LW_SAFE_FREE_STRING(pTargetStatus->pszSite); if (!LW_IS_NULL_OR_EMPTY_STR(pProviderOwnedStatus->pszSite)) { dwError = LwAllocateString( pProviderOwnedStatus->pszSite, &pTargetStatus->pszSite); BAIL_ON_LSA_ERROR(dwError); } pTargetStatus->status = pProviderOwnedStatus->status; pTargetStatus->subMode = pProviderOwnedStatus->subMode; pTargetStatus->dwNetworkCheckInterval = pProviderOwnedStatus->dwNetworkCheckInterval; if (pProviderOwnedStatus->pTrustedDomainInfoArray) { dwError = LsaSrvCopyTrustedDomainInfoArray( pProviderOwnedStatus->dwNumTrustedDomains, pProviderOwnedStatus->pTrustedDomainInfoArray, &pTargetStatus->pTrustedDomainInfoArray); BAIL_ON_LSA_ERROR(dwError); pTargetStatus->dwNumTrustedDomains = pProviderOwnedStatus->dwNumTrustedDomains; } cleanup: return dwError; error: goto cleanup; }
long PlugInShell_Initialize(void) { long macError = eDSNoErr; bool gotUnameInfo = false; PSTR pszVersion = NULL; PCSTR pszVersionName = NULL; bool isUnsupported = false; PNETADAPTERINFO pTempNetInfo = NULL; struct utsname info; BOOLEAN bMergeModeMCX = FALSE; BOOLEAN bEnableForceHomedirOnStartupDisk = FALSE; BOOLEAN bUseADUNCForHomeLocation = FALSE; PSTR pszUNCProtocolForHomeLocation = NULL; PSTR pszAllowAdministrationBy = NULL; BOOLEAN bMergeAdmins = FALSE; PVOID pAllowAdminCheckData = NULL; memset(info.sysname, 0, sizeof(info.sysname)); memset(info.nodename, 0, sizeof(info.nodename)); memset(info.release, 0, sizeof(info.release)); memset(info.version, 0, sizeof(info.version)); memset(info.machine, 0, sizeof(info.machine)); LOG_ENTER(""); LOG("Current State = 0x%08x", GlobalState.PluginState); // // We expect to be called exactly once, except if we fail to initialize. // When that happens, we can get called again several times to try to // initialize successfully. // if (GlobalState.IsInitialized) { LOG("Plug-in already initialized"); GOTO_CLEANUP(); } /* Clear all values for GlobalState */ GlobalState.IsInitialized = false; GlobalState.PluginState = kUnknownState; GlobalState.IsJoinedToAD = false; GlobalState.Flags = LWE_DS_FLAG_NO_OPTIONS_SET; GlobalState.NodeNameList = NULL; GlobalState.pGPOs = NULL; GlobalState.pszRealm = NULL; macError = InitializeContextList(); GOTO_CLEANUP_ON_MACERROR(macError); if (uname(&info)) { gotUnameInfo = false; macError = LWCaptureOutput((char*)"sw_vers -productVersion", &pszVersion); GOTO_CLEANUP_ON_MACERROR(macError); if (strstr(pszVersion, "10.4.") == pszVersion) { GlobalState.Flags = GlobalState.Flags & (~LWE_DS_FLAG_IS_LEOPARD); pszVersionName = MAC_OS_X_VERSION_NAME_10_4; } else if (strstr(pszVersion, "10.5.") == pszVersion) { GlobalState.Flags = GlobalState.Flags | LWE_DS_FLAG_IS_LEOPARD; pszVersionName = MAC_OS_X_VERSION_NAME_10_5; } else if (strstr(pszVersion, "10.6.") == pszVersion) { GlobalState.Flags = GlobalState.Flags | LWE_DS_FLAG_IS_LEOPARD | LWE_DS_FLAG_IS_SNOW_LEOPARD; pszVersionName = MAC_OS_X_VERSION_NAME_10_6; } else if (strstr(pszVersion, "10.7.") == pszVersion) { GlobalState.Flags = GlobalState.Flags | LWE_DS_FLAG_IS_LEOPARD | LWE_DS_FLAG_IS_SNOW_LEOPARD; pszVersionName = MAC_OS_X_VERSION_NAME_10_7; } else { isUnsupported = true; } } else { gotUnameInfo = true; macError = LwAllocateString(info.release, &pszVersion); GOTO_CLEANUP_ON_MACERROR(macError); if (strstr(pszVersion, "8.") == pszVersion) { GlobalState.Flags = GlobalState.Flags & ~LWE_DS_FLAG_IS_LEOPARD; pszVersionName = MAC_OS_X_VERSION_NAME_10_4; } else if (strstr(pszVersion, "9.") == pszVersion) { GlobalState.Flags = GlobalState.Flags | LWE_DS_FLAG_IS_LEOPARD; pszVersionName = MAC_OS_X_VERSION_NAME_10_5; } else if (strstr(pszVersion, "10.") == pszVersion) { GlobalState.Flags = GlobalState.Flags | LWE_DS_FLAG_IS_LEOPARD | LWE_DS_FLAG_IS_SNOW_LEOPARD; pszVersionName = MAC_OS_X_VERSION_NAME_10_6; } else if (strstr(pszVersion, "11.") == pszVersion) { GlobalState.Flags = GlobalState.Flags | LWE_DS_FLAG_IS_LEOPARD | LWE_DS_FLAG_IS_SNOW_LEOPARD; pszVersionName = MAC_OS_X_VERSION_NAME_10_6; } else { isUnsupported = true; } } if (isUnsupported) { pszVersionName = "unsupported"; } LOG("Starting up Likewise - Active directory DS plug-in, detected %s Mac OS X %s(%s)", pszVersionName, gotUnameInfo ? "kernel " : "", pszVersion); if (isUnsupported) { macError = ePlugInFailedToInitialize; GOTO_CLEANUP_ON_MACERROR(macError); } /* Get the network adpater details - We only care about the ENetAddress info */ macError = LWGetNetAdapterList(true, &GlobalState.pNetAdapterList); GOTO_CLEANUP_ON_MACERROR(macError); if (!GlobalState.pNetAdapterList) { LOG("Could not find an ethernet network adapter, will retry later. Computer settings maybe not be applied till one is found."); } pTempNetInfo = GlobalState.pNetAdapterList; while (pTempNetInfo) { LOG("Found network adapter..."); LOG(" Name: %s", pTempNetInfo->pszName); LOG(" ENet: %s", pTempNetInfo->pszENetAddress ? pTempNetInfo->pszENetAddress : "----"); LOG(" IP: %s", pTempNetInfo->pszIPAddress ? pTempNetInfo->pszIPAddress : "----"); LOG(" Up: %s", pTempNetInfo->IsUp ? "yes" : "no"); LOG(" Running: %s", pTempNetInfo->IsRunning ? "yes" : "no"); pTempNetInfo = pTempNetInfo->pNext; } macError = GetConfigurationSettings(&bMergeModeMCX, &bEnableForceHomedirOnStartupDisk, &bUseADUNCForHomeLocation, &pszUNCProtocolForHomeLocation, &pszAllowAdministrationBy, &bMergeAdmins); GOTO_CLEANUP_ON_MACERROR(macError); /* See if MCX setting aggregation feature is to be supported */ if (bMergeModeMCX) { GlobalState.Flags = GlobalState.Flags | LWE_DS_FLAG_MERGE_MODE_MCX; LOG("Merge mode MCX is enabled. Settings from multiple Group Policy Objects will be merged for the AD user accounts at logon."); } /* See if Force Home Directory On Startup Disk feature is to be supported */ if (bEnableForceHomedirOnStartupDisk) { GlobalState.Flags = GlobalState.Flags | LWE_DS_FLAG_FORCE_LOCAL_HOME_DIRECTORY_ON_STARTUP_DISK; LOG("Force Home Directory On Startup Disk is enabled."); } /* See if Use AD UNC for Home Location - SMB feature is to be supported */ if (bUseADUNCForHomeLocation) { if (pszUNCProtocolForHomeLocation && !strcmp(pszUNCProtocolForHomeLocation, "smb")) { GlobalState.Flags = GlobalState.Flags | LWE_DS_FLAG_USE_AD_UNC_FOR_HOME_LOCATION_SMB; LOG("Use AD UNC for Home Location - SMB is enabled."); } else if (pszUNCProtocolForHomeLocation && !strcmp(pszUNCProtocolForHomeLocation, "afp")) { /* See if Use AD UNC for Home Location - AFP feature is to be supported */ GlobalState.Flags = GlobalState.Flags | LWE_DS_FLAG_USE_AD_UNC_FOR_HOME_LOCATION_AFP; LOG("Use AD UNC for Home Location - AFP is enabled."); } else { GlobalState.Flags = GlobalState.Flags | LWE_DS_FLAG_USE_AD_UNC_FOR_HOME_LOCATION_SMB; LOG("Use AD UNC for Home Location - defaulting to SMB protocol."); } } if (pszAllowAdministrationBy) { GlobalState.pszCurrentAllowedAdminsList = pszAllowAdministrationBy; pszAllowAdministrationBy = NULL; macError = GetAccessCheckData(GlobalState.pszCurrentAllowedAdminsList, &pAllowAdminCheckData); if (macError) { if (macError == eDSAuthUnknownUser) { LOG("GetAccessCheckData(%s) failed with error: eDSAuthUnknownUser. AD user accounts will not be added to admin group (GID:80), since the list provided is incorrectly specified. This error suggests that you have a user or group that is not recognized by Likewise authentication daemon. Recommend checking that system administrator has enabled the items here in the Likewise cell that applies to this computer.", GlobalState.pszCurrentAllowedAdminsList); } else { LOG("Failed to GetAccessCheckData(%s) with error: %d", GlobalState.pszCurrentAllowedAdminsList, macError); } LW_SAFE_FREE_STRING(GlobalState.pszCurrentAllowedAdminsList); GlobalState.pszCurrentAllowedAdminsList = NULL; GlobalState.pAllowAdminCheckData = NULL; macError = eDSNoErr; } else { LOG("AllowAdministrationBy configured to: %s", GlobalState.pszCurrentAllowedAdminsList); GlobalState.pAllowAdminCheckData = pAllowAdminCheckData; pAllowAdminCheckData = NULL; } } /* See if Merge Admins feature is to be supported */ if (bMergeAdmins) { GlobalState.Flags = GlobalState.Flags | LWE_DS_FLAG_DONT_REMOVE_LOCAL_ADMINS; LOG("Option to override allow-administration-by with local computer changes to the admin group is enabled."); } if (pthread_rwlock_init(&GlobalState.Lock, NULL) < 0) { int libcError = errno; LOG_ERROR("Failied to init lock: %s (%d)", strerror(libcError), libcError); macError = ePlugInInitError; GOTO_CLEANUP(); } GlobalState.IsLockInitialized = true; if (pthread_mutex_init(&GlobalState.PeriodicTaskMutex, NULL) < 0) { int libcError = errno; LOG_ERROR("Failied to init mutex: %s (%d)", strerror(libcError), libcError); macError = ePlugInInitError; GOTO_CLEANUP(); } GlobalState.IsPeriodicTaskMutexInitialized = true; if (pthread_rwlock_init(&GlobalState.AdminAccessListLock, NULL) < 0) { int libcError = errno; LOG_ERROR("Failied to init admin access list lock: %s (%d)", strerror(libcError), libcError); macError = ePlugInInitError; GOTO_CLEANUP(); } GlobalState.IsAdminAccessListLockInitialized = true; macError = LWIAttrLookup::Initialize(); GOTO_CLEANUP_ON_MACERROR(macError); macError = LWIRecTypeLookup::Initialize(); GOTO_CLEANUP_ON_MACERROR(macError); macError = LWIDirNodeQuery::Initialize(); GOTO_CLEANUP_ON_MACERROR(macError); macError = LWIRecordQuery::Initialize(); GOTO_CLEANUP_ON_MACERROR(macError); LWICRC::Initialize(); // Allow WGM policy options to define Login/Logoff Hook scripts. We do this to automatically support settings // we get from group policies. macError = SetupMCXLoginScriptsSupport(); GOTO_CLEANUP_ON_MACERROR(macError); GlobalState.IsInitialized = true; GlobalState.PluginState = kInitialized | kInactive; // // If we supported custom calls while not active, we would need to create a // node for that here. // cleanup: if (pszVersion) { LwFreeMemory(pszVersion); } if (pszUNCProtocolForHomeLocation) { LW_SAFE_FREE_STRING(pszUNCProtocolForHomeLocation); } if (pszAllowAdministrationBy) { LW_SAFE_FREE_STRING(pszUNCProtocolForHomeLocation); } if (pAllowAdminCheckData) { FreeAccessCheckData(pAllowAdminCheckData); } if (macError) { // This is the only error code allowed in the failure case. macError = ePlugInInitError; PlugInShell_Shutdown(); GlobalState.PluginState = kFailedToInit | kInactive; } LOG("Final State = 0x%08x", GlobalState.PluginState); LOG_LEAVE("--> %d", macError); return macError; }
static long RefreshGPONodes(void) { long macError = eDSNoErr; PGROUP_POLICY_OBJECT pCurrentGPOs = NULL; PGROUP_POLICY_OBJECT pDeletedGPOs = NULL; PGROUP_POLICY_OBJECT pNewGPOs = NULL; PGROUP_POLICY_OBJECT pTemp = NULL; PSTR pszDomain = NULL; bool isAcquired = false; macError = GetDomainJoinState(&pszDomain); GOTO_CLEANUP_ON_MACERROR(macError); if (pszDomain) { if (pszDomain && GlobalState.pszRealm && strcmp(pszDomain, GlobalState.pszRealm)) { LOG("Unexpected domain name change: '%s' -> '%s'", pszDomain, GlobalState.pszRealm); // ISSUE-2008/10/07-dalmeida -- To support this, we would // need to unregister all nodes. macError = eDSOperationFailed; GOTO_CLEANUP_ON_MACERROR(macError); } macError = EnumWorkgroupManagerEnabledGPOs(pszDomain, &pCurrentGPOs); if (macError == eDSReceiveFailed || macError == eDSBogusServer || macError == eDSSendFailed || macError == eDSAuthMasterUnreachable) { LOG("EnumWorkgroupManagerEnableGPOs failed %d, treating as okay", macError); GlobalState.fDomainControllerNotAvailable = true; GlobalState.OfflineTimerCount = 1; macError = eDSNoErr; } if (macError) { LOG("EnumWorkgroupManagerEnableGPOs failed unexpectedly (error = %d)", macError); GOTO_CLEANUP_ON_MACERROR(macError); } } GS_ACQUIRE_SHARED(); pthread_mutex_lock(&GlobalState.PeriodicTaskMutex); isAcquired = true; macError = GPAComputeDeletedList(pCurrentGPOs, GlobalState.pGPOs, &pDeletedGPOs); GOTO_CLEANUP_ON_MACERROR(macError); macError = GPAComputeDeletedList(GlobalState.pGPOs, pCurrentGPOs, &pNewGPOs); GOTO_CLEANUP_ON_MACERROR(macError); pTemp = pDeletedGPOs; while (pTemp) { LOG("Removing GPO directory node (%s)", pTemp->pszDisplayName); UnregisterGPONode(GlobalState.pszRealm, pTemp->pszDisplayName); pTemp = pTemp->pNext; } pTemp = pNewGPOs; while (pTemp) { LOG("Adding GPO directory node (%s)", pTemp->pszDisplayName); RegisterGPONode(pszDomain, pTemp->pszDisplayName); pTemp = pTemp->pNext; } GPA_SAFE_FREE_GPO_LIST(GlobalState.pGPOs); GlobalState.pGPOs = pCurrentGPOs; pCurrentGPOs = NULL; GlobalState.IsJoinedToAD = pszDomain ? true : false; LW_SAFE_FREE_STRING(GlobalState.pszRealm); GlobalState.pszRealm = pszDomain; pszDomain = NULL; cleanup: if (isAcquired) { pthread_mutex_unlock(&GlobalState.PeriodicTaskMutex); GS_RELEASE(); } GPA_SAFE_FREE_GPO_LIST(pCurrentGPOs); GPA_SAFE_FREE_GPO_LIST(pDeletedGPOs); GPA_SAFE_FREE_GPO_LIST(pNewGPOs); LW_SAFE_FREE_STRING(pszDomain); return macError; }
static long Deactivate(void) { long macError = eDSNoErr; PGROUP_POLICY_OBJECT pTemp = NULL; if ( GlobalState.NodeDictionary ) { CFRelease(GlobalState.NodeDictionary); GlobalState.NodeDictionary = NULL; } if ( GlobalState.NodeNameList ) { macError = DSUnregisterNode( GlobalState.Signature, GlobalState.NodeNameList ); if (macError) { LOG_ERROR("Unregister error: %d", macError); } dsDataListDeallocate(0, GlobalState.NodeNameList); free(GlobalState.NodeNameList); GlobalState.NodeNameList = NULL; } while (GlobalState.pGPOs) { pTemp = GlobalState.pGPOs; GlobalState.pGPOs = pTemp->pNext; pTemp->pNext = NULL; /* Remove node representing the GPO */ UnregisterGPONode(GlobalState.pszRealm, pTemp->pszDisplayName); GPA_SAFE_FREE_GPO_LIST(pTemp); } if ( GlobalState.pszRealm ) { LW_SAFE_FREE_STRING(GlobalState.pszRealm); GlobalState.pszRealm = NULL; } GlobalState.IsJoinedToAD = false; if ( GlobalState.pNetAdapterList ) { LWFreeNetAdapterList(GlobalState.pNetAdapterList); GlobalState.pNetAdapterList = NULL; } if ( GlobalState.DsRoot ) { dsCloseDirService( GlobalState.DsRoot ); GlobalState.DsRoot = 0; } if (GlobalState.pszCurrentAllowedAdminsList) { LW_SAFE_FREE_STRING(GlobalState.pszCurrentAllowedAdminsList); GlobalState.pszCurrentAllowedAdminsList = NULL; } if (GlobalState.pAllowAdminCheckData) { FreeAccessCheckData(GlobalState.pAllowAdminCheckData); GlobalState.pAllowAdminCheckData = NULL; } return macError; }
int trace_info_main( int argc, char* argv[] ) { DWORD dwError = 0; HANDLE hLsaConnection = (HANDLE)NULL; DWORD dwTraceFlag = 0; PLSA_TRACE_INFO pTraceFlag = NULL; PLSA_TRACE_INFO pTraceFlagArray = NULL; DWORD dwNumFlags = 0; size_t dwErrorBufferSize = 0; BOOLEAN bPrintOrigError = TRUE; if (argc > 1) { dwError = ParseArgs( argc, argv, &pTraceFlagArray, &dwNumFlags, &dwTraceFlag); BAIL_ON_LSA_ERROR(dwError); } if (pTraceFlagArray) { if (geteuid() != 0) { fprintf(stderr, "This program requires super-user privileges.\n"); dwError = LW_ERROR_ACCESS_DENIED; BAIL_ON_LSA_ERROR(dwError); } } dwError = LsaOpenServer(&hLsaConnection); BAIL_ON_LSA_ERROR(dwError); if (pTraceFlagArray) { dwError = LsaSetTraceFlags( hLsaConnection, pTraceFlagArray, dwNumFlags); BAIL_ON_LSA_ERROR(dwError); printf("The trace levels were set successfully\n\n"); } if (dwTraceFlag) { dwError = LsaGetTraceFlag( hLsaConnection, dwTraceFlag, &pTraceFlag); BAIL_ON_LSA_ERROR(dwError); dwError = PrintTraceInfo(pTraceFlag); BAIL_ON_LSA_ERROR(dwError); } if (dwTraceFlag && pTraceFlagArray) { DWORD iFlag = 0; dwError = LsaEnumTraceFlags( hLsaConnection, &pTraceFlagArray, &dwNumFlags); BAIL_ON_LSA_ERROR(dwError); for(; iFlag < dwNumFlags; iFlag++) { PLSA_TRACE_INFO pInfo = &pTraceFlagArray[iFlag]; dwError = PrintTraceInfo(pInfo); BAIL_ON_LSA_ERROR(dwError); } } cleanup: if (hLsaConnection != (HANDLE)NULL) { LsaCloseServer(hLsaConnection); } LW_SAFE_FREE_MEMORY(pTraceFlag); LW_SAFE_FREE_MEMORY(pTraceFlagArray); return (dwError); error: dwError = MapErrorCode(dwError); dwErrorBufferSize = LwGetErrorString(dwError, NULL, 0); if (dwErrorBufferSize > 0) { DWORD dwError2 = 0; PSTR pszErrorBuffer = NULL; dwError2 = LwAllocateMemory( dwErrorBufferSize, (PVOID*)&pszErrorBuffer); if (!dwError2) { DWORD dwLen = LwGetErrorString(dwError, pszErrorBuffer, dwErrorBufferSize); if ((dwLen == dwErrorBufferSize) && !LW_IS_NULL_OR_EMPTY_STR(pszErrorBuffer)) { fprintf( stderr, "Failed to manage trace flags. Error code %u (%s).\n%s\n", dwError, LW_PRINTF_STRING(LwWin32ExtErrorToName(dwError)), pszErrorBuffer); bPrintOrigError = FALSE; } } LW_SAFE_FREE_STRING(pszErrorBuffer); } if (bPrintOrigError) { fprintf( stderr, "Failed to manage trace flags. Error code %u (%s).\n", dwError, LW_PRINTF_STRING(LwWin32ExtErrorToName(dwError))); } goto cleanup; }
DWORD LsaAdBatchGatherPseudoObject( IN PAD_PROVIDER_DATA pProviderData, IN OUT PLSA_AD_BATCH_ITEM pItem, IN LSA_AD_BATCH_OBJECT_TYPE ObjectType, IN BOOLEAN bIsSchemaMode, IN OPTIONAL DWORD dwKeywordValuesCount, IN OPTIONAL PSTR* ppszKeywordValues, IN HANDLE hDirectory, IN LDAPMessage* pMessage ) { DWORD dwError = 0; PSTR pszComparePseudoDn = NULL; LSA_ASSERT(LSA_IS_XOR(LsaAdBatchIsDefaultSchemaMode(pProviderData), ppszKeywordValues)); SetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_HAVE_PSEUDO); dwError = LsaAdBatchGatherObjectType(pItem, ObjectType); BAIL_ON_LSA_ERROR(dwError); if (!pItem->pszSid) { dwError = LsaAdBatchGatherPseudoSid( &pItem->pszSid, pProviderData, dwKeywordValuesCount, ppszKeywordValues, hDirectory, pMessage); BAIL_ON_LSA_ERROR(dwError); } if (!pItem->pszPseudoDn) { dwError = LwLdapGetString( hDirectory, pMessage, AD_LDAP_DN_TAG, &pItem->pszPseudoDn); BAIL_ON_LSA_ERROR(dwError); if (LW_IS_NULL_OR_EMPTY_STR(pItem->pszPseudoDn)) { dwError = LW_ERROR_DATA_ERROR; BAIL_ON_LSA_ERROR(dwError); } } pItem->FoundPseudoCount++; if (pItem->FoundPseudoCount > 1) { dwError = LwLdapGetString( hDirectory, pMessage, AD_LDAP_DN_TAG, &pszComparePseudoDn); BAIL_ON_LSA_ERROR(dwError); LSA_LOG_WARNING("Found pseudo object %s that conflicts with pseudo object %s for SID %s", LSA_SAFE_LOG_STRING(pItem->pszPseudoDn), LSA_SAFE_LOG_STRING(pszComparePseudoDn), LSA_SAFE_LOG_STRING(pItem->pszSid)); dwError = LW_ERROR_DUPLICATE_USER_OR_GROUP; BAIL_ON_LSA_ERROR(dwError); } if (bIsSchemaMode) { dwError = LsaAdBatchGatherSchemaMode( pItem, hDirectory, pMessage); BAIL_ON_LSA_ERROR(dwError); // In default Schema mode, originally the following portion of code tries to gather real use information // using 'pMessage' obtained during pseudo objects lookup // However, a GC search is used on pseudo objects lookup, // Some of the attributes, such as user-specific attributes, i.e. 'accountExpires' etc. // are not available in GC. We still need to look up real objects in that particular domain for those missing attributes // Hence, we do not gather real object information until we actually do a real object lookup later on. #if 0 if (LsaAdBatchIsDefaultSchemaMode() && !IsSetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_HAVE_REAL)) { dwError = LsaAdBatchGatherRealObject( pItem, ObjectType, NULL, hDirectory, pMessage); BAIL_ON_LSA_ERROR(dwError); } #endif } else { dwError = LsaAdBatchGatherNonSchemaMode( pItem, dwKeywordValuesCount, ppszKeywordValues); BAIL_ON_LSA_ERROR(dwError); } cleanup: LW_SAFE_FREE_STRING(pszComparePseudoDn); return dwError; error: SetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ERROR); goto cleanup; }
static DWORD ParseTraceFlagArray( PCSTR pszArg, PLSA_TRACE_INFO* ppTraceFlagArray, PDWORD pdwNumFlags ) { DWORD dwError = 0; DWORD dwNumFlags = 0; DWORD iFlag = 0; size_t sFlagLen = 0; PCSTR pszInput = pszArg; PLSA_TRACE_INFO pTraceFlagArray = NULL; PSTR pszFlagAndValue = NULL; PSTR pszFlag = NULL; if (*pszArg == ',') { fprintf(stderr, "Error: Invalid argument [%s]\n", pszArg); dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } // Figure out how many flags there are while ((sFlagLen = strcspn(pszInput, ",")) != 0) { size_t sDelimiterLen = 0; pszInput += sFlagLen; sDelimiterLen = strspn(pszInput, ","); pszInput += sDelimiterLen; dwNumFlags++; } dwError = LwAllocateMemory( dwNumFlags * sizeof(LSA_TRACE_INFO), (PVOID*)&pTraceFlagArray); BAIL_ON_LSA_ERROR(dwError); pszInput = pszArg; while ((sFlagLen = strcspn(pszInput, ",")) != 0) { size_t sDelimiterLen = 0; PCSTR pszIndex = NULL; LW_SAFE_FREE_STRING(pszFlagAndValue); dwError = LwStrndup( pszInput, sFlagLen, &pszFlagAndValue); BAIL_ON_LSA_ERROR(dwError); if (!(pszIndex = strchr(pszFlagAndValue, ':')) || LW_IS_NULL_OR_EMPTY_STR(pszIndex+1) || (strcmp(pszIndex+1, "0") && strcmp(pszIndex + 1, "1"))) { fprintf(stderr, "Error: Invalid value specified for trace flag [%s]\n", pszFlagAndValue); dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } else if (pszIndex == pszFlagAndValue) { fprintf(stderr, "Error: No name specified for trace flag [%s]\n", pszFlagAndValue); dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } else { PLSA_TRACE_INFO pTraceFlag = NULL; LW_SAFE_FREE_STRING(pszFlag); dwError = LwStrndup( pszFlagAndValue, (pszIndex - pszFlagAndValue), &pszFlag); BAIL_ON_LSA_ERROR(dwError); pTraceFlag = &pTraceFlagArray[iFlag]; dwError = ParseTraceFlag( pszFlag, &pTraceFlag->dwTraceFlag); BAIL_ON_LSA_ERROR(dwError); pTraceFlag->bStatus = atoi(pszIndex + 1); } pszInput += sFlagLen; sDelimiterLen = strspn(pszInput, ","); pszInput += sDelimiterLen; iFlag++; } *ppTraceFlagArray = pTraceFlagArray; *pdwNumFlags = dwNumFlags; cleanup: LW_SAFE_FREE_STRING(pszFlag); LW_SAFE_FREE_STRING(pszFlagAndValue); return dwError; error: *ppTraceFlagArray = NULL; *pdwNumFlags = 0; LW_SAFE_FREE_MEMORY(pTraceFlagArray); goto cleanup; }
DWORD LsaPamGetLoginId( pam_handle_t* pamh, PPAMCONTEXT pPamContext, PSTR* ppszLoginId, BOOLEAN bAllowPrompt ) { DWORD dwError = 0; PSTR pszLoginId = NULL; PSTR pszPamId = NULL; int iPamError = 0; LSA_LOG_PAM_DEBUG("LsaPamGetLoginId::begin"); iPamError = pam_get_item( pamh, PAM_USER, (PAM_GET_ITEM_TYPE)&pszPamId); dwError = LsaPamUnmapErrorCode(iPamError); #if defined(HAVE_DECL_PAM_BAD_ITEM) || defined(PAM_BAD_ITEM) if (dwError == LsaPamUnmapErrorCode(PAM_BAD_ITEM)) { pszPamId = NULL; dwError = 0; } #endif BAIL_ON_LSA_ERROR(dwError); if (LW_IS_NULL_OR_EMPTY_STR(pszPamId) && bAllowPrompt) { iPamError = pam_get_user( pamh, (PPCHAR_ARG_CAST)&pszPamId, NULL); dwError = LsaPamUnmapErrorCode(iPamError); if (dwError) { dwError = (dwError == LsaPamUnmapErrorCode(PAM_CONV_AGAIN)) ? LsaPamUnmapErrorCode(PAM_INCOMPLETE) : LsaPamUnmapErrorCode(PAM_SERVICE_ERR); BAIL_ON_LSA_ERROR(dwError); } if (LW_IS_NULL_OR_EMPTY_STR(pszPamId)) { dwError = LsaPamUnmapErrorCode(PAM_SERVICE_ERR); BAIL_ON_LSA_ERROR(dwError); } } dwError = LwStrDupOrNull( pszPamId, &pszLoginId); BAIL_ON_LSA_ERROR(dwError); LW_SAFE_FREE_STRING(pPamContext->pszLoginName); dwError = LwStrDupOrNull(pszPamId, &pPamContext->pszLoginName); BAIL_ON_LSA_ERROR(dwError); if (ppszLoginId) { *ppszLoginId = pszLoginId; } else { LW_SAFE_FREE_STRING(pszLoginId); } cleanup: LSA_LOG_PAM_DEBUG("LsaPamGetLoginId::end"); return dwError; error: LW_SAFE_FREE_STRING(pszLoginId); if (ppszLoginId) { *ppszLoginId = NULL; } LSA_LOG_PAM_ERROR("LsaPamGetLoginId failed [error code: %u]", dwError); goto cleanup; }
static DWORD RemoveSambaLoadPath( IN HANDLE hReg ) { DWORD type = 0; HKEY hKey = NULL; DWORD error = 0; DWORD loadOrderSize = 0; PSTR pLoadOrder = NULL; // Do not free PSTR pPos = NULL; BOOLEAN removedSamba = FALSE; error = LwRegOpenKeyExA( hReg, NULL, LSA_PSTORE_REG_KEY_PATH_PLUGINS, 0, KEY_WRITE, &hKey); BAIL_ON_LSA_ERROR(error); error = LwRegGetValueA( hReg, hKey, NULL, "LoadOrder", RRF_RT_REG_MULTI_SZ, &type, NULL, &loadOrderSize); if (error == LWREG_ERROR_NO_SUCH_KEY_OR_VALUE) { LW_RTL_LOG_INFO("LoadOrder key not present"); error = 0; goto cleanup; } BAIL_ON_LSA_ERROR(error); error = LwAllocateMemory(loadOrderSize, (PVOID*) &pLoadOrder); BAIL_ON_LSA_ERROR(error); error = LwRegGetValueA( hReg, hKey, NULL, "LoadOrder", RRF_RT_REG_MULTI_SZ, &type, pLoadOrder, &loadOrderSize); BAIL_ON_LSA_ERROR(error); pPos = pLoadOrder; while (pPos[0]) { DWORD valueLen = strlen(pPos) + 1; if (!strcmp(pPos, PLUGIN_NAME)) { loadOrderSize -= valueLen; memmove( pPos, pPos + valueLen, valueLen); removedSamba = TRUE; } else { pPos += valueLen; } } if (removedSamba) { LW_RTL_LOG_INFO("Removed Samba from load order"); error = LwRegSetValueExA( hReg, hKey, "LoadOrder", 0, REG_MULTI_SZ, (const BYTE*)pLoadOrder, loadOrderSize); BAIL_ON_LSA_ERROR(error); } cleanup: if (hKey != NULL) { LwRegCloseKey( hReg, hKey); } LW_SAFE_FREE_STRING(pLoadOrder); return error; }
DWORD LwKrb5InitializeUserLoginCredentials( IN PCSTR pszUserPrincipalName, IN PCSTR pszPassword, IN uid_t uid, IN gid_t gid, IN LW_KRB5_LOGIN_FLAGS Flags, IN PCSTR pszServicePrincipal, IN PCSTR pszServiceRealm, IN PCSTR pszServicePassword, OUT PVOID* ppNdrPacInfo, OUT size_t* pNdrPacInfoSize, OUT PDWORD pdwGoodUntilTime ) { DWORD dwError = 0; krb5_error_code ret = 0; krb5_context ctx = NULL; krb5_ccache cc = NULL; // Free with krb5_free_cred_contents krb5_creds credsRequest = {0}; krb5_creds *pTgsCreds = NULL; krb5_ticket *pTgsTicket = NULL; krb5_ticket *pDecryptedTgs = NULL; krb5_auth_context authContext = NULL; krb5_data apReqPacket = {0}; krb5_keyblock serviceKey = {0}; krb5_data salt = {0}; // Do not free krb5_data machinePassword = {0}; krb5_flags flags = 0; krb5_int32 authcon_flags = 0; BOOLEAN bInLock = FALSE; PCSTR pszTempCacheName = NULL; PSTR pszTempCachePath = NULL; PVOID pNdrPacInfo = NULL; size_t ndrPacInfoSize = 0; DWORD dwGoodUntilTime = 0; ret = krb5_init_context(&ctx); BAIL_ON_KRB_ERROR(ctx, ret); /* Generates a new filed based credentials cache in /tmp. The file will * be owned by root and only accessible by root. */ ret = krb5_cc_new_unique( ctx, "FILE", "hint", &cc); BAIL_ON_KRB_ERROR(ctx, ret); if (Flags & LW_KRB5_LOGIN_FLAG_SMART_CARD) { dwError = LwKrb5GetTgtWithSmartCard( pszUserPrincipalName, pszPassword, krb5_cc_get_name(ctx, cc), &dwGoodUntilTime); } else { dwError = LwKrb5GetTgt( pszUserPrincipalName, pszPassword, krb5_cc_get_name(ctx, cc), &dwGoodUntilTime); } BAIL_ON_LW_ERROR(dwError); ret = krb5_parse_name(ctx, pszServicePrincipal, &credsRequest.server); BAIL_ON_KRB_ERROR(ctx, ret); ret = krb5_cc_get_principal(ctx, cc, &credsRequest.client); BAIL_ON_KRB_ERROR(ctx, ret); /* Get a TGS for our service using the tgt in the cache */ ret = krb5_get_credentials( ctx, 0, /*no options (not user to user encryption, and not only cached) */ cc, &credsRequest, &pTgsCreds); // Don't trust pTgsCreds on an unsuccessful return // This may be non-zero due to the krb5 libs following referrals // but has been freed in the krb5 libs themselves and any useful // tickets have already been cached. if (ret != 0) { pTgsCreds = NULL; } BAIL_ON_KRB_ERROR(ctx, ret); //No need to store the tgs in the cc. Kerberos does that automatically /* Generate an ap_req message, but don't send it anywhere. Just decode it * immediately. This is the only way to get kerberos to decrypt the tgs * using public APIs */ ret = krb5_mk_req_extended( ctx, &authContext, 0, /* no options necessary */ NULL, /* since this isn't a real ap_req, we don't have any supplemental data to send with it. */ pTgsCreds, &apReqPacket); BAIL_ON_KRB_ERROR(ctx, ret); /* Decode (but not decrypt) the tgs ticket so that we can figure out * which encryption type was used in it. */ ret = krb5_decode_ticket(&pTgsCreds->ticket, &pTgsTicket); /* The TGS ticket is encrypted with the machine password and salted with * the service principal. pszServicePrincipal could probably be used * directly, but it's safer to unparse pTgsCreds->server, because the KDC * sent that to us. */ salt.magic = KV5M_DATA; ret = krb5_unparse_name( ctx, pTgsCreds->server, &salt.data); BAIL_ON_KRB_ERROR(ctx, ret); salt.length = strlen(salt.data); machinePassword.magic = KV5M_DATA; machinePassword.data = (PSTR)pszServicePassword, machinePassword.length = strlen(pszServicePassword), /* Generate a key to decrypt the TGS */ ret = krb5_c_string_to_key( ctx, pTgsTicket->enc_part.enctype, &machinePassword, &salt, &serviceKey); BAIL_ON_KRB_ERROR(ctx, ret); /* Typically krb5_rd_req would decode the AP_REQ using the keytab, but * we don't want to depend on the keytab. As a side effect of kerberos' * user to user authentication support, if a key is explictly set on the * auth context, that key will be used to decrypt the TGS instead of the * keytab. * * By manually generating the key and setting it, we don't require * a keytab. */ if (authContext != NULL) { ret = krb5_auth_con_free(ctx, authContext); BAIL_ON_KRB_ERROR(ctx, ret); } ret = krb5_auth_con_init(ctx, &authContext); BAIL_ON_KRB_ERROR(ctx, ret); ret = krb5_auth_con_setuseruserkey( ctx, authContext, &serviceKey); BAIL_ON_KRB_ERROR(ctx, ret); /* Disable replay detection which is unnecessary and * can fail when authenticating large numbers of users. */ krb5_auth_con_getflags(ctx, authContext, &authcon_flags); krb5_auth_con_setflags(ctx, authContext, authcon_flags & ~KRB5_AUTH_CONTEXT_DO_TIME); if (pszServiceRealm) { ret = krb5_set_default_realm(ctx, pszServiceRealm); BAIL_ON_KRB_ERROR(ctx, ret); } /* This decrypts the TGS. As a side effect it ensures that the KDC that * the user's TGT came from is in the same realm that the machine was * joined to (this prevents users from spoofing the KDC). */ ret = krb5_rd_req( ctx, &authContext, &apReqPacket, pTgsCreds->server, NULL, /* we're not using the keytab */ &flags, &pDecryptedTgs); BAIL_ON_KRB_ERROR(ctx, ret); dwError = LwKrb5FindPac( ctx, pDecryptedTgs, &serviceKey, &pNdrPacInfo, &ndrPacInfoSize); BAIL_ON_LW_ERROR(dwError); if (Flags & LW_KRB5_LOGIN_FLAG_UPDATE_CACHE) { /* 1. Copy old credentials from the existing user creds cache to * the temporary cache. * 2. Delete the existing creds cache. * 3. Move the temporary cache file into the final path. */ dwError = pthread_mutex_lock(&gLwKrb5State.UserCacheMutex); BAIL_ON_LW_ERROR(dwError); bInLock = TRUE; dwError = LwKrb5CopyFromUserCache( ctx, cc, uid ); BAIL_ON_LW_ERROR(dwError); pszTempCacheName = krb5_cc_get_name(ctx, cc); if (!strncasecmp(pszTempCacheName, "FILE:", sizeof("FILE:")-1)) { pszTempCacheName += sizeof("FILE:") - 1; } dwError = LwAllocateString(pszTempCacheName, &pszTempCachePath); BAIL_ON_LW_ERROR(dwError); krb5_cc_close(ctx, cc); // Just to make sure no one accesses this now invalid pointer cc = NULL; dwError = LwKrb5MoveCCacheToUserPath( ctx, pszTempCachePath, uid, gid); if (dwError != LW_ERROR_SUCCESS) { /* Let the user login, even if we couldn't create the ccache for * them. Possible causes are: * 1. /tmp is readonly * 2. Another user maliciously setup a weird file (such as a * directory) where the ccache would go. * 3. Someone created a ccache in the small window after we delete * the old one and before we move in the new one. */ LW_RTL_LOG_WARNING("Unable to set up credentials cache with tgt for uid %ld", (long)uid); dwError = LwRemoveFile(pszTempCachePath); BAIL_ON_LW_ERROR(dwError); } } error: if (dwError) { LW_SAFE_FREE_MEMORY(pNdrPacInfo); ndrPacInfoSize = 0; dwGoodUntilTime = 0; } if (ctx) { // This function skips fields which are NULL krb5_free_cred_contents(ctx, &credsRequest); if (pTgsCreds != NULL) { krb5_free_creds(ctx, pTgsCreds); } if (pTgsTicket != NULL) { krb5_free_ticket(ctx, pTgsTicket); } if (pDecryptedTgs != NULL) { krb5_free_ticket(ctx, pDecryptedTgs); } if (authContext != NULL) { krb5_auth_con_free(ctx, authContext); } krb5_free_data_contents(ctx, &apReqPacket); krb5_free_data_contents(ctx, &salt); krb5_free_keyblock_contents(ctx, &serviceKey); if (cc != NULL) { krb5_cc_destroy(ctx, cc); } krb5_free_context(ctx); } if (bInLock) { pthread_mutex_unlock(&gLwKrb5State.UserCacheMutex); } LW_SAFE_FREE_STRING(pszTempCachePath); *ppNdrPacInfo = pNdrPacInfo; *pNdrPacInfoSize = ndrPacInfoSize; *pdwGoodUntilTime = dwGoodUntilTime; return dwError; }
DWORD FindFileInPath( PCSTR pFilename, PCSTR pSearchPath, PSTR* ppFoundPath ) { DWORD error = ERROR_SUCCESS; //Copy the search path so that strtok can be run on it PSTR pMySearchPath = NULL; PSTR pStrtokSavePtr = NULL; PSTR pCurrentDir = NULL; PSTR pTestPath = NULL; BOOLEAN exists = FALSE; if (ppFoundPath != NULL) { *ppFoundPath = NULL; } error = LwAllocateString(pSearchPath, &pMySearchPath); BAIL_ON_LSA_ERROR(error); pCurrentDir = strtok_r(pMySearchPath, ":", &pStrtokSavePtr); while (TRUE) { LW_SAFE_FREE_STRING(pTestPath); error = LwAllocateStringPrintf( &pTestPath, "%s/%s", pCurrentDir, pFilename); error = LwCheckFileTypeExists( pTestPath, LWFILE_REGULAR, &exists); BAIL_ON_LSA_ERROR(error); if (!exists) { error = LwCheckFileTypeExists( pTestPath, LWFILE_SYMLINK, &exists); BAIL_ON_LSA_ERROR(error); } if (!exists) { error = LwCheckFileTypeExists( pTestPath, LWFILE_DIRECTORY, &exists); BAIL_ON_LSA_ERROR(error); } if (exists) { if (ppFoundPath != NULL) { *ppFoundPath = pTestPath; pTestPath = NULL; } break; } pCurrentDir = strtok_r(NULL, ":", &pStrtokSavePtr); if(pCurrentDir == NULL) { error = ERROR_FILE_NOT_FOUND; BAIL_ON_LSA_ERROR(error); } } cleanup: LW_SAFE_FREE_STRING(pMySearchPath); LW_SAFE_FREE_STRING(pTestPath); return error; }
static DWORD LwGssGetSingleErrorMessage( OUT PSTR* ppszErrorMessage, IN OM_uint32 Status, IN BOOLEAN IsMajor ) { DWORD dwError = 0; PSTR pszErrorMessage = NULL; OM_uint32 majorStatus = 0; OM_uint32 minorStatus = 0; gss_buffer_desc message = GSS_C_EMPTY_BUFFER; OM_uint32 messageContext = 0; int statusType = IsMajor ? GSS_C_GSS_CODE : GSS_C_MECH_CODE; do { majorStatus = gss_display_status( &minorStatus, Status, statusType, GSS_C_NULL_OID, &messageContext, &message); if (majorStatus != GSS_S_COMPLETE) { LW_RTL_LOG_ERROR("Call to gss_display_status() failed with " "majorStatus = 0x%08x, minorStatus = 0x%08x", majorStatus, minorStatus); dwError = ERROR_INTERNAL_ERROR; BAIL_ON_LW_ERROR(dwError); } if (!pszErrorMessage) { dwError = LwAllocateString((PSTR)message.value, &pszErrorMessage); BAIL_ON_LW_ERROR(dwError); } else { PSTR pszNewErrorMessage = NULL; dwError = LwAllocateStringPrintf(&pszNewErrorMessage, "%s; %s", pszErrorMessage, (PSTR)message.value); BAIL_ON_LW_ERROR(dwError); LW_SAFE_FREE_STRING(pszErrorMessage); pszErrorMessage = pszNewErrorMessage; } majorStatus = gss_release_buffer(&minorStatus, &message); } while (messageContext); error: if (dwError) { LW_SAFE_FREE_STRING(pszErrorMessage); } if (message.value) { majorStatus = gss_release_buffer(&minorStatus, &message); } *ppszErrorMessage = pszErrorMessage; return dwError; }
DWORD CaptureOutputWithStderr( PCSTR pCommand, PCSTR* ppArgs, PSTR* ppOutput, int *pExitCode ) { DWORD error = ERROR_SUCCESS; size_t bufferCapacity = 1024; ssize_t inBuffer = 0; ssize_t readCount = 0; int pipeFds[2] = { -1, -1 }; pid_t pid = -1; int status = 0; PSTR pTempOutput = NULL; // Do not free PSTR pNewOutput = NULL; if (ppOutput != NULL) { *ppOutput = NULL; } if (pipe(pipeFds)) { error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } pid = fork(); if (pid < 0) { error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } else if (pid == 0) { // Child process if (dup2(pipeFds[1], STDOUT_FILENO) < 0) { abort(); } if (dup2(pipeFds[1], STDERR_FILENO) < 0) { abort(); } if (close(pipeFds[0])) { abort(); } if (close(pipeFds[1])) { abort(); } execvp(pCommand, (char **)ppArgs); abort(); } if (close(pipeFds[1])) { pipeFds[1] = -1; error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } pipeFds[1] = -1; error = LwAllocateMemory(bufferCapacity, (PVOID*) &pTempOutput); BAIL_ON_LSA_ERROR(error); while ((readCount = read(pipeFds[0], pTempOutput + inBuffer, bufferCapacity - inBuffer)) > 0) { inBuffer += readCount; if (inBuffer == bufferCapacity) { bufferCapacity *= 2; error = LwReallocMemory( pTempOutput, (PVOID*)&pNewOutput, bufferCapacity); BAIL_ON_LSA_ERROR(error); pTempOutput = pNewOutput; } } if (readCount < 0) { error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } if (close(pipeFds[0]) < 0) { pipeFds[0] = -1; error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } pipeFds[0] = -1; if (waitpid(pid, &status, 0) != pid) { error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } if (ppOutput != NULL) { *ppOutput = pTempOutput; pTempOutput = NULL; } if (pExitCode != NULL) { *pExitCode = WEXITSTATUS(status); } else if (status) { error = ERROR_BAD_COMMAND; BAIL_ON_LSA_ERROR(error); } cleanup: if (pipeFds[0] >= 0) { close(pipeFds[0]); } if (pipeFds[1] >= 0) { close(pipeFds[1]); } LW_SAFE_FREE_STRING(pTempOutput); return error; }
DWORD LwKrb5CopyFromUserCache( krb5_context ctx, krb5_ccache destCC, uid_t uid ) { DWORD dwError = LW_ERROR_SUCCESS; PSTR pszCachePath = NULL; krb5_ccache srcCC = NULL; krb5_cc_cursor srcPos = NULL; krb5_cc_cursor destPos = NULL; // Free with krb5_free_cred_contents krb5_creds srcCreds = {0}; // Free with krb5_free_cred_contents krb5_creds destCreds = {0}; krb5_error_code ret = 0; krb5_principal destClient = 0; BOOLEAN bIncludeTicket = TRUE; DWORD dwTime = 0; ret = krb5_cc_get_principal( ctx, destCC, &destClient); BAIL_ON_KRB_ERROR(ctx, ret); dwError = LwKrb5GetUserCachePath( uid, KRB5_File_Cache, &pszCachePath); BAIL_ON_LW_ERROR(dwError); ret = krb5_cc_resolve( ctx, pszCachePath, &srcCC); BAIL_ON_KRB_ERROR(ctx, ret); ret = krb5_cc_start_seq_get( ctx, srcCC, &srcPos); if (ret == KRB5_FCC_NOFILE) { // The cache file does not exist ret = 0; goto cleanup; } if (ret == KRB5_CC_FORMAT) { // Some other user put a bad cc in place - don't copy anything // from it. ret = 0; goto cleanup; } BAIL_ON_KRB_ERROR(ctx, ret); dwTime = time(NULL); while (1) { krb5_free_cred_contents( ctx, &srcCreds); ret = krb5_cc_next_cred( ctx, srcCC, &srcPos, &srcCreds); if (ret == KRB5_CC_FORMAT) { break; } else if (ret == KRB5_CC_END) { break; } else { BAIL_ON_KRB_ERROR(ctx, ret); } if (!krb5_principal_compare(ctx, destClient, srcCreds.client)) { /* Can't keep these creds. The client principal doesn't * match. */ continue; } if ( srcCreds.times.endtime < dwTime ) { /* Credentials are too old. */ continue; } if (destPos != NULL) { krb5_cc_end_seq_get( ctx, destCC, &destPos); destPos = NULL; } ret = krb5_cc_start_seq_get( ctx, destCC, &destPos); BAIL_ON_KRB_ERROR(ctx, ret); bIncludeTicket = TRUE; while(bIncludeTicket) { krb5_free_cred_contents( ctx, &destCreds); ret = krb5_cc_next_cred( ctx, destCC, &destPos, &destCreds); if (ret == KRB5_CC_END) { break; } else { BAIL_ON_KRB_ERROR(ctx, ret); } if (krb5_principal_compare( ctx, destCreds.server, srcCreds.server)) { /* These credentials are already in the dest cache */ bIncludeTicket = FALSE; } } if (bIncludeTicket) { // These creds can go in the new cache ret = krb5_cc_store_cred(ctx, destCC, &srcCreds); BAIL_ON_KRB_ERROR(ctx, ret); } } cleanup: LW_SAFE_FREE_STRING(pszCachePath); if (ctx != NULL) { if (srcPos != NULL) { krb5_cc_end_seq_get( ctx, srcCC, &srcPos); } if (destPos != NULL) { krb5_cc_end_seq_get( ctx, destCC, &destPos); } if (srcCC != NULL) { krb5_cc_close(ctx, srcCC); } krb5_free_cred_contents(ctx, &srcCreds); krb5_free_cred_contents(ctx, &destCreds); if (destClient != NULL) { krb5_free_principal(ctx, destClient); } } return dwError; error: goto cleanup; }
DWORD CheckSambaVersion( PCSTR pSmbdPath ) { DWORD error = 0; PCSTR ppArgs[] = { pSmbdPath, "-V", 0 }; PSTR pVersionString = NULL; error = CaptureOutputWithStderr( pSmbdPath, ppArgs, &pVersionString, NULL); BAIL_ON_LSA_ERROR(error); if (!strncmp(pVersionString, "Version ", sizeof("Version ") -1)) { memmove( pVersionString, pVersionString + (sizeof("Version ") - 1), strlen(pVersionString) - (sizeof("Version ") - 1) + 1); } LwStripWhitespace( pVersionString, TRUE, TRUE); LW_RTL_LOG_ERROR("Found smbd version %s", pVersionString); if (!strncmp(pVersionString, "3.2.", sizeof("3.2.") - 1)) { } else if (!strncmp(pVersionString, "3.4.", sizeof("3.4.") - 1)) { } else if (!strncmp(pVersionString, "3.5.", sizeof("3.5.") - 1)) { } else if (!strncmp(pVersionString, "3.0.", sizeof("3.0.") - 1)) { int build = 0; sscanf(pVersionString, "3.0.%d.", &build); if (build < 25) { LW_RTL_LOG_ERROR("Unsupported smbd version %s", pVersionString); error = ERROR_PRODUCT_VERSION; BAIL_ON_LSA_ERROR(error); } } else { LW_RTL_LOG_ERROR("Unsupported smbd version %s", pVersionString); error = ERROR_PRODUCT_VERSION; BAIL_ON_LSA_ERROR(error); } cleanup: LW_SAFE_FREE_STRING(pVersionString); return error; }
DWORD LwKrb5VerifyPac( krb5_context ctx, const krb5_ticket *pTgsTicket, const struct berval *pPacBerVal, const krb5_keyblock *serviceKey, char** ppchLogonInfo, size_t* psLogonInfo ) { krb5_error_code ret = 0; PAC_DATA *pPacData = NULL; DWORD i; char *pchPacCopy = NULL; //Do not free krb5_data krbPacData = {0}; //Do not free krb5_checksum checksum = {0}; //Do not free PAC_SIGNATURE_DATA *pServerSig = NULL; PAC_LOGON_NAME *pLogonName = NULL; size_t sServerSig = 0; //Do not free char *pchLogonInfoStart = NULL; size_t sLogonInfoLen = 0; krb5_boolean bHasGoodChecksum = FALSE; uint64_t qwNtAuthTime; DWORD dwError = LW_ERROR_SUCCESS; //Free with krb5_free_unparsed_name PSTR pszClientPrincipal = NULL; PSTR pszLogonName = NULL; char* pchLogonInfo = NULL; #if defined(WORDS_BIGENDIAN) WORD * pwNameLocal = NULL; DWORD dwCount = 0; #endif dwError = LwAllocateMemory( pPacBerVal->bv_len, OUT_PPVOID(&pPacData)); BAIL_ON_LW_ERROR(dwError); memcpy(pPacData, pPacBerVal->bv_val, pPacBerVal->bv_len); #if defined(WORDS_BIGENDIAN) pPacData->dwBufferCount = LW_ENDIAN_SWAP32(pPacData->dwBufferCount); pPacData->dwVersion = LW_ENDIAN_SWAP32(pPacData->dwVersion); #endif // We only know about version 0 if (pPacData->dwVersion != 0) { dwError = LW_ERROR_INVALID_MESSAGE; BAIL_ON_LW_ERROR(dwError); } // Make sure that the last buffer in the pac data doesn't go out of bounds // of the parent buffer if ((void *)&pPacData->buffers[pPacData->dwBufferCount] - (void *)pPacData > pPacBerVal->bv_len) { dwError = LW_ERROR_INVALID_MESSAGE; BAIL_ON_LW_ERROR(dwError); } // Make sure the data associated with each buffer doesn't go out of // bounds for (i = 0; i < pPacData->dwBufferCount; i++) { #if defined(WORDS_BIGENDIAN) pPacData->buffers[i].dwType = LW_ENDIAN_SWAP32(pPacData->buffers[i].dwType); pPacData->buffers[i].dwSize = LW_ENDIAN_SWAP32(pPacData->buffers[i].dwSize); pPacData->buffers[i].qwOffset = LW_ENDIAN_SWAP64(pPacData->buffers[i].qwOffset); #endif if (pPacData->buffers[i].qwOffset + pPacData->buffers[i].dwSize < pPacData->buffers[i].qwOffset) { dwError = LW_ERROR_INVALID_MESSAGE; BAIL_ON_LW_ERROR(dwError); } if (pPacData->buffers[i].qwOffset + pPacData->buffers[i].dwSize > pPacBerVal->bv_len) { dwError = LW_ERROR_INVALID_MESSAGE; BAIL_ON_LW_ERROR(dwError); } } dwError = LwAllocateMemory( pPacBerVal->bv_len, OUT_PPVOID(&pchPacCopy)); BAIL_ON_LW_ERROR(dwError); memcpy(pchPacCopy, pPacBerVal->bv_val, pPacBerVal->bv_len); krbPacData.magic = KV5M_DATA; krbPacData.length = pPacBerVal->bv_len; krbPacData.data = pchPacCopy; for (i = 0; i < pPacData->dwBufferCount; i++) { switch (pPacData->buffers[i].dwType) { case PAC_TYPE_LOGON_INFO: pchLogonInfoStart = (char *)pPacData + pPacData->buffers[i].qwOffset; sLogonInfoLen = pPacData->buffers[i].dwSize; break; case PAC_TYPE_SRV_CHECKSUM: pServerSig = (PAC_SIGNATURE_DATA *)((char *)pPacData + pPacData->buffers[i].qwOffset); #if defined(WORDS_BIGENDIAN) pServerSig->dwType = LW_ENDIAN_SWAP32(pServerSig->dwType); #endif sServerSig = pPacData->buffers[i].dwSize - (size_t)&((PAC_SIGNATURE_DATA *)0)->pchSignature; /* The checksum is calculated with the signatures zeroed out. */ memset(pchPacCopy + pPacData->buffers[i].qwOffset + (size_t)&((PAC_SIGNATURE_DATA *)0)->pchSignature, 0, pPacData->buffers[i].dwSize - (size_t)&((PAC_SIGNATURE_DATA *)0)->pchSignature); break; case PAC_TYPE_KDC_CHECKSUM: /* The checksum is calculated with the signatures zeroed out. */ memset(pchPacCopy + pPacData->buffers[i].qwOffset + (size_t)&((PAC_SIGNATURE_DATA *)0)->pchSignature, 0, pPacData->buffers[i].dwSize - (size_t)&((PAC_SIGNATURE_DATA *)0)->pchSignature); break; case PAC_TYPE_LOGON_NAME: pLogonName = (PAC_LOGON_NAME *)((char *)pPacData + pPacData->buffers[i].qwOffset); #if defined(WORDS_BIGENDIAN) pLogonName->ticketTime = LW_ENDIAN_SWAP64(pLogonName->ticketTime); pLogonName->wAccountNameLen = LW_ENDIAN_SWAP16(pLogonName->wAccountNameLen); pwNameLocal = pLogonName->pwszName; for ( dwCount = 0 ; dwCount < pLogonName->wAccountNameLen / 2 ; dwCount++ ) { pwNameLocal[dwCount] = LW_ENDIAN_SWAP16(pwNameLocal[dwCount]); } #endif if ((char *)&pLogonName->pwszName + pLogonName->wAccountNameLen > (char *)pPacData + pPacData->buffers[i].qwOffset + pPacData->buffers[i].dwSize) { // The message is invalid because the terminating null // of the name lands outside of the buffer. dwError = LW_ERROR_INVALID_MESSAGE; BAIL_ON_LW_ERROR(dwError); } break; default: break; } } if (pServerSig == NULL) { dwError = LW_ERROR_INVALID_MESSAGE; BAIL_ON_LW_ERROR(dwError); } if (pLogonName == NULL) { //We need the logon name to verify the pac is for the right user dwError = LW_ERROR_INVALID_MESSAGE; BAIL_ON_LW_ERROR(dwError); } if (pchLogonInfoStart == NULL) { /* The buffer we really care about isn't in the pac. */ dwError = LW_ERROR_INVALID_MESSAGE; BAIL_ON_LW_ERROR(dwError); } checksum.magic = KV5M_CHECKSUM; checksum.checksum_type = pServerSig->dwType; checksum.length = sServerSig; checksum.contents = (unsigned char *)pServerSig->pchSignature; ret = krb5_c_verify_checksum( ctx, serviceKey, KRB5_KEYUSAGE_APP_DATA_CKSUM, &krbPacData, &checksum, &bHasGoodChecksum); BAIL_ON_KRB_ERROR(ctx, ret); if (!bHasGoodChecksum) { dwError = LW_ERROR_INVALID_MESSAGE; BAIL_ON_LW_ERROR(dwError); } // Make sure the pac was issued with this ticket, not an old ticket qwNtAuthTime = pTgsTicket->enc_part2->times.authtime; qwNtAuthTime += 11644473600LL; qwNtAuthTime *= 1000*1000*10; if (pLogonName->ticketTime != qwNtAuthTime) { dwError = LW_ERROR_CLOCK_SKEW; BAIL_ON_LW_ERROR(dwError); } ret = krb5_unparse_name( ctx, pTgsTicket->enc_part2->client, &pszClientPrincipal); BAIL_ON_KRB_ERROR(ctx, ret); // Strip off the domain name if (strchr(pszClientPrincipal, '@') != NULL) { strchr(pszClientPrincipal, '@')[0] = '\0'; } dwError = LwWc16snToMbs( pLogonName->pwszName, &pszLogonName, pLogonName->wAccountNameLen / 2); BAIL_ON_LW_ERROR(dwError); if (strcasecmp(pszClientPrincipal, pszLogonName)) { // The pac belongs to a different user dwError = LW_ERROR_INVALID_LOGIN_ID; BAIL_ON_LW_ERROR(dwError); } dwError = LwAllocateMemory( sLogonInfoLen, OUT_PPVOID(&pchLogonInfo)); BAIL_ON_LW_ERROR(dwError); memcpy(pchLogonInfo, pchLogonInfoStart, sLogonInfoLen); *ppchLogonInfo = pchLogonInfo; *psLogonInfo = sLogonInfoLen; cleanup: LW_SAFE_FREE_STRING(pszLogonName); LW_SAFE_FREE_MEMORY(pPacData); LW_SAFE_FREE_MEMORY(pchPacCopy); if (pszClientPrincipal != NULL) { krb5_free_unparsed_name(ctx, pszClientPrincipal); } return dwError; error: LW_SAFE_FREE_MEMORY(pchLogonInfo); *ppchLogonInfo = NULL; goto cleanup; }
DWORD UninstallWbclient( PCSTR pSmbdPath ) { DWORD error = 0; PSTR pSambaDir = NULL; PSTR pWbClient = NULL; PSTR pWbClientOriginal = NULL; PCSTR pLikewiseWbClient = LIBDIR "/" WBCLIENT_FILENAME; char pBuffer[1024] = { 0 }; struct stat statBuf = { 0 }; error = GetWbclientDir( pSmbdPath, &pSambaDir); BAIL_ON_LSA_ERROR(error); error = LwAllocateStringPrintf( &pWbClient, "%s/%s", pSambaDir, WBCLIENT_FILENAME ); BAIL_ON_LSA_ERROR(error); if (readlink(pWbClient, pBuffer, sizeof(pBuffer)) < 0) { switch(errno) { // File does not exist case ENOENT: // Not a symbolic link case EINVAL: pBuffer[0] = 0; break; default: error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } } pBuffer[sizeof(pBuffer) - 1] = 0; if (strcmp(pBuffer, pLikewiseWbClient)) { LW_RTL_LOG_INFO("Path %s is not a symbolic link or does not point to %s", pWbClient, pLikewiseWbClient); // Already configured goto cleanup; } error = LwAllocateStringPrintf( &pWbClientOriginal, "%s.lwidentity.orig", pWbClient ); BAIL_ON_LSA_ERROR(error); if (unlink(pWbClient) < 0) { error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } if (stat(pWbClientOriginal, &statBuf) < 0) { if (errno == ENOENT) { // This is probably Samba 3.0.x, and it did not have an original // libwbclient.so. } else { LW_RTL_LOG_ERROR("Cannot find original wbclient library at %s", pWbClientOriginal); error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } } else { if (symlink(pWbClientOriginal, pWbClient) < 0) { error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } LW_RTL_LOG_INFO("Linked %s to %s", pWbClient, pLikewiseWbClient); } cleanup: LW_SAFE_FREE_STRING(pSambaDir); LW_SAFE_FREE_STRING(pWbClient); LW_SAFE_FREE_STRING(pWbClientOriginal); return error; }
long LWIAttrValDataQuery::QueryComputerGroupInformation(LWIQuery* pQuery, char* pszAttribute, char* pszPattern) { long macError = eDSNoErr; LWIAttrLookup::Index_t attrIndex = LWIAttrLookup::idx_unknown; PSTR pszHostname = NULL; macError = GetDnsHostName(&pszHostname); GOTO_CLEANUP_ON_MACERROR(macError); attrIndex = LWIAttrLookup::GetIndex(pszAttribute); switch (attrIndex) { case LWIAttrLookup::idx_kDSNAttrRecordName: macError = pQuery->QueryComputerGroupInformationByName(pszPattern); GOTO_CLEANUP_ON_MACERROR(macError); break; case LWIAttrLookup::idx_kDSNAttrComputers: if (!strcmp(pszPattern, "localhost") || !strcmp(pszPattern, pszHostname) ) { macError = pQuery->QueryComputerGroupInformationByName(kDSRecordsAll); GOTO_CLEANUP_ON_MACERROR(macError); break; } else { LOG("Got request to search for %s as a (Computers) attribute for ComputerGroup objects, currently not supported and therefore ignoring", pszPattern); break; } case LWIAttrLookup::idx_kDSNAttrGroupMembership: if (!strcmp(pszPattern, "localhost") || !strcmp(pszPattern, pszHostname)) { macError = pQuery->QueryComputerGroupInformationByName(kDSRecordsAll); GOTO_CLEANUP_ON_MACERROR(macError); break; } else { LOG("Got request to search for %s as a GroupMembership) attribute for ComputerGroup objects, currently not supported and therefore ignoring", pszPattern); break; } default: #ifdef SHOW_DEBUG_SPEW LOG("Unsupported attribute index for group - %d", attrIndex); #endif macError = eDSNoErr; break; } cleanup: if (pszHostname) { LW_SAFE_FREE_STRING(pszHostname); } return macError; }
DWORD GetSecretsPath( PCSTR pSmbdPath, PSTR* ppPath ) { DWORD error = 0; PSTR pCommandLine = NULL; PCSTR ppArgs[] = { "/bin/sh", "-c", NULL, NULL }; PSTR pSambaPrivateDir = NULL; PSTR pPath = NULL; struct stat statBuf = { 0 }; // Look for secrets.tdb in the statedir (Ubuntu 10.10 is like this) error = LwAllocateStringPrintf( &pCommandLine, "%s -b | grep STATEDIR:", pSmbdPath ); BAIL_ON_LSA_ERROR(error); ppArgs[2] = pCommandLine; error = CaptureOutputWithStderr( "/bin/sh", ppArgs, &pSambaPrivateDir, NULL); if (error == ERROR_BAD_COMMAND) { pSambaPrivateDir = NULL; error = ERROR_BAD_COMMAND; } else { if (strstr(pSambaPrivateDir, ": ")) { char *pValueStart = strstr(pSambaPrivateDir, ": ") + 2; memmove( pSambaPrivateDir, pValueStart, strlen(pSambaPrivateDir) - (pValueStart - pSambaPrivateDir) + 1); } LwStripWhitespace( pSambaPrivateDir, TRUE, TRUE); error = LwAllocateStringPrintf( &pPath, "%s/secrets.tdb", pSambaPrivateDir ); BAIL_ON_LSA_ERROR(error); // Verify the path exists if (stat(pPath, &statBuf) < 0) { if (errno == ENOENT) { // Try the private dir instead LW_SAFE_FREE_STRING(pSambaPrivateDir); LW_SAFE_FREE_STRING(pPath); } else { LW_RTL_LOG_ERROR("Cannot find secrets.tdb at %s", pPath); error = LwMapErrnoToLwError(errno); BAIL_ON_LSA_ERROR(error); } } } if (pPath == NULL) { // This version of smbd is older than 3.5, or the distro vendor decided // to put the file in the private dir (Fedora 14 is like that). LW_SAFE_FREE_STRING(pCommandLine); error = LwAllocateStringPrintf( &pCommandLine, "%s -b | grep PRIVATE_DIR:", pSmbdPath ); BAIL_ON_LSA_ERROR(error); ppArgs[2] = pCommandLine; error = CaptureOutputWithStderr( "/bin/sh", ppArgs, &pSambaPrivateDir, NULL); BAIL_ON_LSA_ERROR(error); LwStripWhitespace( pSambaPrivateDir, TRUE, TRUE); if (strstr(pSambaPrivateDir, ": ")) { char *pValueStart = strstr(pSambaPrivateDir, ": ") + 2; memmove( pSambaPrivateDir, pValueStart, strlen(pSambaPrivateDir) - (pValueStart - pSambaPrivateDir) + 1); } error = LwAllocateStringPrintf( &pPath, "%s/secrets.tdb", pSambaPrivateDir ); BAIL_ON_LSA_ERROR(error); } cleanup: *ppPath = pPath; LW_SAFE_FREE_STRING(pCommandLine); LW_SAFE_FREE_STRING(pSambaPrivateDir); return error; }
DWORD UmnSrvUpdateADGroup( PLW_EVENTLOG_CONNECTION pEventlog, HANDLE hReg, HKEY hGroups, long long PreviousRun, long long Now, PLSA_SECURITY_OBJECT pGroup ) { DWORD dwError = 0; HKEY hKey = NULL; HKEY hMembers = NULL; USER_MONITOR_GROUP old = { 0 }; DWORD dwNow = Now; old.gr_gid = -1; PSTR pEncodedGroup = NULL; dwError = LwURLEncodeString( pGroup->groupInfo.pszUnixName, &pEncodedGroup); BAIL_ON_UMN_ERROR(dwError); dwError = RegOpenKeyExA( hReg, hGroups, pEncodedGroup, 0, KEY_ALL_ACCESS, &hKey); if (dwError == LWREG_ERROR_NO_SUCH_KEY_OR_VALUE) { dwError = 0; } else { BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvReadGroup( "AD Groups", pEncodedGroup, &old); BAIL_ON_UMN_ERROR(dwError); } // Check if the key does not exist yet, or it was not fully populated. if (old.LastUpdated == 0) { UMN_LOG_INFO("Adding group '%s' (gid %d)", pGroup->groupInfo.pszUnixName, pGroup->groupInfo.gid); dwError = RegCreateKeyExA( hReg, hGroups, pEncodedGroup, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL); if (dwError == LWREG_ERROR_KEYNAME_EXIST) { // The key exists, but the values were not fully populated on a // previous run because the user monitor crashed or was killed. Use // the existing key and let the values get overwritten. dwError = 0; } BAIL_ON_UMN_ERROR(dwError); dwError = RegCreateKeyExA( hReg, hKey, "Members", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hMembers, NULL); if (dwError == LWREG_ERROR_KEYNAME_EXIST) { // The key exists, but the values were not fully populated on a // previous run because the user monitor crashed or was killed. Use // the existing key and let the values get overwritten. dwError = 0; } BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvWriteADGroupValues( hReg, hKey, pGroup); BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvWriteADGroupEvent( pEventlog, PreviousRun, NULL, Now, pGroup); BAIL_ON_UMN_ERROR(dwError); } else if (strcmp(pGroup->groupInfo.pszUnixName, old.gr_name)) { // The group's name changed. This is too drastic of a change for a // change event. File a deletion and addition event. dwError = UmnSrvWriteADGroupEvent( pEventlog, PreviousRun, &old, Now, NULL); BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvWriteADGroupEvent( pEventlog, PreviousRun, NULL, Now, pGroup); BAIL_ON_UMN_ERROR(dwError); } else if (strcmp((pGroup->groupInfo.pszPasswd ? pGroup->groupInfo.pszPasswd : "x"), old.gr_passwd) || pGroup->groupInfo.gid != old.gr_gid) { UMN_LOG_INFO("Group '%s' (gid %d) changed", pGroup->groupInfo.pszUnixName, pGroup->groupInfo.gid); dwError = UmnSrvWriteADGroupValues( hReg, hKey, pGroup); BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvWriteADGroupEvent( pEventlog, PreviousRun, &old, Now, pGroup); BAIL_ON_UMN_ERROR(dwError); if (pGroup->groupInfo.gid != old.gr_gid) { // Send out membership deletion events for all members. They // will get readded through normal processing with the new gid dwError = RegOpenKeyExA( hReg, hKey, "Members", 0, KEY_ALL_ACCESS, &hMembers); BAIL_ON_UMN_ERROR(dwError); dwError = UmnSrvFindDeletedGroupMembers( pEventlog, hReg, "AD Groups", hMembers, Now, TRUE, old.gr_gid, old.gr_name); BAIL_ON_UMN_ERROR(dwError); } } dwError = RegSetValueExA( hReg, hKey, "LastUpdated", 0, REG_DWORD, (PBYTE)&dwNow, sizeof(dwNow)); BAIL_ON_UMN_ERROR(dwError); cleanup: LW_SAFE_FREE_STRING(pEncodedGroup); UmnSrvFreeGroupContents(&old); if (hKey) { RegCloseKey( hReg, hKey); } if (hMembers) { RegCloseKey( hReg, hMembers); } return dwError; error: goto cleanup; }