MonaxGT/gosddl

View on GitHub
gosddl.go

Summary

Maintainability
A
0 mins
Test Coverage
package gosddl

import (
    "bufio"
    "fmt"
    "log"
    "os"
    "strings"

    "encoding/json"
    "github.com/pkg/errors"
)

// ACLProcessor main struct with methods
type ACLProcessor struct {
    Rights permissions
    File   string
}

type entryACL struct {
    AccountSid        string   `json:"accountSID,omitempty"`
    AceType           string   `json:"aceType,omitempty"`
    AceFlags          []string `json:"aceFlags,omitempty"`
    Rights            []string `json:"rights,omitempty"`
    ObjectGUID        string   `json:"objectGUID,omitempty"`
    InheritObjectGUID string   `json:"inheritObjectGUID,omitempty"`
}

type permissions struct {
    Owner     string     `json:"owner,omitempty"`
    Primary   string     `json:"primary,omitempty"`
    Dacl      []entryACL `json:"dacl,omitempty"`
    DaclInher []string   `json:"daclInheritFlags,omitempty"`
    Sacl      []entryACL `json:"sacl,omitempty"`
    SaclInger []string   `json:"saclInheritFlags,omitempty"`
}

// checkSIDsFile check file of SIDs where data saved in SID,User
func checkSIDsFile(filePath string, sid string) string {
    file, err := os.Open(filePath)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        if strings.Split(scanner.Text(), ",")[0] == sid {
            return strings.Split(scanner.Text(), ",")[1]
        }
    }
    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }
    return sid
}

// sidReplace replace identification account: sid/wellkhownsid/usersid
func (app *ACLProcessor) sidReplace(str string) string {
    if len(str) > 2 {
        if x, ok := sddlWellKnownSidsRep[str]; ok {
            return x
        } else if app.File != "" {
            return checkSIDsFile(app.File, str)
        }
        return str
    }
    return app.replacer(sddlSidsRep, str)[0]
}

// replacer chunk string with 2 letters, add to array and then resolve
func (app *ACLProcessor) replacer(maps map[string]string, str string) []string {
    var temp, result []string
    if len(str) > 2 {
        for j := 0; j < len(str)-1; j = j + 2 {
            temp = append(temp, fmt.Sprintf("%s%s", string(str[j]), string(str[j+1])))
        }
    } else {
        temp = append(temp, str)
    }
    for _, v := range temp {
        if x, ok := maps[v]; ok {
            result = append(result, x)
        } else {
            result = append(result, v)
        }
    }
    return result
}

/* splitBodyACL Convert values from string to struct with replace strings
Base format Rights: (ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid)
*/
func (app *ACLProcessor) splitBodyACL(str string) entryACL {
    splitACL := strings.Split(str, ";")
    return entryACL{
        AceType:           app.replacer(sddlAceType, splitACL[0])[0],
        AceFlags:          app.replacer(sddlAceFlags, splitACL[1]),
        Rights:            app.replacer(sddlRights, splitACL[2]),
        ObjectGUID:        splitACL[3],
        InheritObjectGUID: splitACL[4],
        AccountSid:        app.sidReplace(splitACL[5]),
    }
}

func (app *ACLProcessor) splitBody(body string) []entryACL {
    var entryACLInternalArr []entryACL
    for _, y := range strings.Split(body, "(") {
        if y != "" {
            ace := strings.TrimSuffix(y, ")")
            entryACLInternalArr = append(entryACLInternalArr, app.splitBodyACL(ace))
        }
    }
    return entryACLInternalArr
}

func (app *ACLProcessor) parseBody(body string) ([]string, []entryACL) {
    var inheritFlagArr []string
    var entryACLInternalArr []entryACL
    if strings.Index(body, "(") != 0 {
        inheritFlag := body[0:strings.Index(body, "(")]
        ace := body[strings.Index(body, "("):]
        if len(inheritFlag) > 2 {
            for j := 0; j < len(inheritFlag)-1; j = j + 2 {
                inheritFlagArr = append(inheritFlagArr, app.replacer(sddlInheritanceFlags, fmt.Sprintf("%s%s", string(inheritFlag[j]), string(inheritFlag[j+1])))[0])
            }
        }
        entryACLInternalArr = app.splitBody(ace)
    } else {
        entryACLInternalArr = app.splitBody(body)
    }
    return inheritFlagArr, entryACLInternalArr
}

func (app *ACLProcessor) parseSDDL(sddrArr []string) {
    for _, y := range sddrArr {
        sddlSplit := strings.Split(y, ":")
        letter := sddlSplit[0]
        body := sddlSplit[1]
        switch letter {
        case "O":
            app.Rights.Owner = app.sidReplace(body)
        case "G":
            app.Rights.Primary = app.sidReplace(body)
        case "D":
            app.Rights.DaclInher, app.Rights.Dacl = app.parseBody(body)
        case "S":
            app.Rights.SaclInger, app.Rights.Sacl = app.parseBody(body)
        default:
            log.Fatal("Unresolved group")
        }
    }
}

// slice SDDL create slice objects from str to array of strings
func (app *ACLProcessor) sliceSDDL(indecs []int, str string) {
    var sddlArr []string
    for i := 0; i < len(indecs)-1; i++ {
        sl := str[indecs[i]:indecs[i+1]]
        sddlArr = append(sddlArr, sl)
    }
    app.parseSDDL(sddlArr)
}

// FindGroupIndex used for find index of group Owner, Primary, DACL, SACL
func (app *ACLProcessor) findGroupIndex(str string) error {
    groups := []string{"O:", "G:", "D:", "S:"}
    var result []int
    for _, i := range groups {
        if strings.Index(str, i) != -1 {
            result = append(result, strings.Index(str, i))
        }
    }
    if result == nil {
        return errors.New("Can't find any group")
    }
    result = append(result, len(str))
    app.sliceSDDL(result, str)
    return nil
}

// Processor main function in gosddl package
func (app *ACLProcessor) Processor(str string) error {
    err := app.findGroupIndex(str)
    if err != nil {
        return err
    }
    body, err := json.Marshal(app.Rights)
    if err != nil {
        log.Fatal(err)
        return err
    }
    fmt.Println(string(body))
    return nil
}