/* Editor Settings: expandtabs and use 4 spaces for indentation * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: * * -*- mode: c, c-basic-offset: 4 -*- */ /* * Copyright Likewise Software 2004-2008 * All rights reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the license, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. You should have received a copy * of the GNU Lesser General Public License along with this program. If * not, see . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Copyright (C) Likewise Software. All rights reserved. * * Module Name: * * users.c * * Abstract: * * Likewise Security and Authentication Subsystem (LSASS) * * User Lookup and Management API * * Authors: Krishna Ganugapati (krishnag@likewisesoftware.com) * Sriram Nambakam (snambakam@likewisesoftware.com) * Kyle Stemen (kstemen@likewisesoftware.com) */ #define LSA_ENABLE_DEPRECATED #include "client.h" typedef struct __LSA_CLIENT_ENUM_USERS_HANDLE { DWORD dwUserInfoLevel; DWORD dwMaxNumUsers; DWORD dwObjectCount; DWORD dwObjectIndex; PLSA_SECURITY_OBJECT* ppObjects; HANDLE hEnum; } LSA_CLIENT_ENUM_USERS_HANDLE, *PLSA_CLIENT_ENUM_USERS_HANDLE; LSASS_API DWORD LsaAddUser( HANDLE hLsaConnection, PVOID pUserInfo, DWORD dwUserInfoLevel ) { DWORD dwError = 0; PLSA_USER_ADD_INFO pAddInfo = NULL; switch (dwUserInfoLevel) { case 0: dwError = LsaMarshalUserInfo0ToUserAddInfo( hLsaConnection, pUserInfo, &pAddInfo); BAIL_ON_LSA_ERROR(dwError); break; case 1: case 2: dwError = LW_ERROR_NOT_SUPPORTED; BAIL_ON_LSA_ERROR(dwError); break; default: dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } dwError = LsaTransactAddUser2( hLsaConnection, NULL, pAddInfo); BAIL_ON_LSA_ERROR(dwError); error: if (pAddInfo) { LsaFreeUserAddInfo(pAddInfo); } return dwError; } LSASS_API DWORD LsaModifyUser( HANDLE hLsaConnection, PLSA_USER_MOD_INFO pUserModInfo ) { DWORD dwError = 0; PLSA_USER_MOD_INFO_2 pUserModInfo2 = NULL; dwError = LsaMarshalUserModInfoToUserModInfo2( hLsaConnection, pUserModInfo, &pUserModInfo2); BAIL_ON_LSA_ERROR(dwError); dwError = LsaTransactModifyUser2( hLsaConnection, NULL, pUserModInfo2); BAIL_ON_LSA_ERROR(dwError); error: if (pUserModInfo2) { LsaFreeUserModInfo2(pUserModInfo2); } return dwError; } LSASS_API DWORD LsaFindUserByName( HANDLE hLsaConnection, PCSTR pszName, DWORD dwUserInfoLevel, PVOID* ppUserInfo ) { DWORD dwError = 0; PVOID pUserInfo = NULL; LSA_QUERY_LIST QueryList; PLSA_SECURITY_OBJECT* ppObjects = NULL; BAIL_ON_INVALID_HANDLE(hLsaConnection); BAIL_ON_INVALID_STRING(pszName); dwError = LsaValidateUserInfoLevel(dwUserInfoLevel); BAIL_ON_LSA_ERROR(dwError); BAIL_ON_INVALID_POINTER(ppUserInfo); QueryList.ppszStrings = &pszName; dwError = LsaFindObjects( hLsaConnection, NULL, 0, LSA_OBJECT_TYPE_USER, LSA_QUERY_TYPE_BY_NAME, 1, QueryList, &ppObjects); BAIL_ON_LSA_ERROR(dwError); if (ppObjects[0] == NULL) { dwError = LW_ERROR_NO_SUCH_USER; BAIL_ON_LSA_ERROR(dwError); } dwError = LsaMarshalUserInfo( ppObjects[0], dwUserInfoLevel, &pUserInfo); BAIL_ON_LSA_ERROR(dwError); error: if (ppUserInfo) { *ppUserInfo = pUserInfo; } if (ppObjects) { LsaFreeSecurityObjectList(1, ppObjects); } return dwError; } LSASS_API DWORD LsaFindUserById( HANDLE hLsaConnection, uid_t uid, DWORD dwUserInfoLevel, PVOID* ppUserInfo ) { DWORD dwError = 0; PVOID pUserInfo = NULL; LSA_QUERY_LIST QueryList; PLSA_SECURITY_OBJECT* ppObjects = NULL; DWORD dwUid = (DWORD) uid; BAIL_ON_INVALID_HANDLE(hLsaConnection); dwError = LsaValidateUserInfoLevel(dwUserInfoLevel); BAIL_ON_LSA_ERROR(dwError); BAIL_ON_INVALID_POINTER(ppUserInfo); QueryList.pdwIds = &dwUid; dwError = LsaFindObjects( hLsaConnection, NULL, 0, LSA_OBJECT_TYPE_USER, LSA_QUERY_TYPE_BY_UNIX_ID, 1, QueryList, &ppObjects); BAIL_ON_LSA_ERROR(dwError); if (ppObjects[0] == NULL) { dwError = LW_ERROR_NO_SUCH_USER; BAIL_ON_LSA_ERROR(dwError); } dwError = LsaMarshalUserInfo( ppObjects[0], dwUserInfoLevel, &pUserInfo); BAIL_ON_LSA_ERROR(dwError); error: if (ppUserInfo) { *ppUserInfo = pUserInfo; } if (ppObjects) { LsaFreeSecurityObjectList(1, ppObjects); } return dwError; } LSASS_API DWORD LsaBeginEnumUsers( HANDLE hLsaConnection, DWORD dwUserInfoLevel, DWORD dwMaxNumUsers, LSA_FIND_FLAGS FindFlags, PHANDLE phResume ) { DWORD dwError = 0; PLSA_CLIENT_ENUM_USERS_HANDLE pEnum = NULL; dwError = LwAllocateMemory(sizeof(*pEnum), OUT_PPVOID(&pEnum)); BAIL_ON_LSA_ERROR(dwError); pEnum->dwUserInfoLevel = dwUserInfoLevel; pEnum->dwMaxNumUsers = dwMaxNumUsers; dwError = LsaOpenEnumObjects( hLsaConnection, NULL, &pEnum->hEnum, FindFlags, LSA_OBJECT_TYPE_USER, NULL); BAIL_ON_LSA_ERROR(dwError); *phResume = pEnum; cleanup: return dwError; error: *phResume = NULL; if (pEnum) { LsaEndEnumUsers(hLsaConnection, pEnum); } goto cleanup; } LSASS_API DWORD LsaEnumUsers( HANDLE hLsaConnection, HANDLE hResume, PDWORD pdwNumUsersFound, PVOID** pppUserInfoList ) { DWORD dwError = 0; PLSA_CLIENT_ENUM_USERS_HANDLE pEnum = hResume; DWORD dwTotalInfoCount = 0; DWORD dwInfoCount = 0; DWORD dwObjectsUsed = 0; PVOID* ppUserInfo = NULL; if (!pEnum->hEnum) { dwError = LW_ERROR_NO_MORE_USERS; BAIL_ON_LSA_ERROR(dwError); } dwError = LwAllocateMemory(sizeof(*ppUserInfo) * pEnum->dwMaxNumUsers, OUT_PPVOID(&ppUserInfo)); BAIL_ON_LSA_ERROR(dwError); while (dwTotalInfoCount < pEnum->dwMaxNumUsers) { if (!pEnum->ppObjects) { dwError = LsaEnumObjects( hLsaConnection, pEnum->hEnum, pEnum->dwMaxNumUsers, &pEnum->dwObjectCount, &pEnum->ppObjects); if (dwError == ERROR_NO_MORE_ITEMS) { dwError = 0; break; } BAIL_ON_LSA_ERROR(dwError); } while (pEnum->dwObjectIndex < pEnum->dwObjectCount) { dwError = LsaMarshalUserInfoList( pEnum->dwObjectCount - pEnum->dwObjectIndex, pEnum->ppObjects + pEnum->dwObjectIndex, pEnum->dwUserInfoLevel, pEnum->dwMaxNumUsers - dwTotalInfoCount, ppUserInfo + dwTotalInfoCount, &dwObjectsUsed, &dwInfoCount); BAIL_ON_LSA_ERROR(dwError); pEnum->dwObjectIndex += dwObjectsUsed; dwTotalInfoCount += dwInfoCount; } LsaUtilFreeSecurityObjectList(pEnum->dwObjectCount, pEnum->ppObjects); pEnum->ppObjects = NULL; pEnum->dwObjectIndex = 0; } if (dwTotalInfoCount == 0) { dwError = LsaCloseEnum(hLsaConnection, pEnum->hEnum); pEnum->hEnum = NULL; BAIL_ON_LSA_ERROR(dwError); *pdwNumUsersFound = 0; *pppUserInfoList = NULL; LW_SAFE_FREE_MEMORY(ppUserInfo); } else { *pdwNumUsersFound = dwTotalInfoCount; *pppUserInfoList = ppUserInfo; } cleanup: return dwError; error: *pdwNumUsersFound = 0; *pppUserInfoList = NULL; if (ppUserInfo) { LsaFreeUserInfoList(pEnum->dwUserInfoLevel, ppUserInfo, dwTotalInfoCount); } goto cleanup; } LSASS_API DWORD LsaEndEnumUsers( HANDLE hLsaConnection, HANDLE hResume ) { DWORD dwError = 0; PLSA_CLIENT_ENUM_USERS_HANDLE pEnum = hResume; if (pEnum) { if (pEnum->hEnum) { dwError = LsaCloseEnum(hLsaConnection, pEnum->hEnum); } if (pEnum->ppObjects) { LsaUtilFreeSecurityObjectList(pEnum->dwObjectCount, pEnum->ppObjects); } LwFreeMemory(pEnum); } return dwError; } LSASS_API DWORD LsaDeleteUserById( HANDLE hLsaConnection, uid_t uid ) { DWORD dwError = 0; LSA_QUERY_LIST QueryList; PLSA_SECURITY_OBJECT* ppObjects = NULL; DWORD dwUid = (DWORD) uid; QueryList.pdwIds = &dwUid; dwError = LsaFindObjects( hLsaConnection, NULL, 0, LSA_OBJECT_TYPE_USER, LSA_QUERY_TYPE_BY_UNIX_ID, 1, QueryList, &ppObjects); BAIL_ON_LSA_ERROR(dwError); if (ppObjects[0] == NULL) { dwError = LW_ERROR_NO_SUCH_USER; BAIL_ON_LSA_ERROR(dwError); } dwError = LsaTransactDeleteObject( hLsaConnection, NULL, ppObjects[0]->pszObjectSid); BAIL_ON_LSA_ERROR(dwError); cleanup: LsaUtilFreeSecurityObjectList(1, ppObjects); return dwError; error: goto cleanup; } LSASS_API DWORD LsaDeleteUserByName( HANDLE hLsaConnection, PCSTR pszName ) { DWORD dwError = 0; PVOID pUserInfo = NULL; DWORD dwUserInfoLevel = 0; if (geteuid() != 0) { dwError = EACCES; BAIL_ON_LSA_ERROR(dwError); } BAIL_ON_INVALID_HANDLE(hLsaConnection); BAIL_ON_INVALID_STRING(pszName); dwError = LsaFindUserByName( hLsaConnection, pszName, dwUserInfoLevel, &pUserInfo); BAIL_ON_LSA_ERROR(dwError); dwError = LsaDeleteUserById( hLsaConnection, ((PLSA_USER_INFO_0)pUserInfo)->uid); BAIL_ON_LSA_ERROR(dwError); cleanup: if (pUserInfo) { LsaFreeUserInfo(dwUserInfoLevel, pUserInfo); } return dwError; error: goto cleanup; } LSASS_API DWORD LsaGetNamesBySidList( IN HANDLE hLsaConnection, IN size_t sCount, IN PSTR* ppszSidList, OUT PLSA_SID_INFO* ppSIDInfoList, OUT OPTIONAL CHAR *pchDomainSeparator ) { DWORD dwError = 0; LSA_QUERY_LIST QueryList; PLSA_SECURITY_OBJECT* ppObjects = NULL; PLSA_SID_INFO pSidInfo = NULL; DWORD dwIndex = 0; BAIL_ON_INVALID_HANDLE(hLsaConnection); QueryList.ppszStrings = (PCSTR*) ppszSidList; dwError = LsaFindObjects( hLsaConnection, NULL, 0, LSA_OBJECT_TYPE_UNDEFINED, LSA_QUERY_TYPE_BY_SID, (DWORD) sCount, QueryList, &ppObjects); BAIL_ON_LSA_ERROR(dwError); if (ppObjects[0] == NULL) { dwError = LW_ERROR_NO_SUCH_OBJECT; BAIL_ON_LSA_ERROR(dwError); } dwError = LwAllocateMemory(sizeof(*pSidInfo) * sCount, OUT_PPVOID(&pSidInfo)); BAIL_ON_LSA_ERROR(dwError); for (dwIndex = 0; dwIndex < sCount; dwIndex++) { pSidInfo[dwIndex].accountType = ppObjects[dwIndex]->type; if (pSidInfo[dwIndex].accountType != AccountType_NotFound) { dwError = LwAllocateString( ppObjects[dwIndex]->pszSamAccountName, &pSidInfo[dwIndex].pszSamAccountName); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateString( ppObjects[dwIndex]->pszNetbiosDomainName, &pSidInfo[dwIndex].pszDomainName); BAIL_ON_LSA_ERROR(dwError); } } *ppSIDInfoList = pSidInfo; if (pchDomainSeparator) { *pchDomainSeparator = '\\'; } cleanup: return dwError; error: *ppSIDInfoList = NULL; if (pSidInfo) { LsaFreeSIDInfoList(pSidInfo, sCount); } goto cleanup; }