/* 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: * * lsa_wbc_sid.c * * Abstract: * * Likewise Security and Authentication Subsystem (LSASS) * * Authors: Gerald Carter * */ #include "wbclient.h" #include "lsawbclient_p.h" #include "util_str.h" #define MAX_SID_STRING_LEN 1024 wbcErr wbcSidCopy( struct wbcDomainSid *dst, struct wbcDomainSid *src ) { DWORD dwErr = LW_ERROR_INTERNAL; wbcErr wbcStatus = WBC_ERR_UNKNOWN_FAILURE; BAIL_ON_NULL_PTR_PARAM(dst, dwErr); BAIL_ON_NULL_PTR_PARAM(src, dwErr); memcpy(dst, src, sizeof(struct wbcDomainSid)); dwErr = LW_ERROR_SUCCESS; done: wbcStatus = map_error_to_wbc_status(dwErr); return wbcStatus; } wbcErr wbcSidAppendRid( struct wbcDomainSid *sid, DWORD rid ) { DWORD dwErr = LW_ERROR_INTERNAL; wbcErr wbcStatus = WBC_ERR_UNKNOWN_FAILURE; BAIL_ON_NULL_PTR_PARAM(sid, dwErr); /* See if there is room */ if (sid->num_auths >= WBC_MAXSUBAUTHS) { dwErr = LW_ERROR_INVALID_SID; BAIL_ON_LSA_ERR(dwErr); } sid->sub_auths[sid->num_auths] = rid; sid->num_auths++; dwErr = LW_ERROR_SUCCESS; done: wbcStatus = map_error_to_wbc_status(dwErr); return dwErr; } wbcErr wbcSidToString( const struct wbcDomainSid *sid, char **sid_string ) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; CHAR pszSidStr[MAX_SID_STRING_LEN] = ""; uint32_t dwAuthId = 0; int i = 0; DWORD dwErr = LW_ERROR_INTERNAL; SET_OUT_PTR_NULL(sid_string); BAIL_ON_NULL_PTR_PARAM(sid, dwErr); BAIL_ON_NULL_PTR_PARAM(sid_string, dwErr); dwAuthId = sid->id_auth[5] + (sid->id_auth[4] << 8) + (sid->id_auth[3] << 16) + (sid->id_auth[2] << 24); snprintf(pszSidStr, sizeof(pszSidStr)-strlen(pszSidStr), "S-%d-%d", sid->sid_rev_num, dwAuthId); for (i=0; inum_auths; i++) { char pszAuth[12]; snprintf(pszAuth, sizeof(pszAuth), "-%u", sid->sub_auths[i]); strncat(pszSidStr, pszAuth, sizeof(pszSidStr)-strlen(pszSidStr)); } *sid_string = _wbc_strdup(pszSidStr); BAIL_ON_NULL_PTR(*sid_string, dwErr); dwErr = LW_ERROR_SUCCESS; done: wbc_status = map_error_to_wbc_status(dwErr); return wbc_status; } wbcErr wbcStringToSid( const char *sid_string, struct wbcDomainSid *sid ) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; DWORD dwErr = LW_ERROR_INTERNAL; const CHAR *pszStrToken = NULL; CHAR *pszStrNextToken = NULL; DWORD dwX; BAIL_ON_NULL_PTR_PARAM(sid_string, dwErr); BAIL_ON_NULL_PTR_PARAM(sid, dwErr); /* Some additional sanity checks on the SID string format */ if ((strlen((const char*)sid_string) < 2) || (sid_string[0] != 's' && sid_string[0] != 'S') || (sid_string[1] != '-')) { dwErr = LW_ERROR_INVALID_SID; BAIL_ON_LSA_ERR(dwErr); } /* Revision */ pszStrToken = sid_string+2; dwX = (DWORD)strtol(pszStrToken, &pszStrNextToken, 10); if ((dwX == 0) || !pszStrNextToken || (pszStrNextToken[0] != '-')) { dwErr = LW_ERROR_INVALID_SID; BAIL_ON_LSA_ERR(dwErr); } sid->sid_rev_num = (uint8_t)dwX; /* Id Auth */ pszStrToken = pszStrNextToken + 1; dwX = (DWORD)strtoul(pszStrToken, &pszStrNextToken, 10); if ((dwX == 0) || !pszStrNextToken || (pszStrNextToken[0] != '-')) { dwErr = LW_ERROR_INVALID_SID; BAIL_ON_LSA_ERR(dwErr); } sid->id_auth[5] = (dwX & 0x000000FF); sid->id_auth[4] = (dwX & 0x0000FF00) >> 8; sid->id_auth[3] = (dwX & 0x00FF0000) >> 16; sid->id_auth[2] = (dwX & 0xFF000000) >> 24; sid->id_auth[1] = 0; sid->id_auth[0] = 0; /* Subauths */ sid->num_auths = 0; do { pszStrToken = pszStrNextToken + 1; errno = 0; dwX = (DWORD)strtoul(pszStrToken, &pszStrNextToken, 10); if (errno || pszStrToken == pszStrNextToken) { break; } sid->sub_auths[sid->num_auths++] = dwX; if (!pszStrNextToken || (pszStrNextToken[0] != '-')) { break; } } while (sid->num_auths < WBC_MAXSUBAUTHS); /* Check for a premature end to the above loop */ if (pszStrNextToken && (pszStrNextToken[0] != '\0')) { dwErr = LW_ERROR_INVALID_SID; BAIL_ON_LSA_ERR(dwErr); } dwErr = LW_ERROR_SUCCESS; done: wbc_status = map_error_to_wbc_status(dwErr); return wbc_status; } wbcErr wbcLookupName( const char *dom_name, const char *name, struct wbcDomainSid *sid, enum wbcSidType *name_type ) { LSA_USER_INFO_0 *pUserInfo = NULL; LSA_GROUP_INFO_1 *pGroupInfo = NULL; HANDLE hLsa = (HANDLE)NULL; DWORD dwErr = LW_ERROR_INTERNAL; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; CHAR pszQualifiedName[512] = ""; BAIL_ON_NULL_PTR_PARAM(name, dwErr); if (dom_name) { snprintf(pszQualifiedName, sizeof(pszQualifiedName), "%s\\", dom_name); } strncat(pszQualifiedName, name, sizeof(pszQualifiedName) - (strlen(pszQualifiedName)+1)); dwErr = LsaOpenServer(&hLsa); BAIL_ON_LSA_ERR(dwErr); /* First try to lookup the name as a user */ dwErr = LsaFindUserByName(hLsa, pszQualifiedName, 0, (PVOID*)&pUserInfo); if (dwErr == LW_ERROR_SUCCESS) { if (sid) { wbc_status = wbcStringToSid(pUserInfo->pszSid, sid); dwErr = map_wbc_to_lsa_error(wbc_status); BAIL_ON_LSA_ERR(dwErr); } if (name_type) { *name_type = WBC_SID_NAME_USER; } goto done; } /* Fall back and try it as a group */ dwErr = LsaFindGroupByName(hLsa, pszQualifiedName, LSA_FIND_FLAGS_NSS, 1, (PVOID*)&pGroupInfo); BAIL_ON_LSA_ERR(dwErr); if (sid) { wbc_status = wbcStringToSid(pGroupInfo->pszSid, sid); dwErr = map_wbc_to_lsa_error(wbc_status); BAIL_ON_LSA_ERR(dwErr); } if (name_type) { *name_type = WBC_SID_NAME_DOM_GRP; } dwErr = LsaCloseServer(hLsa); BAIL_ON_LSA_ERR(dwErr); hLsa = (HANDLE)NULL; dwErr = LW_ERROR_SUCCESS; done: if ( hLsa) { LsaCloseServer(hLsa); hLsa = (HANDLE)NULL; } if (pUserInfo) { LsaFreeUserInfo(0, pUserInfo); } if (pGroupInfo) { LsaFreeGroupInfo(1, pGroupInfo); } wbc_status = map_error_to_wbc_status(dwErr); return wbc_status; } static enum wbcSidType map_lsa_sid_type_to_wbc( ADAccountType type ) { if (type == AccountType_User) return WBC_SID_NAME_USER; if (type == AccountType_Group) return WBC_SID_NAME_DOM_GRP; return WBC_SID_NAME_UNKNOWN; } wbcErr wbcLookupSid( const struct wbcDomainSid *sid, char **domain, char **name, enum wbcSidType *name_type ) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; HANDLE hLsa = (HANDLE)NULL; DWORD dwErr = LW_ERROR_INTERNAL; PSTR pszSidString = NULL; PSTR ppszSidList[2]; PLSA_SID_INFO pNameList = NULL; SET_OUT_PTR_NULL(domain); SET_OUT_PTR_NULL(name); BAIL_ON_NULL_PTR_PARAM(sid, dwErr); /* Validate the SID */ wbc_status = wbcSidToString(sid, &pszSidString); dwErr = map_wbc_to_lsa_error(wbc_status); BAIL_ON_LSA_ERR(dwErr); ppszSidList[0] = pszSidString; ppszSidList[1] = NULL; dwErr = LsaOpenServer(&hLsa); BAIL_ON_LSA_ERR(dwErr); dwErr = LsaGetNamesBySidList( hLsa, 1, ppszSidList, &pNameList, NULL); BAIL_ON_LSA_ERR(dwErr); dwErr = LsaCloseServer(hLsa); hLsa = (HANDLE)NULL; BAIL_ON_LSA_ERR(dwErr); /* Fill in return values here Some of these could have been passed in as NULL */ if (pNameList[0].accountType == AccountType_NotFound) { dwErr = LW_ERROR_NOT_MAPPED; BAIL_ON_LSA_ERR(dwErr); } if (domain) { *domain = _wbc_strdup(pNameList[0].pszDomainName); BAIL_ON_NULL_PTR(*domain, dwErr); StrUpper(*domain); } if (name) { *name = _wbc_strdup(pNameList[0].pszSamAccountName); BAIL_ON_NULL_PTR(*name, dwErr); } if (name_type) { *name_type = map_lsa_sid_type_to_wbc(pNameList[0].accountType); } dwErr = LW_ERROR_SUCCESS; done: if (pNameList) { LsaFreeSIDInfoList(pNameList, 1); } if (pszSidString) { wbcFreeMemory(pszSidString); } if (hLsa) { LsaCloseServer(hLsa); hLsa = (HANDLE)NULL; } if (dwErr != LW_ERROR_SUCCESS) { if (domain) { _WBC_FREE(*domain); } if (name) { _WBC_FREE(*name); } } wbc_status = map_error_to_wbc_status(dwErr); return wbc_status; } wbcErr wbcLookupRids( struct wbcDomainSid *dom_sid, int num_rids, uint32_t *rids, const char **domain_name, const char ***names, enum wbcSidType **types ) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; DWORD dwErr = LW_ERROR_INTERNAL; struct wbcDomainSid sid; int i; char *domain = NULL; SET_OUT_PTR_NULL(domain_name); SET_OUT_PTR_NULL(names); SET_OUT_PTR_NULL(types); BAIL_ON_NULL_PTR_PARAM(dom_sid, dwErr); BAIL_ON_NULL_PTR_PARAM(rids, dwErr); if (names) { /* Add one more to the end to NULL terminate the array of strings. Required by _wbc_free_string_array() */ *names = _wbc_malloc_zero(sizeof(char*)*(num_rids+1), _wbc_free_string_array); BAIL_ON_NULL_PTR(*names, dwErr); } if (types) { *types = _wbc_malloc_zero(sizeof(enum wbcSidType)*num_rids, NULL); BAIL_ON_NULL_PTR(*types, dwErr); } for (i=0; i