sddlparse

package module
v1.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 29, 2024 License: MIT Imports: 6 Imported by: 0

README

GoDoc

Basic SDDL parsing functionality for AD SDDLs in Go

This library provides functions to parse and modify the SDDL format, centered around Active Directory Access Control Lists (ACLs).

Features

  • Parse SDDL strings into a structured format
  • Modify the structured format
  • Convert the structured format back to SDDL strings
  • Parse SDDL binary data into a structured format
  • Convert the structured format back to SDDL binary data

Usage

Given a base64 output from ldapsearch, or a binary format from a library such as Go LDAP, you can parse the binary data into a structured format:

package main

import (
    parser "github.com/huner2/go-sddlparse"
)

func main() {
    b64 = "base64 encoded SDDL"
    sddl, err := parser.SDDLFromBase64Encoded(b64)
    if err != nil {
        panic(err)
    }
    // Do something with the SDDL, such as add a new ACE
    sddl.DACL = append(sddl.DACL, &parser.ACE{
        Type: parser.ACETYPE_ACCESS_ALLOWED,
        Flags: 0,
        Mask: parser.ACEMASK_GENERIC_ALL,
        SID: "S-1-5-32-544",
    })

    // Convert the SDDL to binary
    bin, err = sddl.ToBinary()
    if err != nil {
        panic(err)
    }
}

The same can be done with a SDDL string, using SDDLFromString.

An example using the go-ldap library:

package main

import (
    "github.com/go-ldap/ldap/v3"
    parser "github.com/huner2/go-sddlparse"
    "log"
)

func main() {
    conn, err := ldap.DialURL("ldap://10.137.137.2")
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    err = conn.Bind("testuser@test.test", "testpassword")
    if err != nil {
        log.Fatal(err)
    }
    searchRequest := ldap.NewSearchRequest(
        "DC=test,DC=test",
        ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
        "(objectClass=*)",
        []string{"nTSecurityDescriptor"},
        nil,
    )
    sr, err := conn.Search(searchRequest)
    if err != nil {
        log.Fatal(err)
    }
    descriptor := sr.Entries[0].GetAttributeValue("nTSecurityDescriptor")
    sddl, err := parser.SDDLFromBinary([]byte(descriptor))
    if err != nil {
        log.Fatal(err)
    }
}

License

This library is licensed under the MIT license. See the LICENSE file for more details.

Documentation

Index

Constants

View Source
const (
	SDDL_OWNERDEFAULTED = 1 << iota
	SDDL_GROUPDEFAULTED
	SDDL_DACLPRESENT
	SDDL_DACLDEFAULTED
	SDDL_SACLPRESENT
	SDDL_SACLDEFAULTED
	SDDL_SERVERSECURITY
	SDDL_DACLTRUSTED
	SDDL_DACLINHERITANCEREQUIRED
	SDDL_INHERITEANCEREQUIRED
	SDDL_DACLAUTOINHERITED
	SDDL_SACLAUTOINHERITED
	SDDL_DACLPROTECTED
	SDDL_SACLPROTECTED
	SDDL_CONTROLVALID
	SDDL_SELFRELATIVE
)

SDDL Control Flags

Variables

This section is empty.

Functions

This section is empty.

Types

type ACE

type ACE struct {
	// Common fields
	Type       AceType
	Flags      AceFlag
	AccessMask AccessMask
	SID        string

	// Object-specific fields
	ObjectType          GUID
	InheritedObjectType GUID
	ObjectFlags         ObjectFlag

	// Callback-specific fields
	ApplicationData []byte

	// System-resource-specific fields
	AttributeData []byte
}

ACE is an Access Control Entry. This is a simplified version of the Windows ACE structure.

This struct contains all fields for all the covered ACE types. Only the fields for the resolved ACE type will be populated.

func (*ACE) MustString

func (ace *ACE) MustString() (string, error)

MustString returns the ACE as a string. Returns an error if the ACE has unhandled elements.

func (*ACE) String

func (ace *ACE) String() string

String returns the ACE as a string. Shortcut for MustString, returning an empty string on error.

type ACL

type ACL []*ACE

ACL represents a Windows ACL. Simplified to a slice of ACEs.

type AccessMask

type AccessMask uint32

Access Mask Flags

const (
	ACCESS_MASK_GENERIC_READ           AccessMask = 0x80000000
	ACCESS_MASK_GENERIC_WRITE          AccessMask = 0x40000000
	ACCESS_MASK_GENERIC_EXECUTE        AccessMask = 0x20000000
	ACCESS_MASK_GENERIC_ALL            AccessMask = 0x10000000
	ACCESS_MASK_MAXIMUM_ALLOWED        AccessMask = 0x02000000
	ACCESS_MASK_ACCESS_SYSTEM_SECURITY AccessMask = 0x01000000
	ACCESS_MASK_SYNCHRONIZE            AccessMask = 0x00100000
	ACCESS_MASK_WRITE_OWNER            AccessMask = 0x00080000
	ACCESS_MASK_WRITE_DACL             AccessMask = 0x00040000
	ACCESS_MASK_READ_CONTROL           AccessMask = 0x00020000
	ACCESS_MASK_DELETE                 AccessMask = 0x00010000

	ACCESS_MASK_ADS_RIGHT_DS_CREATE_CHILD   AccessMask = 0x00000001
	ACCESS_MASK_ADS_RIGHT_DS_DELETE_CHILD   AccessMask = 0x00000002
	ACCESS_MASK_ADS_RIGHT_DS_LIST_CONTENTS  AccessMask = 0x00000004
	ACCESS_MASK_ADS_RIGHT_DS_SELF           AccessMask = 0x00000008
	ACCESS_MASK_ADS_RIGHT_DS_READ_PROP      AccessMask = 0x00000010
	ACCESS_MASK_ADS_RIGHT_DS_WRITE_PROP     AccessMask = 0x00000020
	ACCESS_MASK_ADS_RIGHT_DS_DELETE_TREE    AccessMask = 0x00000040
	ACCESS_MASK_ADS_RIGHT_DS_LIST_OBJECT    AccessMask = 0x00000080
	ACCESS_MASK_ADS_RIGHT_DS_CONTROL_ACCESS AccessMask = 0x00000100
)

func (*AccessMask) MustString

func (mask *AccessMask) MustString() (string, error)

MustString returns the access mask as a string. If the access mask is not known or it doesn't have a string representation, it returns an error.

func (*AccessMask) String

func (mask *AccessMask) String() string

String returns the access mask as a string. If the access mask is not known, it returns the mask as a hex string.

type AceFlag

type AceFlag byte

Ace Flags

const (
	ACEFLAG_OBJECT_INHERIT       AceFlag = 0x01
	ACEFLAG_CONTAINER_INHERIT    AceFlag = 0x02
	ACEFLAG_NO_PROPAGATE_INHERIT AceFlag = 0x04
	ACEFLAG_INHERIT_ONLY         AceFlag = 0x08
	ACEFLAG_INHERITED            AceFlag = 0x10
	ACEFLAG_SUCCESSFUL_ACCESS    AceFlag = 0x40
	ACEFLAG_FAILED_ACCESS        AceFlag = 0x80
)

func (*AceFlag) MustString

func (aceFlag *AceFlag) MustString() (string, error)

MustString returns the ACE flag as a string. If the ACE flag is not known or it doesn't have a string representation, it returns an error.

func (*AceFlag) String

func (aceFlag *AceFlag) String() string

String returns the ACE flag as a string. If the ACE flag is not known, it returns the flag as a hex string.

type AceType

type AceType byte

Ace Types

const (
	ACETYPE_ACCESS_ALLOWED AceType = iota
	ACETYPE_ACCESS_DENIED
	ACETYPE_SYSTEM_AUDIT
	ACETYPE_SYSTEM_ALARM
	ACETYPE_ACCESS_ALLOWED_COMPOUND
	ACETYPE_ACCESS_ALLOWED_OBJECT
	ACETYPE_ACCESS_DENIED_OBJECT
	ACETYPE_SYSTEM_AUDIT_OBJECT
	ACETYPE_SYSTEM_ALARM_OBJECT
	ACETYPE_ACCESS_ALLOWED_CALLBACK
	ACETYPE_ACCESS_DENIED_CALLBACK
	ACETYPE_ACCESS_ALLOWED_CALLBACK_OBJECT
	ACETYPE_ACCESS_DENIED_CALLBACK_OBJECT
	ACETYPE_SYSTEM_AUDIT_CALLBACK
	ACETYPE_SYSTEM_ALARM_CALLBACK
	ACETYPE_SYSTEM_AUDIT_CALLBACK_OBJECT
	ACETYPE_SYSTEM_ALARM_CALLBACK_OBJECT
	ACETYPE_SYSTEM_MANDATORY_LABEL
	ACETYPE_SYSTEM_RESOURCE_ATTRIBUTE
	ACETYPE_SYSTEM_SCOPED_POLICY_ID
)

Not all conditional ACE types are supported in the SDDL. The conditional ACE types ACCESS_ALLOWED_CALLBACK_ACE and ACCESS_DENIED_CALLBACK_ACE are not supported in Windows Vista and earlier client releases or Windows Server 2008 and earlier server releases. The conditional ACE types ACCESS_ALLOWED_CALLBACK_OBJECT_ACE and SYSTEM_AUDIT_CALLBACK_ACE are not supported in Windows 7 or Windows Server 2008 R2.

func (*AceType) MustString

func (aceType *AceType) MustString() (string, error)

MustString returns the ACE type as a string. If the ACE type is not known or it doesn't have a string representation, it returns an error.

func (*AceType) String

func (aceType *AceType) String() string

String returns the ACE type as a string. If the ACE type is not known, it returns the type as a hex string.

Some of the ACE types don't have a string representation that I can find.

https://learn.microsoft.com/en-us/windows/win32/secauthz/ace-strings

type GUID

type GUID struct {
	Data1 uint32
	Data2 uint16
	Data3 uint16
	Data4 [8]byte
}

GUID represents a Windows GUID.

Redefining this here to avoid importing golang.org/x/sys/windows.

func GuidFromString

func GuidFromString(gstring string) (*GUID, error)

GuidFromString returns a GUID from a string.

Format: {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} or xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Returns an error if the string is not a valid GUID.

func (*GUID) IsNull

func (g *GUID) IsNull() bool

IsNull returns true if the GUID is null.

func (*GUID) String

func (guid *GUID) String() string

String returns the GUID as a string.

Format: {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}

type ObjectFlag

type ObjectFlag byte
const (
	ACE_OBJECT_INVALID                ObjectFlag = 0x00
	ACE_OBJECT_TYPE_PRESENT           ObjectFlag = 0x01
	ACE_INHERITED_OBJECT_TYPE_PRESENT ObjectFlag = 0x02
)

type SDDL

type SDDL struct {
	Version      byte
	ControlFlags uint16
	// Owner and Group are SIDs as strings.
	Owner string
	Group string
	SACL  ACL
	DACL  ACL
}

SDDL represents a Windows SDDL string. This is a subset of the SDDL format, only containing the fields we care about.

See https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format for more information.

func SDDLFromBase64Encoded

func SDDLFromBase64Encoded(data []byte) (*SDDL, error)

SDDLFromBase64Encoded decodes a base64 encoded SDDL string. This is a shortcut for base64.StdEncoding.DecodeString and SDDLFromBinary.

Returns an error if the base64 decoding fails or if the SDDL is invalid.

func SDDLFromBinary

func SDDLFromBinary(data []byte) (*SDDL, error)

SDDLFromBinary decodes a binary SDDL string. This expects the generic binary format Windows uses.

Returns an error if the SDDL is invalid. The SDDL will be deemed invalid for any of the following reasons:

  • The SDDL is too short
  • The SDDL does not start with 0x01 0x00
  • The owner or group SID is invalid (if present)
  • The SACL or DACL is invalid (if present)
  • An unknown or unhandled ACE type is encountered

func SDDLFromString

func SDDLFromString(sddl, domainIdentity, machineIdentity string) (*SDDL, error)

SDDLFromString decodes the standard SDDL string format.

Domain and machine identity are used to resolve SID aliases to SIDs. If not provided, then SIDs will look like S-1-5--500.

Machine identity is likely unnecessary for any active directory SDDLs, whereas domain identity is likely unnecessary for any local machine results.

func (*SDDL) MustString

func (sddl *SDDL) MustString() (string, error)

MustString returns the SDDL as a string. Returns an error if the SDDL has unhandled elements.

func (*SDDL) String

func (sddl *SDDL) String() string

String returns the SDDL as a string. Shortcut for MustString, returning an empty string on error.

func (*SDDL) ToBase64Encoded

func (sddl *SDDL) ToBase64Encoded() ([]byte, error)

ToBase64Encoded encodes the SDDL as a base64 byte array. This is a shortcut for base64.StdEncoding.Encode and SDDLToBinary.

Returns an error if the SDDL is invalid.

func (*SDDL) ToBinary

func (sddl *SDDL) ToBinary() ([]byte, error)

ToBinary encodes the SDDL as a binary string. This is the generic binary format Windows uses.

Returns an error if the SDDL is invalid.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL