/* Editor Settings: expandtabs and use 4 spaces for indentation * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: * */ /* * Copyright Likewise Software 2004-2008 * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program 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 General Public License * for more details. You should have received a copy of the GNU 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 * 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: * * main.c * * Abstract: * * Likewise Security and Authentication Subsystem (LSASS) * * Driver for program to modify an existing group * * Authors: * Krishna Ganugapati (krishnag@likewise.com) * Sriram Nambakam (snambakam@likewise.com) * Rafal Szczesniak (rafal@likewise.com) */ #include "mod_group_includes.h" #define LW_PRINTF_STRING(x) ((x) ? (x) : "") static DWORD LsaModGroupMain( int argc, char* argv[] ); static DWORD ParseArgs( int argc, char* argv[], PSTR* ppszLoginId, PDLINKEDLIST* ppTaskList ); static BOOLEAN ValidateArgs( PCSTR pszLoginId, PDLINKEDLIST pTaskList ); static VOID FreeTasksInList( PVOID pListMember, PVOID pGroupData ); static VOID FreeTask( PGROUP_MOD_TASK pTask ); static PSTR GetProgramName( PSTR pszFullProgramPath ); static VOID ShowUsage( PCSTR pszProgramName ); static DWORD ModifyGroup( PSTR pszLoginId, PDLINKEDLIST pTaskList ); static DWORD ResolveNames( HANDLE hLsaConnection, PDLINKEDLIST pTaskList ); static DWORD BuildGroupModInfo( gid_t gid, PDLINKEDLIST pTaskList, PLSA_GROUP_MOD_INFO* ppGroupModInfo ); int mod_group_main( int argc, char* argv[] ) { return LsaModGroupMain(argc, argv); } static DWORD MapErrorCode( DWORD dwError ); static DWORD LsaModGroupMain( int argc, char* argv[] ) { DWORD dwError = 0; PDLINKEDLIST pTaskList = NULL; PSTR pszLoginId = NULL; size_t dwErrorBufferSize = 0; BOOLEAN bPrintOrigError = TRUE; if (geteuid() != 0) { fprintf(stderr, "This program requires super-user privileges.\n"); dwError = EACCES; BAIL_ON_LSA_ERROR(dwError); } dwError = ParseArgs(argc, argv, &pszLoginId, &pTaskList); BAIL_ON_LSA_ERROR(dwError); dwError = ModifyGroup( pszLoginId, pTaskList); BAIL_ON_LSA_ERROR(dwError); cleanup: if (pTaskList) { LsaDLinkedListForEach(pTaskList, &FreeTasksInList, NULL); LsaDLinkedListFree(pTaskList); } LW_SAFE_FREE_STRING(pszLoginId); 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 modify group. 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 modify group. Error code %u (%s).\n", dwError, LW_PRINTF_STRING(LwWin32ExtErrorToName(dwError))); } goto cleanup; } DWORD ParseArgs( int argc, char* argv[], PSTR* ppszLoginId, PDLINKEDLIST* ppTaskList ) { typedef enum { PARSE_MODE_OPEN = 0, PARSE_MODE_ADD_TO_GROUPS, PARSE_MODE_REMOVE_FROM_GROUPS, PARSE_MODE_DONE } ParseMode; DWORD dwError = 0; ParseMode parseMode = PARSE_MODE_OPEN; int iArg = 1; PSTR pArg = NULL; PDLINKEDLIST pTaskList = NULL; PGROUP_MOD_TASK pTask = NULL; PSTR pszLoginId = NULL; PSTR pszAddMembers = NULL; PSTR pszRemoveMembers = NULL; do { pArg = argv[iArg++]; if (pArg == NULL || *pArg == '\0') { break; } switch(parseMode) { case PARSE_MODE_OPEN: { if ((strcmp(pArg, "--help") == 0) || (strcmp(pArg, "-h") == 0)) { ShowUsage(GetProgramName(argv[0])); exit(0); } else if (!strcmp(pArg, "--add-members")) { parseMode = PARSE_MODE_ADD_TO_GROUPS; } else if (!strcmp(pArg, "--remove-members")) { parseMode = PARSE_MODE_REMOVE_FROM_GROUPS; } else { dwError = LwAllocateString(pArg, &pszLoginId); BAIL_ON_LSA_ERROR(dwError); parseMode = PARSE_MODE_DONE; } break; } case PARSE_MODE_REMOVE_FROM_GROUPS: { dwError = LwAllocateMemory(sizeof(GROUP_MOD_TASK), (PVOID*)&pTask); BAIL_ON_LSA_ERROR(dwError); pTask->taskType = GroupModTask_RemoveMembers; dwError = LwAllocateString(pArg, &pszRemoveMembers); BAIL_ON_LSA_ERROR(dwError); pTask->pData = pszRemoveMembers; dwError = LsaDLinkedListAppend(&pTaskList, pTask); BAIL_ON_LSA_ERROR(dwError); parseMode = PARSE_MODE_OPEN; break; } case PARSE_MODE_ADD_TO_GROUPS: { dwError = LwAllocateMemory(sizeof(GROUP_MOD_TASK), (PVOID*)&pTask); BAIL_ON_LSA_ERROR(dwError); pTask->taskType = GroupModTask_AddMembers; dwError = LwAllocateString(pArg, &pszAddMembers); BAIL_ON_LSA_ERROR(dwError); pTask->pData = pszAddMembers; dwError = LsaDLinkedListAppend(&pTaskList, pTask); BAIL_ON_LSA_ERROR(dwError); parseMode = PARSE_MODE_OPEN; break; } case PARSE_MODE_DONE: { ShowUsage(GetProgramName(argv[0])); exit(1); } } } while (iArg < argc); if (parseMode != PARSE_MODE_OPEN && parseMode != PARSE_MODE_DONE) { ShowUsage(GetProgramName(argv[0])); exit(1); } if (!ValidateArgs(pszLoginId, pTaskList)) { ShowUsage(GetProgramName(argv[0])); exit(1); } *ppszLoginId = pszLoginId; *ppTaskList = pTaskList; cleanup: return dwError; error: *ppTaskList = NULL; if (pTaskList) { LsaDLinkedListForEach(pTaskList, FreeTasksInList, NULL); LsaDLinkedListFree(pTaskList); } if (pTask) { FreeTask(pTask); } LW_SAFE_FREE_STRING(pszLoginId); goto cleanup; } BOOLEAN ValidateArgs( PCSTR pszLoginId, PDLINKEDLIST pTaskList ) { BOOLEAN bValid = FALSE; PDLINKEDLIST pListMember = NULL; for (pListMember = pTaskList; pListMember; pListMember = pListMember->pNext) { PGROUP_MOD_TASK pTask = (PGROUP_MOD_TASK)pListMember->pItem; if (pTask) { switch(pTask->taskType) { default: break; } } } if (LW_IS_NULL_OR_EMPTY_STR(pszLoginId)) { fprintf(stderr, "Error: A valid group id or group name must be specified.\n"); goto cleanup; } bValid = TRUE; cleanup: return bValid; } VOID FreeTasksInList( PVOID pTask, PVOID pGroupData ) { if (pTask) { FreeTask((PGROUP_MOD_TASK)pTask); } } VOID FreeTask( PGROUP_MOD_TASK pTask ) { PSTR pszMember = pTask->pData; LW_SAFE_FREE_STRING(pszMember); LwFreeMemory(pTask); } PSTR GetProgramName( PSTR pszFullProgramPath ) { if (pszFullProgramPath == NULL || *pszFullProgramPath == '\0') { return NULL; } // start from end of the string PSTR pszNameStart = pszFullProgramPath + strlen(pszFullProgramPath); do { if (*(pszNameStart - 1) == '/') { break; } pszNameStart--; } while (pszNameStart != pszFullProgramPath); return pszNameStart; } VOID ShowUsage( PCSTR pszProgramName ) { fprintf(stdout, "Usage: %s {modification options} ( group name | gid )\n\n", pszProgramName); fprintf(stdout, "\nModification options:\n"); fprintf(stdout, "{ --help }\n"); fprintf(stdout, "{ --add-members nt4-style-name }\n"); fprintf(stdout, "{ --remove-members nt4-style-name }\n"); } DWORD ModifyGroup( PSTR pszGroupId, PDLINKEDLIST pTaskList ) { DWORD dwError = 0; PLSA_GROUP_MOD_INFO pGroupModInfo = NULL; gid_t gid = 0; int nRead = 0; LSA_FIND_FLAGS dwFindFlags = LSA_FIND_FLAGS_NSS; PVOID pGroupInfo = NULL; DWORD dwGroupInfoLevel = 0; HANDLE hLsaConnection = (HANDLE)NULL; BAIL_ON_INVALID_STRING(pszGroupId); dwError = LsaOpenServer(&hLsaConnection); BAIL_ON_LSA_ERROR(dwError); nRead = sscanf(pszGroupId, "%u", (unsigned int*)&gid); if ((nRead == EOF) || (nRead == 0)) { dwError = LsaFindGroupByName( hLsaConnection, pszGroupId, dwFindFlags, dwGroupInfoLevel, &pGroupInfo); BAIL_ON_LSA_ERROR(dwError); gid = ((PLSA_GROUP_INFO_0)pGroupInfo)->gid; LsaFreeGroupInfo(dwGroupInfoLevel, pGroupInfo); pGroupInfo = NULL; } dwError = ResolveNames( hLsaConnection, pTaskList); BAIL_ON_LSA_ERROR(dwError); dwError = BuildGroupModInfo( gid, pTaskList, &pGroupModInfo); BAIL_ON_LSA_ERROR(dwError); dwError = LsaModifyGroup( hLsaConnection, pGroupModInfo); BAIL_ON_LSA_ERROR(dwError); fprintf(stdout, "Successfully modified group %s\n", pszGroupId); cleanup: if (pGroupModInfo) { LsaFreeGroupModInfo(pGroupModInfo); } if (pGroupInfo) { LsaFreeGroupInfo(dwGroupInfoLevel, pGroupInfo); } if (hLsaConnection != (HANDLE)NULL) { LsaCloseServer(hLsaConnection); } return dwError; error: goto cleanup; } DWORD ResolveNames( HANDLE hLsaConnection, PDLINKEDLIST pTaskList ) { DWORD dwError = 0; NTSTATUS ntStatus = STATUS_SUCCESS; PDLINKEDLIST pListMember = pTaskList; DWORD dwGroupInfoLevel = 1; PLSA_GROUP_INFO_1 pGroupInfo = NULL; DWORD dwUserInfoLevel = 1; PLSA_USER_INFO_1 pUserInfo = NULL; PGROUP_MOD_TASK pTask = NULL; PSTR pszName = NULL; PSTR pszSID = NULL; PSID pSid = NULL; for (; pListMember; pListMember = pListMember->pNext) { pTask = (PGROUP_MOD_TASK)pListMember->pItem; if (pTask->taskType == GroupModTask_AddMembers || pTask->taskType == GroupModTask_RemoveMembers) { pszName = (PSTR)pTask->pData; ntStatus = RtlAllocateSidFromCString(&pSid, pszName); if (ntStatus == STATUS_SUCCESS) { dwError = LwAllocateString(pszName, &pszSID); BAIL_ON_LSA_ERROR(dwError); } else { dwError = LsaFindGroupByName(hLsaConnection, pszName, LSA_FIND_FLAGS_NSS, dwGroupInfoLevel, (PVOID*)&pGroupInfo); if (dwError == 0) { dwError = LwAllocateString(pGroupInfo->pszSid, &pszSID); BAIL_ON_LSA_ERROR(dwError); } else if (dwError == LW_ERROR_NO_SUCH_GROUP) { dwError = LsaFindUserByName(hLsaConnection, pszName, dwUserInfoLevel, (PVOID*)&pUserInfo); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateString(pUserInfo->pszSid, &pszSID); BAIL_ON_LSA_ERROR(dwError); } else { BAIL_ON_LSA_ERROR(dwError); } } LW_SAFE_FREE_STRING(pTask->pData); pTask->pData = NULL; pTask->pData = pszSID; if (pGroupInfo) { LsaFreeGroupInfo(dwGroupInfoLevel, pGroupInfo); pGroupInfo = NULL; } if (pUserInfo) { LsaFreeUserInfo(dwUserInfoLevel, pUserInfo); pUserInfo = NULL; } RTL_FREE(&pSid); } } cleanup: if (pGroupInfo) { LsaFreeGroupInfo(dwGroupInfoLevel, pGroupInfo); } if (pUserInfo) { LsaFreeUserInfo(dwUserInfoLevel, pUserInfo); } RTL_FREE(&pSid); return dwError; error: LW_SAFE_FREE_STRING(pTask->pData); goto cleanup; } DWORD BuildGroupModInfo( gid_t gid, PDLINKEDLIST pTaskList, PLSA_GROUP_MOD_INFO* ppGroupModInfo ) { DWORD dwError = 0; PDLINKEDLIST pListMember = pTaskList; PLSA_GROUP_MOD_INFO pGroupModInfo = NULL; dwError = LsaBuildGroupModInfo(gid, &pGroupModInfo); BAIL_ON_LSA_ERROR(dwError); for (; pListMember; pListMember = pListMember->pNext) { PGROUP_MOD_TASK pTask = (PGROUP_MOD_TASK)pListMember->pItem; switch(pTask->taskType) { case GroupModTask_AddMembers: { dwError = LsaModifyGroup_AddMembers(pGroupModInfo, pTask->pData); BAIL_ON_LSA_ERROR(dwError); break; } case GroupModTask_RemoveMembers: { dwError = LsaModifyGroup_RemoveMembers(pGroupModInfo, pTask->pData); BAIL_ON_LSA_ERROR(dwError); break; } } } *ppGroupModInfo = pGroupModInfo; cleanup: return dwError; error: *ppGroupModInfo = NULL; if (pGroupModInfo) { LsaFreeGroupModInfo(pGroupModInfo); } goto cleanup; } static DWORD MapErrorCode( DWORD dwError ) { DWORD dwError2 = dwError; switch (dwError) { case ECONNREFUSED: case ENETUNREACH: case ETIMEDOUT: dwError2 = LW_ERROR_LSA_SERVER_UNREACHABLE; break; default: break; } return dwError2; } /* local variables: mode: c c-basic-offset: 4 indent-tabs-mode: nil tab-width: 4 end: */