/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*-
 * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
 * Editor Settings: expandtabs and use 4 spaces for indentation */

/*
 * 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
 * <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
 * 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:
 *
 *        samdb.h
 *
 * Abstract:
 *
 *
 *      Likewise SAM Database Provider
 *
 *      SAM Database API
 *
 * Authors: Rafal Szczesniak (rafal@likewise.com)
 *          Danilo Almeida (dalmeida@likewise.com)
 *
 */

/**
 * @file samdb.h
 * @brief Security Accounts Manager Database API
 */

#ifndef __SAMDB_H__
#define __SAMDB_H__

LW_BEGIN_EXTERN_C

/**
 * @defgroup samdb Security Accounts Manager Database API
 * @ingroup oem
 * @brief Security Accounts Manager Database API
 */

/*@{*/

//
// Object Model
//
// SAMDB contains the following object types:
//
// Domain Objects - There are only two of these.  One is a named local
//   domain.  The other is the BUILTIN domain.
//
// User Objects - These represent a user.
//
// Local Group Objcets - These represent a local group.  In SAMR
//     terminology, this is an "alias".
//
// Every object has a SID and a (NetBIOS) domain name.  Non-domain
// objects also have a SamAccountName.
//

/**
 * @brief SamDb object type enumeration
 */
typedef enum _SAMDB_OBJECT_TYPE {
    /**
     * @brief Unknown object
     */
    SAMDB_OBJECT_TYPE_UNKNOWN,
    /**
     * @brief Domain object
     */
    SAMDB_OBJECT_TYPE_DOMAIN,
    /**
     * @brief User object
     */
    SAMDB_OBJECT_TYPE_USER,
    /**
     * @brief Local group object.
     * In SAMR paralance, an "alias" is a "local group" while a "group"
     * is a "domain group".  To make it clearer, we never use "group"
     * in this interface.
     */
    SAMDB_OBJECT_TYPE_LOCAL_GROUP,
} SAMDB_OBJECT_TYPE, *PSAMDB_OBJECT_TYPE;

/**
 * @brief SamDb query type enumeration
 */
typedef enum _SAMDB_QUERY_TYPE {
    /**
     * @brief Unknown query type
     */
    SAMDB_QUERY_TYPE_UNKNOWN,
    /**
     * @brief Query by SID
     */
    SAMDB_QUERY_TYPE_SID,
    /**
     * @brief Query by NT name (Object's Name or DOMAIN\SamAccountName)
     */
    SAMDB_QUERY_TYPE_NT_NAME,
    /**
     * @brief Query by unix id (User or Group Id)
     */
    SAMDB_QUERY_TYPE_UNIX_ID,
    // SAMDB_QUERY_TYPE_UNIX_NAME,
    /**
     * @brief Query by name. Cannot return domain object.
     * Only DOMAIN\SamAccountName.
     */
    SAMDB_QUERY_TYPE_NT_OR_UNIX_NAME,
} SAMDB_QUERY_TYPE, *PSAMDB_QUERY_TYPE;

/**
 * @brief SamDb query parameter.
 * Depending on query type this can be Object's Name or SamAccountName
 */
typedef union _SAMDB_QUERY {
    /**
     * @brief Name to query by.
     * Depending on query type this can be Object's Name or SamAccountName
     */
    PWSTR Name;
    /**
     * @brief SID to query by.
     */
    PSID Sid;
    /**
     * @brief Id to query by. Depending on object type this will be compared
     * to user or group unix id.
     */
    DWORD Id;
} SAMDB_QUERY, *PSAMDB_QUERY;

/**
 * @brief Sorting order that can be applied to the results of #SamDbEnumObjects
 * call.
 */
typedef enum _SAMDB_ENUM_SORT_ORDER {
    /**
     * @brief Returns objects in whatever order database returns them.
     */
    SAMDB_ENUM_SORT_ORDER_NONE = 0,
    /**
     * @brief Returns objects in ascending order by object name.
     */
    SAMDB_ENUM_SORT_ORDER_ASCENDING
} SAMDB_ENUM_SORT_ORDER, *PSAMDB_ENUM_SORT_ORDER;

/**
 * @brief SamDb unicode strings array type.
 */
typedef struct _SAMDB_STRING_ARRAY {
    DWORD Count;
    PWSTR* String;
} SAMDB_STRING_ARRAY, *PSAMDB_STRING_ARRAY;

/**
 * @brief Logon hours type. Specifies time units per week a user is allowed
 * to login.
 */
typedef struct _SAMDB_LOGON_HOURS {
    DWORD UnitsPerWeek;
    PBOOLEAN LogonHours;
} SAMDB_LOGON_HOURS, *PSAMDB_LOGON_HOURS;

/**
 * @brief Fixed-length blob resulting from passing user password to one-way
 * function. Commonly referred to as "password hash".
 */
typedef struct _SAMDB_OWF_PASSWORD {
    BOOLEAN IsPresent;
    BYTE Data[16];
} SAMDB_OWF_PASSWORD, *PSAMDB_OWF_PASSWORD;

/**
 * @brief SamDb blob type.
 */
typedef struct _SAMDB_BLOB {
    USHORT Size;
    PVOID Data;
} SAMDB_BLOB, *PSAMDB_BLOB;

/**
 * @brief Unix user info
 */
typedef struct _SAMDB_UNIX_USER_INFO {
    DWORD Uid;
    PWSTR HomeDirectory;
    PWSTR Shell;
    PWSTR Gecos;
} SAMDB_UNIX_USER_INFO, *PSAMDB_UNIX_USER_INFO;

/**
 * @brief Unix group info
 */
typedef struct _SAMDB_UNIX_GROUP_INFO {
    DWORD Gid;
} SAMDB_UNIX_GROUP_INFO, *PSAMDB_UNIX_GROUP_INFO;

/**
 * @brief userAccountControl flags type. Stored in the database and in Windows.
 */
typedef ULONG SAMDB_UF_FLAGS, *PSAMDB_UF_FLAGS;

// Mapping: SAMDB_UF_FLAG_XXX == UF_XXX in [MS-SAMR]
#define SAMDB_UF_FLAG_SCRIPT                            0x00000001 // IGNORE (therefore unmapped)
#define SAMDB_UF_FLAG_ACCOUNTDISABLE                    0x00000002
#define SAMDB_UF_FLAG_HOMEDIR_REQUIRED                  0x00000008
#define SAMDB_UF_FLAG_LOCKOUT                           0x00000010
#define SAMDB_UF_FLAG_PASSWD_NOTREQD                    0x00000020
#define SAMDB_UF_FLAG_PASSWD_CANT_CHANGE                0x00000040 // Not mapped above!
#define SAMDB_UF_FLAG_ENCRYPTED_TEXT_PASSWORD_ALLOWED   0x00000080
#define SAMDB_UF_FLAG_TEMP_DUPLICATE_ACCOUNT            0x00000100
#define SAMDB_UF_FLAG_NORMAL_ACCOUNT                    0x00000200
#define SAMDB_UF_FLAG_INTERDOMAIN_TRUST_ACCOUNT         0x00000800
#define SAMDB_UF_FLAG_WORKSTATION_TRUST_ACCOUNT         0x00001000
#define SAMDB_UF_FLAG_SERVER_TRUST_ACCOUNT              0x00002000
#define SAMDB_UF_FLAG_DONT_EXPIRE_PASSWD                0x00010000
#define SAMDB_UF_FLAG_MNS_LOGON_ACCOUNT                 0x00020000
#define SAMDB_UF_FLAG_SMARTCARD_REQUIRED                0x00040000
#define SAMDB_UF_FLAG_TRUSTED_FOR_DELEGATION            0x00080000
#define SAMDB_UF_FLAG_NOT_DELEGATED                     0x00100000
#define SAMDB_UF_FLAG_USE_DES_KEY_ONLY                  0x00200000
#define SAMDB_UF_FLAG_DONT_REQUIRE_PREAUTH              0x00400000
#define SAMDB_UF_FLAG_PASSWORD_EXPIRED                  0x00800000
#define SAMDB_UF_FLAG_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION    0x01000000
#define SAMDB_UF_FLAG_NO_AUTH_DATA_REQUIRED             0x02000000
#define SAMDB_UF_FLAG_PARTIAL_SECRETS_ACCOUNT           0x04000000
#define SAMDB_UF_FLAG_USE_AES_KEYS                      0x08000000

/**
 * @brief SAMR UserAccountControl flags type. Used in SAMR RPC calls.
 */
typedef ULONG SAMDB_USER_FLAGS, *PSAMDB_USER_FLAGS;

// Mapping: SAMDB_USER_FLAG_XXX == USER_XXX in [MS-SAMR]
#define SAMDB_USER_FLAG_ACCOUNT_DISABLED                0x00000001 // is disabled
#define SAMDB_USER_FLAG_HOME_DIRECTORY_REQUIRED         0x00000002 // home directory is required
#define SAMDB_USER_FLAG_PASSWORD_NOT_REQUIRED           0x00000004 // ignore password length policy
#define SAMDB_USER_FLAG_TEMP_DUPLICATE_ACCOUNT          0x00000008 // IGNORE
#define SAMDB_USER_FLAG_NORMAL_ACCOUNT                  0x00000010 // is not a computer object
#define SAMDB_USER_FLAG_MNS_LOGON_ACCOUNT               0x00000020 // IGNORE
#define SAMDB_USER_FLAG_INTERDOMAIN_TRUST_ACCOUNT       0x00000040 // is domain trust object
#define SAMDB_USER_FLAG_WORKSTATION_TRUST_ACCOUNT       0x00000080 // is member workstation or server
#define SAMDB_USER_FLAG_SERVER_TRUST_ACCOUNT            0x00000100 // is a domain controller
#define SAMDB_USER_FLAG_DONT_EXPIRE_PASSWORD            0x00000200 // password does not expire
#define SAMDB_USER_FLAG_ACCOUNT_AUTO_LOCKED             0x00000400 // is locked out
#define SAMDB_USER_FLAG_ENCRYPTED_TEXT_PASSWORD_ALLOWED 0x00000800 // allow clear text password (can be encrypted, but must be reversible)
#define SAMDB_USER_FLAG_SMARTCARD_REQUIRED              0x00001000 // must use smart card for auth
#define SAMDB_USER_FLAG_TRUSTED_FOR_DELEGATION          0x00002000 // Kerberos - set ok-as-delegate flag in tickets
#define SAMDB_USER_FLAG_NOT_DELEGATED                   0x00004000 // Kerberos - do not allow proxiable/forwardable TGT
#define SAMDB_USER_FLAG_USE_DES_KEY_ONLY                0x00008000 // Kerberos - only use des-cbc-md5 or des-cbc-crc keys
#define SAMDB_USER_FLAG_DONT_REQUIRE_PREAUTH            0x00010000 // Kerberos - do not require preauth
#define SAMDB_USER_FLAG_PASSWORD_EXPIRED                0x00020000 // password has expired
#define SAMDB_USER_FLAG_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION  0x00040000 // Kerberos - ???
#define SAMDB_USER_FLAG_NO_AUTH_DATA_REQUIRED           0x00080000 // Kerberos - Do not include PAC in service tickets
#define SAMDB_USER_FLAG_PARTIAL_SECRETS_ACCOUNT         0x00100000 // is a read-only domain controller (RODC)
#define SAMDB_USER_FLAG_USE_AES_KEYS                    0x00200000 // IGNORE

/**
 * @brief Likewise-specific flags type.
 */
typedef DWORD SAMDB_LIKEWISE_FLAGS, *PSAMDB_LIKEWISE_FLAGS;
#define SAMDB_LIKEWISE_FLAG_UNIX_ENABLED                0x00000001 // User or local group has a unix id

/**
 * @brief SamDb Domain info type.
 */
typedef struct _SAMDB_DOMAIN_INFO {
    /**
     * @brief This number is read-only and is updated internally only
     */
    ULONG64 SequenceNumber;
    DWORD MinPasswordLength;
    DWORD PasswordHistoryLength;
    LONG64 MinPasswordAge;
    LONG64 MaxPasswordAge;
    LONG64 PasswordChangeTime;
    DWORD PasswordProperties;
    DWORD LockoutThreshold;
    LONG64 LockoutDuration;
    LONG64 LockoutWindow;
    PWSTR Comment;
} SAMDB_DOMAIN_INFO;

/**
 * @brief SamDb User info. Defines Windows side of user account.
 */
typedef struct _SAMDB_USER_INFO {
    //
    // Time values - 0 means n/a or never
    //

    /**
     * @brief Read-only. Currently always 0
     */
    LONG64 LastLogon;
    /**
     * @brief Read-only. Currently always 0
     */
    LONG64 LastLogoff;
    /**
     * @brief Set to zero to enforce password change at nearest logon.
     * Value 0x7FFFFFFFFFFFFFFF means the password never expires.
     */
    LONG64 PasswordLastSet;
    /**
     * @brief 0x7FFFFFFFFFFFFFFF means the account never expires.
     */
    LONG64 AccountExpires;

    //
    // Strings or String Arrays
    //

    PWSTR FullName;
    /**
     * @brief Windows home directory
     */
    PWSTR HomeDirectory;
    PWSTR HomeDirectoryDrive;
    PWSTR ScriptPath;
    PWSTR ProfilePath;
    /**
     * @brief Account description (can only be updated by administrator)
     */
    PWSTR Description;
    SAMDB_STRING_ARRAY Workstations;
    /**
     * @brief User comment. Unlike Description it can be updated by user.
     */
    PWSTR UserComment;

    /**
     * @brief LM OWF password.
     */
    SAMDB_OWF_PASSWORD LmOwfPassword;
    /**
     * @brief NT OWF password.
     */
    SAMDB_OWF_PASSWORD NtOwfPassword;

    //
    // Blobs
    //

    // Current Likewise implementation does not allow blob.
    SAMDB_BLOB Parameters;
    // SAMDB_BLOB PrivateData; // cannot actually be used

    //
    // Misc.
    //

    ULONG PrimaryGroupRid;
    SAMDB_UF_FLAGS UserAccountControl;
    SAMDB_LOGON_HOURS LogonHours;
    // currently read-only, always 0
    ULONG BadPasswordCount;
    // currently read-only, always 0
    ULONG LogonCount;
    USHORT CountryCode;
    USHORT CodePage;

    //
    // Unix Info - NULL if not present
    //

    PSAMDB_UNIX_USER_INFO UnixInfo;

    //
    // Likewise specific flags
    //
    SAMDB_LIKEWISE_FLAGS LikewiseFlags;

} SAMDB_USER_INFO, *PSAMDB_USER_INFO;


/**
 * @brief SamDb Local Group info. Defines Windows side of local group account.
 */
typedef struct _SAMDB_LOCAL_GROUP_INFO {
    PWSTR Description;

    //
    // Unix Info - NULL if not present
    //

    /**
     * @brief Unix side of local user account.
     * NULL if not present (user is not unix-enabled).
     */
    PSAMDB_UNIX_GROUP_INFO UnixInfo;

    /**
     * @brief Likewise specific flags
     */
    SAMDB_LIKEWISE_FLAGS LikewiseFlags;

} SAMDB_LOCAL_GROUP_INFO, *PSAMDB_LOCAL_GROUP_INFO;


/**
 * @brief SamDb Object info.
 * Encapsulates all object types returned from SamDb API
 */
typedef struct _SAMDB_OBJECT_INFO {
    /**
     * @brief Read-only
     */
    SAMDB_OBJECT_TYPE Type;
    /**
     * @brief Read-only
     */
    PSID Sid;
     // NetBIOS domain name for domain object else SamAccountName
    /**
     * @brief Object name.
     * NetBIOS domain name if Type == SAMDB_OBJECT_TYPE_DOMAIN.
     * Undefined if Type == SAMDB_OBJECT_UNKNOWN.
     * SamAccountName otherwise.
     */
    PWSTR Name;
    union {
        SAMDB_DOMAIN_INFO Domain;
        SAMDB_USER_INFO User;
        SAMDB_LOCAL_GROUP_INFO LocalGroup;
    } Info;
} SAMDB_OBJECT_INFO, *PSAMDB_OBJECT_INFO;


typedef ULONG SAMDB_FIELDS, *PSAMDB_FIELDS;

#define SAMDB_FIELD_OBJECT_MASK                             0x80000000
#define SAMDB_FIELD_SPECIFIC_MASK                           0x7FFFFFFF

// Fields in SAMDB_OBJECT_INFO type
// Note that object type and SID must always be present and cannot change.
#define SAMDB_FIELD_OBJECT_NAME                             0x80000000

// Fields in SAMDB_DOMAIN_INFO type
#define SAMDB_FIELD_DOMAIN_MIN_PASSWORD_LENGTH              0x00000001
#define SAMDB_FIELD_DOMAIN_PASSWORD_HISTORY_LENGTH          0x00000002
#define SAMDB_FIELD_DOMAIN_MIN_PASSWORD_AGE                 0x00000004
#define SAMDB_FIELD_DOMAIN_MAX_PASSWORD_AGE                 0x00000008
#define SAMDB_FIELD_DOMAIN_PASSWORD_CHANGE_TIME             0x00000010
#define SAMDB_FIELD_DOMAIN_LOCKOUT_THRESHOLD                0x00000020
#define SAMDB_FIELD_DOMAIN_LOCKOUT_DURATION                 0x00000040
#define SAMDB_FIELD_DOMAIN_LOCKOUT_WINDOW                   0x00000080
#define SAMDB_FIELD_DOMAIN_COMMENT                          0x00000100

// Fields in SAMDB_USER_INFO type
#define SAMDB_FIELD_USER_LAST_LOGON                         0x00000001
#define SAMDB_FIELD_USER_LAST_LOGOFF                        0x00000002
#define SAMDB_FIELD_USER_PASSWORD_LAST_SET                  0x00000004
#define SAMDB_FIELD_USER_ACCOUNT_EXPIRES                    0x00000008
#define SAMDB_FIELD_USER_FULL_NAME                          0x00000010
#define SAMDB_FIELD_USER_HOME_DIRECTORY                     0x00000020
#define SAMDB_FIELD_USER_HOME_DIRECTORY_DRIVE               0x00000040
#define SAMDB_FIELD_USER_SCRIPT_PATH                        0x00000080
#define SAMDB_FIELD_USER_PROFILE_PATH                       0x00000100
#define SAMDB_FIELD_USER_DESCRIPTION                        0x00000200
#define SAMDB_FIELD_USER_WORKSTATIONS                       0x00000400
#define SAMDB_FIELD_USER_USER_COMMENT                       0x00000800
#define SAMDB_FIELD_USER_LM_OWF_PASSWORD                    0x00001000
#define SAMDB_FIELD_USER_NT_OWF_PASSWORD                    0x00002000
#define SAMDB_FIELD_USER_PARAMETERS                         0x00004000
#define SAMDB_FIELD_USER_PRIMARY_GROUP_RID                  0x00008000
#define SAMDB_FIELD_USER_ACCOUNT_CONTROL                    0x00010000
#define SAMDB_FIELD_USER_LOGON_HOURS                        0x00020000
#define SAMDB_FIELD_USER_BAD_PASSWORD_COUNT                 0x00040000
#define SAMDB_FIELD_USER_LOGON_COUNT                        0x00080000
#define SAMDB_FIELD_USER_COUNTRY_CODE                       0x00100000
#define SAMDB_FIELD_USER_CODE_PAGE                          0x00200000
#define SAMDB_FIELD_USER_UNIX_UID                           0x00400000
#define SAMDB_FIELD_USER_UNIX_HOME_DIRECTORY                0x01000000
#define SAMDB_FIELD_USER_UNIX_SHELL                         0x02000000
#define SAMDB_FIELD_USER_UNIX_GECOS                         0x04000000
#define SAMDB_FIELD_USER_LIKEWISE_FLAGS                     0x08000000

// Fields in SAMDB_LOCAL_GROUP_INFO type
#define SAMDB_FIELD_LOCAL_GROUP_DESCRIPTION                 0x00000001
#define SAMDB_FIELD_LOCAL_GROUP_UNIX_GID                    0x00000002
#define SAMDB_FIELD_LOCAL_GROUP_LIKEWISE_FLAGS              0x00000004


//
// Functions
//

/**
 * @brief Callback function to be called when an object identified
 * by ObjectSid changes.
 *
 * @param[in] Context an optional context passed to the callback
 * @param[in] ObjectSid SID identifying an object that has changed
 */
typedef
VOID
(*SAMDB_RELOAD_CALLBACK)(
    IN PVOID Context,
    IN PSID ObjectSid
    );

typedef struct _SAMDB_CALLBACK_REGISTRATION
SAMDB_CALLBACK_REGISTRATION, *PSAMDB_CALLBACK_REGISTRATION;

/**
 * @brief Register new callback function.
 *
 * @param[out] Registration opaque registration handle than can be passed to
 * #SamDbUnregisterCallback to unregister the callback
 * @param[in] Context an optional context passed to the callback
 * @param[in] ObjectSid SID identifying object a callback is going to be subscribed for
 * @param[in] IsPrefix TRUE if the callback is supposed to be called when object with
 * ObjectSid or any other object with SID which ObjectSid is a prefix of has changed.
 * FALSE if only a change of object with ObjectSid matters.
 * @param[in] ReloadCallback Pointer to callback function
 */
DWORD
SamDbRegisterCallback(
    OUT PSAMDB_CALLBACK_REGISTRATION* Registration,
    IN PVOID Context,
    IN PSID ObjectSid,
    IN BOOLEAN IsPrefix,
    IN SAMDB_RELOAD_CALLBACK ReloadCallback
    );

/**
 * @brief Unregister existing callback function.
 *
 * @param[in] Registration opaque registration handle returned from #SamDbRegisterCallback
 */
VOID
SamDbUnregisterCallback(
    IN PSAMDB_CALLBACK_REGISTRATION Registration
    );


// Ensure that we support read-only samdb.

// Normally, the input object should not have a SID.
// ASSERT(LOGICAL_XOR(Object->Sid, Sid)).

/**
 * @brief Add new object to sam database.
 *
 * Only user or local group objects can be added.
 *
 * @param[in] Object new object to be added to the database.
 * @param[in] Sid optional SID of the new object to be added.
 * Generated automatically, if NULL.
 */
DWORD
SamDbAddObject(
    IN PSAMDB_OBJECT_INFO Object,
    IN OPTIONAL PSID Sid
    );


/**
 * @brief Update existing object in sam database.
 *
 * @param[in] Object object to be updated with Object->Sid pointing to the object.
 * @param[in] UpdateFields flags specifying fields to be considered for update.
 * Note: BUILTIN domain name cannot be updated
 */
DWORD
SamDbUpdateObject(
    IN PSAMDB_OBJECT_INFO Object,
    IN SAMDB_FIELDS UpdateFields
    );


// This called by 2 different components:
// - local provider
// - SAMR RPC code

/**
 * @brief Find existing objects in sam database.
 *
 * @param[in] ObjectType object type to look for. Can be SAMDB_OBJECT_TYPE_UNKNOWN
 * if any object type is considered
 * @param[in] QueryType type of query to use
 * @param[in] QueryCount number of queries to perform
 * @param[in] QueryList pointer to QueryCount long array of queries specifying
 * objects to look for
 * @param[out] pObjects returned QueryCount long array of objects found. If array
 * element is non-NULL, then the corresponding object has been found. NULL otherwise
 * (array has to be freed by #SamDbFreeObjects)
 */
DWORD
SamDbFindObjects(
    IN SAMDB_OBJECT_TYPE ObjectType,
    IN SAMDB_QUERY_TYPE QueryType,
    IN DWORD QueryCount,
    IN PSAMDB_QUERY QueryList,
    OUT PSAMDB_OBJECT_INFO** pObjects
    );


/**
 * @brief Delete existing object from sam database.
 *
 * @param[in] Sid SID of an object to be deleted
 */
DWORD
SamDbDeleteObject(
    IN PSID Sid
    );


/**
 * @brief Query the list of local group members.
 *
 * @param[in] Sid local group SID to be queried
 * @param[out] MembersCount number of members found in local group
 * @param[out] Members array of pointers to member SIDs
 * @retval ERROR_SUCCESS success
 * @retval ERROR_NO_SUCH_GROUP a group identified by Sid does not exist
 * in the database
 */
DWORD
SamDbQueryMembers(
    IN PSID Sid,
    OUT PDWORD MembersCount,
    OUT PSID** Members
    );


/**
 * @brief Query the list of an object memberships in local groups.
 * An object can either be user account or foreign security principal
 * (e.g. domain user or group).
 *
 * @param[in] Sid object SID
 * @param[out] MemberOfCount number of local group memberships found
 * @param[out] MemberOf array of pointers to local group SIDs
 */
DWORD
SamDbQueryMemberOf(
    IN PSID Sid,
    OUT PDWORD MemberOfCount,
    OUT PSID** MemberOf
    );


/**
 * @brief Update members list of a local group
 *
 * @param[in] Sid local group SID
 * @param[in] AddMembersCount number of members to be added to the local group
 * @param[in] AddMembers array of pointers to new member SIDs
 * @param[in] RemoveMembersCount number of members to be removed
 * from the local group
 * @param[in] RemoveMembers array of pointers to member SIDs to be
 * removed from the local group
 */
DWORD
SamDbUpdateMembers(
    IN PSID Sid,
    IN DWORD AddMembersCount,
    IN OPTIONAL PSID* AddMembers,
    IN DWORD RemoveMembersCount,
    IN OPTIONAL PSID* RemoveMembers
    );


/**
 * @brief Opaque enumeration handle type returned from #SamDbOpenEnumObjects
 * and passed to #SamDbEnumObjects and #SamDbCloseEnum.
 */
typedef struct _SAMDB_ENUM_HANDLE_DATA *SAMDB_ENUM_HANDLE;
typedef SAMDB_ENUM_HANDLE *PSAMDB_ENUM_HANDLE;


/**
 * @brief Opens enumeration handle with specified enumeration parameters.
 *
 * Returned EnumHandle has to be closed by #SamDbCloseEnum.
 *
 * @param[in] DomainSid optional SID of domain which can be used to limit
 * the scope of objects enumerated
 * @param[in] ObjectType type of objects to be returned (all other types
 * will be filtered out)
 * @param[in] SortOrder type of sorting order applied to returned results
 * @param[out] EnumHandle opaque enumeration handle
 */
DWORD
SamDbOpenEnumObjects(
    IN OPTIONAL PSID DomainSid,
    IN SAMDB_OBJECT_TYPE ObjectType,
    IN SAMDB_ENUM_SORT_ORDER SortOrder,
    OUT PSAMDB_ENUM_HANDLE EnumHandle
    );


/**
 * @brief Enumerates objects found in the database.
 *
 * @param[in] EnumHandle enumeration handle returned from #SamDbOpenEnumObjects
 * @param[in] MaxCount max number of objects to be returned
 * @param[out] ObjectsCount number of objects returned
 * @param[out] Objects array of pointers to objects returned (has to be freed
 * by #SamDbFreeObjects)
 * @retval ERROR_SUCCESS all requested objects have been enumerated.
 * @retval ERROR_MORE_DATA not all requested objecs have been enumerated
 * (#SamDbEnumObjects needs to be called again)
 * @retval ERROR_NO_MORE_ITEMS there's no more objects left to enumerate
 */
DWORD
SamDbEnumObjects(
    IN SAMDB_ENUM_HANDLE EnumHandle,
    IN DWORD MaxCount,
    OUT PDWORD ObjectsCount,
    OUT PSAMDB_OBJECT_INFO** Objects
    );


/**
 * @brief Closes enumeration handle and frees its associated resources.
 *
 * @param[in] EnumHandle enumeration handle returned from #SamDbOpenEnumObjects
 */
VOID
SamDbCloseEnum(
    IN SAMDB_ENUM_HANDLE EnumHandle
    );


/**
 * @brief Returns security descriptor information of an object.
 *
 * @param[in] Sid SID identifying the object
 * @param[in] SecurityInformation type of information from security descriptor
 * to be returned
 * @param[out] pSecurityDescriptor address where pointer to relative security
 * descriptor should be returned (has to be freed by #SamDbFree)
 */
DWORD
SamDbQuerySecurityDescriptor(
    IN PSID Sid,
    IN SECURITY_INFORMATION SecurityInformation,
    OUT PSECURITY_DESCRIPTOR_RELATIVE* pSecurityDescriptor
    );


/**
 * @brief Sets security descriptor information to an object.
 *
 * @param[in] Sid SID identifying the object
 * @param[in] SecurityInformation type of information in security descriptor
 * to be set
 * @param[in] SecurityDescriptor pointer to relative security descriptor
 * to be set
 */
DWORD
SamDbSetSecurityDescriptor(
    IN PSID Sid,
    IN SECURITY_INFORMATION SecurityInformation,
    IN PSECURITY_DESCRIPTOR_RELATIVE SecurityDescriptor
    );


/**
 * @brief Changes local domain name and/or local domain SID.
 *
 * @param[in] DomainName (optional) new local domain name
 * @param[in] DomainSid (optional) new local domain SID
 */
DWORD
SamDbChangeDomainNameSid(
    IN OPTIONAL PWSTR DomainName,
    IN OPTIONAL PSID DomainSid
    );


//
// Init and cleanup functions. They are optional, so implementers
// may choose to call them to make sure the library is ready to
// use before actually calling any of APIs.
//

/**
 * @brief Init function. It is optional and can be called to make
 * sure the database is in fully operational condition before calling
 * any of APIs.
 */
DWORD
SamDbInitializeLibrary(
    VOID
    );


/**
 * @brief Cleanup function. It is optional and can be called to enforce
 * freeing all internal resources of SamDb library.
 */
VOID
SamDbCleanupLibrary(
    VOID
    );


//
// User account control flags mapping functions. SAMDB_UF_FLAGS is
// used by SamDb APIs. SAMDB_USER_FLAGS may be used by older APIs,
// like Samr.
//

/**
 * @brief Function mapping older #SAMDB_USER_FLAGS to #SAMDB_UF_FLAGS
 * used by SamDB APIs.
 *
 * @param[in] Flags #SAMDB_USER_FLAGS to map
 * @param[out] Remaining optional address where any flags that couldn't
 * be mapped are returned
 */
SAMDB_UF_FLAGS
SamDbMapSamrToDatabaseFlags(
    IN SAMDB_USER_FLAGS Flags,
    OUT OPTIONAL PSAMDB_USER_FLAGS Remaining
    );


/**
 * @brief Function mapping #SAMDB_UF_FLAGS used by SamDB APIs to older
 * #SAMDB_USER_FLAGS.
 *
 * @param[in] Flags #SAMDB_UF_FLAGS to map
 * @param[out] Remaining optional address where any flags that couldn't
 * be mapped are returned
 */
SAMDB_USER_FLAGS
SamDbMapDatabaseToSamrFlags(
    IN SAMDB_UF_FLAGS Flags,
    OUT OPTIONAL PSAMDB_UF_FLAGS Remaining
    );


//
// Functions freeing returned buffers
//

// For a simple data type (such as SID from SamDbAddObject or
// SD from SamDbQuerySecurityDescriptor).

/**
 * @brief Frees simple pointers like security descriptor from
 * #SamDbQuerySecurityDescriptor
 *
 * @param[in] Memory pointer to free
 */
VOID
SamDbFree(
    IN PVOID Memory
    );


/**
 * @brief Frees array of pointers to SamDb objects returned from
 * #SamDbFindObjects and #SamDbEnumObjects.
 *
 * @param[in] ObjectsCount number of objects in array
 * @param[in] Objects array of pointers to objects to free
 */
VOID
SamDbFreeObjects(
    IN DWORD ObjectsCount,
    IN PSAMDB_OBJECT_INFO* Objects
    );


/**
 * @brief Frees a pointer to SamDb object.
 *
 * @param[in] Object pointers to the object
 */
VOID
SamDbFreeObject(
    IN PSAMDB_OBJECT_INFO Object
    );


/**
 * @brief Frees all the contents of the Object but not the pointer itself.
 *
 * @param[in] Object pointer to the object
 */
VOID
SamDbReleaseObject(
    PSAMDB_OBJECT_INFO Object
    );



// For SamDbQueryMembers and SamDbQueryMemberOf
/**
 * @brief Frees array of SIDs returned from #SamDbQueryMembers or
 * #SamDbQueryMemberOf
 *
 * @param[in] SidsCount number of SID pointers in array
 * @param[in] Sids pointer to array of SID pointers
 */
VOID
SamDbFreeSidList(
    IN DWORD SidsCount,
    IN PSID* Sids
    );

/*@}*/

LW_END_EXTERN_C

#endif /* __SAMDB_H__ */
