/* 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 * 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 */ #include "iop.h" #include typedef struct _IO_CREATE_SECURITY_CONTEXT { LONG ReferenceCount; IO_SECURITY_CONTEXT_PROCESS_INFORMATION Process; PACCESS_TOKEN AccessToken; LW_PIO_CREDS Credentials; } IO_CREATE_SECURITY_CONTEXT; PIO_SECURITY_CONTEXT_PROCESS_INFORMATION IoSecurityGetProcessInfo( IN PIO_CREATE_SECURITY_CONTEXT SecurityContext ) { return &SecurityContext->Process; } PACCESS_TOKEN IoSecurityGetAccessToken( IN PIO_CREATE_SECURITY_CONTEXT SecurityContext ) { return SecurityContext->AccessToken; } LW_PIO_CREDS IoSecurityGetCredentials( IN PIO_CREATE_SECURITY_CONTEXT SecurityContext ) { return SecurityContext->Credentials; } static VOID IopSecurityFreeSecurityContext( IN OUT PIO_CREATE_SECURITY_CONTEXT* SecurityContext ) { PIO_CREATE_SECURITY_CONTEXT securityContext = *SecurityContext; if (securityContext) { LWIO_ASSERT(0 == LwInterlockedRead(&securityContext->ReferenceCount)); RtlReleaseAccessToken(&securityContext->AccessToken); IO_FREE(&securityContext); *SecurityContext = NULL; } } VOID IopSecurityReferenceSecurityContext( IN PIO_CREATE_SECURITY_CONTEXT SecurityContext ) { LONG count = InterlockedIncrement(&SecurityContext->ReferenceCount); LWIO_ASSERT(count > 1); } VOID IoSecurityDereferenceSecurityContext( IN OUT PIO_CREATE_SECURITY_CONTEXT* SecurityContext ) { PIO_CREATE_SECURITY_CONTEXT securityContext = *SecurityContext; if (securityContext) { LONG count = InterlockedDecrement(&securityContext->ReferenceCount); LWIO_ASSERT(count >= 0); if (0 == count) { IopSecurityFreeSecurityContext(&securityContext); } *SecurityContext = NULL; } } static NTSTATUS IopSecurityCreateSecurityContext( OUT PIO_CREATE_SECURITY_CONTEXT* SecurityContext, IN uid_t Uid, IN gid_t Gid, IN PACCESS_TOKEN AccessToken, IN OPTIONAL LW_PIO_CREDS Credentials ) { NTSTATUS status = STATUS_SUCCESS; PIO_CREATE_SECURITY_CONTEXT securityContext = NULL; status = RTL_ALLOCATE(&securityContext, IO_CREATE_SECURITY_CONTEXT, sizeof(*securityContext)); GOTO_CLEANUP_ON_STATUS(status); securityContext->ReferenceCount = 1; securityContext->Process.Uid = Uid; securityContext->Process.Gid = Gid; securityContext->AccessToken = AccessToken; RtlReferenceAccessToken(AccessToken); securityContext->Credentials = Credentials; status = STATUS_SUCCESS; cleanup: if (!NT_SUCCESS(status)) { IoSecurityDereferenceSecurityContext(&securityContext); } *SecurityContext = securityContext; return status; } NTSTATUS IoSecurityCreateSecurityContextFromUidGid( OUT PIO_CREATE_SECURITY_CONTEXT* SecurityContext, IN uid_t Uid, IN gid_t Gid, IN OPTIONAL LW_PIO_CREDS Credentials ) { NTSTATUS status = STATUS_SUCCESS; PLW_MAP_SECURITY_CONTEXT context = NULL; PACCESS_TOKEN accessToken = NULL; PIO_CREATE_SECURITY_CONTEXT securityContext = NULL; // do not free this context status = IopGetMapSecurityContext(&context); GOTO_CLEANUP_ON_STATUS(status); status = LwMapSecurityCreateAccessTokenFromUidGid( context, &accessToken, Uid, Gid); GOTO_CLEANUP_ON_STATUS(status); status = IopSecurityCreateSecurityContext( &securityContext, Uid, Gid, accessToken, Credentials); GOTO_CLEANUP_ON_STATUS(status); cleanup: if (!NT_SUCCESS(status)) { IoSecurityDereferenceSecurityContext(&securityContext); } RtlReleaseAccessToken(&accessToken); *SecurityContext = securityContext; return status; } NTSTATUS IoSecurityCreateSecurityContextFromUsername( OUT PIO_CREATE_SECURITY_CONTEXT* SecurityContext, IN PUNICODE_STRING Username ) { NTSTATUS status = STATUS_SUCCESS; PLW_MAP_SECURITY_CONTEXT context = NULL; PACCESS_TOKEN accessToken = NULL; PIO_CREATE_SECURITY_CONTEXT securityContext = NULL; TOKEN_UNIX tokenUnix = { 0 }; // do not free this context status = IopGetMapSecurityContext(&context); GOTO_CLEANUP_ON_STATUS(status); status = LwMapSecurityCreateAccessTokenFromUnicodeStringUsername( context, &accessToken, Username); GOTO_CLEANUP_ON_STATUS(status); // TODO-Do we want to keep process information as the // current process or just take TOKEN_UNIX info? status = RtlQueryAccessTokenUnixInformation( accessToken, &tokenUnix); GOTO_CLEANUP_ON_STATUS(status); status = IopSecurityCreateSecurityContext( &securityContext, tokenUnix.Uid, tokenUnix.Gid, accessToken, NULL); GOTO_CLEANUP_ON_STATUS(status); cleanup: if (!NT_SUCCESS(status)) { IoSecurityDereferenceSecurityContext(&securityContext); } RtlReleaseAccessToken(&accessToken); *SecurityContext = securityContext; return status; } NTSTATUS IoSecurityCreateSecurityContextFromGssContext( OUT PIO_CREATE_SECURITY_CONTEXT* SecurityContext, IN LW_MAP_SECURITY_GSS_CONTEXT hGssContext ) { NTSTATUS status = STATUS_SUCCESS; PLW_MAP_SECURITY_CONTEXT context = NULL; PACCESS_TOKEN accessToken = NULL; PIO_CREATE_SECURITY_CONTEXT securityContext = NULL; TOKEN_UNIX tokenUnix = { 0 }; // do not free this context status = IopGetMapSecurityContext(&context); GOTO_CLEANUP_ON_STATUS(status); status = LwMapSecurityCreateAccessTokenFromGssContext( context, &accessToken, hGssContext); GOTO_CLEANUP_ON_STATUS(status); // TODO-Do we want to keep process information as the // current process or just take TOKEN_UNIX info? status = RtlQueryAccessTokenUnixInformation( accessToken, &tokenUnix); GOTO_CLEANUP_ON_STATUS(status); status = IopSecurityCreateSecurityContext( &securityContext, tokenUnix.Uid, tokenUnix.Gid, accessToken, NULL); GOTO_CLEANUP_ON_STATUS(status); cleanup: if (!NT_SUCCESS(status)) { IoSecurityDereferenceSecurityContext(&securityContext); } RtlReleaseAccessToken(&accessToken); *SecurityContext = securityContext; return status; }