/* Editor Settings: expandtabs and use 4 spaces for indentation
 * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
 */

/*
 * Copyright Likewise Software
 * 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 <http://www.gnu.org/licenses/>.
 *
 * 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_wellknownsids.c
 *
 * Abstract:
 *
 *        Remote Procedure Call (RPC) Server Interface
 *
 *        Accounts selection functions (by name or SID) for use before
 *        doing lookups in remote lsa or local samr rpc servers
 *
 * Authors: Rafal Szczesniak (rafal@likewise.com)
 */

#include "api.h"

#define WELLKNOWN_NT_AUTHORITY "NT AUTHORITY"

WELLKNOWN_SID gWellknownSids[] = {
    {
        .pszDomain = "",
        .pszName = "NULL SID",
        .pszSid = "S-1-0-0"
    },
    {
        .pszDomain = "",
        .pszName = "Everyone",
        .pszSid = "S-1-1-0"
    },
    {
        .pszDomain = "",
        .pszName = "LOCAL",
        .pszSid = "S-1-2-0"
    },
    {
        .pszDomain = "",
        .pszName = "CREATOR OWNER",
        .pszSid = "S-1-3-0"
    },
    {
        .pszDomain = "",
        .pszName = "CREATOR GROUP",
        .pszSid = "S-1-3-1"
    },
    {
        .pszDomain = "",
        .pszName = "CREATOR OWNER SERVER",
        .pszSid = "S-1-3-2"
    },
    {
        .pszDomain = "",
        .pszName = "CREATOR GROUP SERVER",
        .pszSid = "S-1-3-3"
    },
    {
        .pszDomain = "",
        .pszName = "OWNER RIGHTS",
        .pszSid = "S-1-3-4"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "DIALUP",
        .pszSid = "S-1-5-1"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "NETWORK",
        .pszSid = "S-1-5-2"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "BATCH",
        .pszSid = "S-1-5-3"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "INTERACTIVE",
        .pszSid = "S-1-5-4"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "SERVICE",
        .pszSid = "S-1-5-6"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "ANONYMOUS LOGON",
        .pszSid = "S-1-5-7"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "PROXY",
        .pszSid = "S-1-5-8"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "ENTERPRISE DOMAIN CONTROLLERS",
        .pszSid = "S-1-5-9"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "SELF",
        .pszSid = "S-1-5-10"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "Authenticated Users",
        .pszSid = "S-1-5-11"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "RESTRICTED",
        .pszSid = "S-1-5-12"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "TERMINAL SERVER USER",
        .pszSid = "S-1-5-13"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "REMOTE INTERACTIVE LOGON",
        .pszSid = "S-1-5-14"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "This Organization",
        .pszSid = "S-1-5-15"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "IUSR",
        .pszSid = "S-1-5-17"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "SYSTEM",
        .pszSid = "S-1-5-18"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "LOCAL SERVICE",
        .pszSid = "S-1-5-19"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "NETWORK SERVICE",
        .pszSid = "S-1-5-20"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "NTLM Authentication",
        .pszSid = "S-1-5-64-10"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "SChannel Authentication",
        .pszSid = "S-1-5-64-14"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "Digest Authentication",
        .pszSid = "S-1-5-64-21"
    },
    {
        .pszDomain = WELLKNOWN_NT_AUTHORITY,
        .pszName = "Other Organization",
        .pszSid = "S-1-5-1000"
    }
};

DWORD
LsaSrvLookupWellknownSidByName(
    IN PCSTR pszDomain,
    IN PCSTR pszName,
    OUT OPTIONAL PWELLKNOWN_SID *ppWellknownSid
    )
{
    DWORD i = 0;
    PWELLKNOWN_SID pWellknownSid = NULL;

    if (LwRtlCStringIsNullOrEmpty(pszName))
    {
        goto error;
    }

    for (i = 0 ; i < sizeof(gWellknownSids) / sizeof(gWellknownSids[0]) ; i++)
    {
        if (LwRtlCStringIsEqual(
                pszName,
                gWellknownSids[i].pszName,
                FALSE))
        {
           if (LwRtlCStringIsNullOrEmpty(pszDomain))
           {
               pWellknownSid = &gWellknownSids[i];
           }
           else if (LwRtlCStringIsEqual(
                        pszDomain,
                        gWellknownSids[i].pszDomain,
                        FALSE))
           {
               pWellknownSid = &gWellknownSids[i];
           }

           break;
        }
    }

error:

    if (ppWellknownSid)
    {
        *ppWellknownSid = pWellknownSid;
    }
    return pWellknownSid ? ERROR_SUCCESS : ERROR_NONE_MAPPED;
}

DWORD
LsaSrvLookupWellknownSidBySidString(
    IN PCSTR pSid,
    OUT OPTIONAL PWELLKNOWN_SID *ppWellknownSid
    )
{
    DWORD i = 0;
    PWELLKNOWN_SID pWellknownSid = NULL;

    for (i = 0 ; i < sizeof(gWellknownSids) / sizeof(gWellknownSids[0]) ; i++)
    {
        if (LwRtlCStringIsEqual(pSid, gWellknownSids[i].pszSid, FALSE))
        {
           pWellknownSid = &gWellknownSids[i];

           break;
        }
    }

    if (ppWellknownSid)
    {
        *ppWellknownSid = pWellknownSid;
    }

    return pWellknownSid ? ERROR_SUCCESS : ERROR_NONE_MAPPED;
}

static
DWORD
LsaSrvMarshalWellknownSid(
    IN PWELLKNOWN_SID pWellknownSid,
    OUT PLSA_SECURITY_OBJECT *ppObject
    )
{
    DWORD dwError = 0;
    PLSA_SECURITY_OBJECT pObject = NULL;

    dwError = LwAllocateMemory(
        sizeof(*pObject),
        OUT_PPVOID(&pObject));
    BAIL_ON_LSA_ERROR(dwError);

    pObject->type = LSA_OBJECT_TYPE_WELLKNOWN;
    pObject->enabled = FALSE;
    pObject->bIsLocal = TRUE;

    if (LwRtlCStringIsNullOrEmpty(pWellknownSid->pszDomain))
    {
        dwError = LwAllocateString(
                      "",
                      &pObject->pszNetbiosDomainName);
        BAIL_ON_LSA_ERROR(dwError);

        dwError = LwAllocateString(
                      pWellknownSid->pszName,
                      &pObject->pszSamAccountName);
        BAIL_ON_LSA_ERROR(dwError);
    }
    else
    {
        dwError = LwAllocateString(
                      pWellknownSid->pszDomain,
                      &pObject->pszNetbiosDomainName);
        BAIL_ON_LSA_ERROR(dwError);

        dwError = LwAllocateStringPrintf(
                      &pObject->pszSamAccountName,
                      "%s\\%s",
                      pWellknownSid->pszDomain,
                      pWellknownSid->pszName);
        BAIL_ON_LSA_ERROR(dwError);
    }

    dwError = LwAllocateString(
                  pWellknownSid->pszSid,
                  &pObject->pszObjectSid);
    BAIL_ON_LSA_ERROR(dwError);

error:
    if (dwError)
    {
        if (pObject)
        {
            LsaUtilFreeSecurityObject(pObject);
            pObject = NULL;
        }
    }

    *ppObject = pObject;

    return dwError;
}

static
DWORD
LsaSrvFindWellknownSidByName(
    IN PCSTR pName,
    OUT PLSA_SECURITY_OBJECT *ppObject
    )
{
    DWORD dwError = 0;
    PLSA_SECURITY_OBJECT pObject = NULL;
    PWELLKNOWN_SID pWellknownSid = NULL;
    PLSA_LOGIN_NAME_INFO pLoginInfo = NULL;

    dwError = LsaSrvCrackDomainQualifiedName(
                  pName,
                  &pLoginInfo);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LsaSrvLookupWellknownSidByName(
                  pLoginInfo->pszDomain,
                  pLoginInfo->pszName,
                  &pWellknownSid);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LsaSrvMarshalWellknownSid(
                  pWellknownSid,
                  &pObject);
    BAIL_ON_LSA_ERROR(dwError);

error:

    if (pLoginInfo)
    {
        LsaSrvFreeNameInfo(pLoginInfo);
        pLoginInfo = NULL;
    }

    *ppObject = pObject;

    return dwError;
}

static
DWORD
LsaSrvFindWellknownSidBySid(
    IN PCSTR pSid,
    OUT PLSA_SECURITY_OBJECT *ppObject
    )
{
    DWORD dwError = 0;
    PLSA_SECURITY_OBJECT pObject = NULL;
    PWELLKNOWN_SID pWellknownSid = NULL;

    dwError = LsaSrvLookupWellknownSidBySidString(
                  pSid,
                  &pWellknownSid);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LsaSrvMarshalWellknownSid(
                  pWellknownSid,
                  &pObject);
    BAIL_ON_LSA_ERROR(dwError);

error:

    *ppObject = pObject;

    return dwError;
}

DWORD
LsaSrvFindObjectsWellknownSids(
    IN LSA_FIND_FLAGS FindFlags,
    IN OPTIONAL LSA_OBJECT_TYPE ObjectType,
    IN LSA_QUERY_TYPE QueryType,
    IN DWORD Count,
    IN LSA_QUERY_LIST QueryList,
    OUT PLSA_SECURITY_OBJECT** pppObjects
    )
{
    DWORD dwError = 0;
    PLSA_SECURITY_OBJECT* ppObjects = NULL;
    DWORD index = 0;

    switch (QueryType)
    {
    case LSA_QUERY_TYPE_BY_NT4:
    case LSA_QUERY_TYPE_BY_ALIAS:
    case LSA_QUERY_TYPE_BY_SID:
        break;
    default:
        dwError = LW_ERROR_NOT_HANDLED;
        BAIL_ON_LSA_ERROR(dwError);
    }

    dwError = LwAllocateMemory(
                  sizeof(*ppObjects) * Count,
                  OUT_PPVOID(&ppObjects));
    BAIL_ON_LSA_ERROR(dwError);

    for (index = 0 ; index < Count ; index++)
    {
       switch (QueryType)
       {
       case LSA_QUERY_TYPE_BY_ALIAS:
       case LSA_QUERY_TYPE_BY_NT4:
            dwError = LsaSrvFindWellknownSidByName(
                QueryList.ppszStrings[index],
                &ppObjects[index]);
            if (dwError == ERROR_NONE_MAPPED)
            {
                dwError = 0;
            }
            BAIL_ON_LSA_ERROR(dwError);

            break;

        case LSA_QUERY_TYPE_BY_SID:
            dwError = LsaSrvFindWellknownSidBySid(
                QueryList.ppszStrings[index],
                &ppObjects[index]);
            if (dwError == ERROR_NONE_MAPPED)
            {
                dwError = 0;
            }
            BAIL_ON_LSA_ERROR(dwError);

            break;
       }
    }

error:

    if (dwError)
    {
        LsaUtilFreeSecurityObjectList(Count, ppObjects);
        ppObjects = NULL;
    }

    *pppObjects = ppObjects;

    return dwError;
}

/*
local variables:
mode: c
c-basic-offset: 4
indent-tabs-mode: nil
tab-width: 4
end:
*/
