Skip to content

Commit

Permalink
Merge pull request #6 from MonaxGT/develop
Browse files Browse the repository at this point in the history
Add File with SIDs support. Refactored code
  • Loading branch information
MonaxGT authored Dec 24, 2018
2 parents a3bea79 + a1e5cab commit 06cfc6c
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 81 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go:
- master

install:
- go get -d -v ./...
- go get -t -v ./...

script:
- go build ./...
Expand Down
6 changes: 4 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ COPY --from=build-env /etc/passwd /etc/passwd

USER app

WORKDIR /app
VOLUME /app/data

ENTRYPOINT ["./gosddl"]
WORKDIR /app/data

ENTRYPOINT ["../gosddl"]
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,32 @@ GoSDDL (Security Descriptor Definition Language)
[![Maintainability](https://api.codeclimate.com/v1/badges/69e05e119408b9f830d4/maintainability)](https://codeclimate.com/github/MonaxGT/gosddl/maintainability)

Converter from SDDL-string to user-friendly JSON. SDDL consist of four part: Owner, Primary Group, DACL, SACL.

This converter works with two mode:

1) Direct
2) API

You can attach file with SIDs-Username for decoding with replacement SID to Username.
You should attach file with option -f. File should store with format:

```sh
S-1-XXXX,Username1
S-1-YYYY,Username2
```

Installing
------------------------------------------------

To start using gosddl, install Go and run go get:

```go
```sh
$ go get -u github.com/MonaxGT/gosddl
```

Direct usage example
------------------------------------------------

```go
```sh
go run gosddl.go "D:(A;;GA;;;S-1-5-21-111111111-1111111111-1111111111-11111)(A;;GA;;;SY)(A;;GXGR;;;S-1-5-5-1-1111111111)(A;;GA;;;BA)"

{"owner":"","primary":"","dacl":[{"accountsid":"S-1-5-21-111111111-1111111111-1111111111-11111","aceType":"ACCESS ALLOWED","aceflags":[""],"rights":["GENERIC_ALL"],"objectguid":"","InheritObjectGuid":""},{"accountsid":"Local system","aceType":"ACCESS ALLOWED","aceflags":[""],"rights":["GENERIC_ALL"],"objectguid":"","InheritObjectGuid":""},{"accountsid":"S-1-5-5-1-1111111111","aceType":"ACCESS ALLOWED","aceflags":[""],"rights":["GENERIC_EXECUTE","GENERIC_READ"],"objectguid":"","InheritObjectGuid":""},{"accountsid":"Built-in administrators","aceType":"ACCESS ALLOWED","aceflags":[""],"rights":["GENERIC_ALL"],"objectguid":"","InheritObjectGuid":""}],"daclInheritFlags":null,"sacl":null,"saclInheritFlags":null}
Expand All @@ -31,7 +39,7 @@ go run gosddl.go "D:(A;;GA;;;S-1-5-21-111111111-1111111111-1111111111-11111)(A;;
API usage example
------------------------------------------------

```go
```sh
go run gosddl.go -api

curl 'http://127.0.0.1:8000/sddl/D:(A;;GA;;;S-1-5-21-111111111-1111111111-1111111111-11111)(A;;GA;;;SY)(A;;GXGR;;;S-1-5-5-1-1111111111)(A;;GA;;;BA)'
Expand All @@ -44,7 +52,7 @@ Additionally you can use Docker
```docker
docker build -t gosddl .
docker run -d -p 8000:8000 gosddl -api
docker run --rm -it gosddl "O:BAG:SYD:(D;;GA;;;AN)(D;;GA;;;BG)(A;;GA;;;SY)(A;;GA;;;BA)S:ARAI(AU;SAFA;DCLCRPCRSDWDWO;;;WD)"
docker run --rm -it -v $PWD/store:/app/data gosddl "O:BAG:SYD:(D;;GA;;;AN)(D;;GA;;;BG)(A;;GA;;;SY)(A;;GA;;;BA)S:ARAI(AU;SAFA;DCLCRPCRSDWDWO;;;WD)"
```

Links:
Expand Down
153 changes: 103 additions & 50 deletions gosddl.go
Original file line number Diff line number Diff line change
@@ -1,44 +1,76 @@
package gosddl

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

"encoding/json"
)

type entryACLInternal struct {
AccountSid string `json:"accountSID"`
AceType string `json:"aceType"`
AceFlags []string `json:"aceFlags"`
Rights []string `json:"rights"`
ObjectGUID string `json:"objectGUID"`
InheritObjectGUID string `json:"inheritObjectGUID"`
// ACLProcessor main struct with methods
type ACLProcessor struct {
Rights Permissons
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 Permissons struct {
Owner string `json:"owner"`
Primary string `json:"primary"`
Dacl []entryACLInternal `json:"dacl"`
DaclInher []string `json:"daclInheritFlags"`
Sacl []entryACLInternal `json:"sacl"`
SaclInger []string `json:"saclInheritFlags"`
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"`
}

// replace identification account: sid/wellkhownsid/usersid
func sidReplace(str string) string {
// 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 {
return str
} else if app.File != "" {
return checkSIDsFile(app.File, str)
}
return replacer(sddlWellKnownSidsRep, str)[0]
return str
}
return replacer(sddlSidsRep, str)[0]
return app.replacer(sddlSidsRep, str)[0]
}

// chunk string with 2 letters, add to array and then resolve
func replacer(maps map[string]string, str string) []string {
// 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 {
Expand All @@ -57,81 +89,83 @@ func replacer(maps map[string]string, str string) []string {
return result
}

// Base format ACL: (ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid)
// Convert values from string to struct with replace strings
func splitBodyACL(str string) entryACLInternal {
temp := strings.Split(str, ";")
return entryACLInternal{
AceType: replacer(sddlAceType, temp[0])[0],
AceFlags: replacer(sddlAceFlags, temp[1]),
Rights: replacer(sddlRights, temp[2]),
ObjectGUID: temp[3],
InheritObjectGUID: temp[4],
AccountSid: sidReplace(temp[5]),
/* 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 splitBody(body string) []entryACLInternal {
var entryACLInternalArr []entryACLInternal
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, splitBodyACL(ace))
entryACLInternalArr = append(entryACLInternalArr, app.splitBodyACL(ace))
}
}
return entryACLInternalArr
}

func (p *Permissons) parseBody(body string) ([]string, []entryACLInternal) {
func (app *ACLProcessor) parseBody(body string) ([]string, []entryACL) {
var inheritFlagArr []string
var entryACLInternalArr []entryACLInternal
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, replacer(sddlInheritanceFlags, fmt.Sprintf("%s%s", string(inheritFlag[j]), string(inheritFlag[j+1])))[0])
inheritFlagArr = append(inheritFlagArr, app.replacer(sddlInheritanceFlags, fmt.Sprintf("%s%s", string(inheritFlag[j]), string(inheritFlag[j+1])))[0])
}
}
entryACLInternalArr = splitBody(ace)
entryACLInternalArr = app.splitBody(ace)
} else {
entryACLInternalArr = splitBody(body)
entryACLInternalArr = app.splitBody(body)
}
return inheritFlagArr, entryACLInternalArr
}

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

}

// create slice objects from str to array of strings
func (p *Permissons) sliceSDDL(indecs []int, str string) {
// 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)
}
p.parseSDDL(sddlArr)
app.parseSDDL(sddlArr)
}

func (p *Permissons) FindGroupIndex(str string) {
// FindGroupIndex used for find index of group Owner, Primary, DACL, SACL
func (app *ACLProcessor) findGroupIndex(str string) {
groups := []string{"O:", "G:", "D:", "S:"}
var result []int
for _, i := range groups {
Expand All @@ -140,5 +174,24 @@ func (p *Permissons) FindGroupIndex(str string) {
}
}
result = append(result, len(str))
p.sliceSDDL(result, str)
app.sliceSDDL(result, str)
}

// Processor main function in gosddl package
func Processor(api bool, port string, file string) {
var app ACLProcessor
app.File = file
if api {
fmt.Println("API Interface started on port", port)
app.httpHandler(port)
} else if flag.Args() != nil {
app.findGroupIndex(flag.Args()[0])
body, err := json.Marshal(app.Rights)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(body))
} else {
log.Fatal("You should give me SDDL string or use API mode")
}
}
12 changes: 5 additions & 7 deletions http.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,23 @@ import (
"github.com/gorilla/mux"
)

var permisson Permissons

func getInfo(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode("Hello")
}

func decode(w http.ResponseWriter, r *http.Request) {
func (app *ACLProcessor) decode(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
if params["sddl"] != "" {
sddl := params["sddl"]
permisson.FindGroupIndex(sddl)
json.NewEncoder(w).Encode(permisson)
app.findGroupIndex(sddl)
json.NewEncoder(w).Encode(app.Rights)
return
}
}

func HttpHandler(port string) {
func (app *ACLProcessor) httpHandler(port string) {
router := mux.NewRouter()
router.HandleFunc("/sddl", getInfo).Methods("GET")
router.HandleFunc("/sddl/{sddl}", decode).Methods("GET")
router.HandleFunc("/sddl/{sddl}", app.decode).Methods("GET")
log.Fatal(http.ListenAndServe(port, router))
}
19 changes: 3 additions & 16 deletions service/gosddl/main.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,15 @@
package main

import (
"encoding/json"
"flag"
"fmt"
"log"

"github.com/MonaxGT/gosddl"
)

func main() {
var permisson gosddl.Permissons
apiPtr := flag.Bool("api", false, "a bool")
apiPtr := flag.Bool("api", false, "Use API mode")
apiPortPtr := flag.String("port", ":8000", "Default port 8000")
fileSIDs := flag.String("f", "", "File with users's SIDs")
flag.Parse()
if *apiPtr {
fmt.Println("API Interface started on port", *apiPortPtr)
gosddl.HttpHandler(*apiPortPtr)
} else if flag.Args() != nil {
permisson.FindGroupIndex(flag.Args()[0])
b, err := json.Marshal(permisson)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
}
gosddl.Processor(*apiPtr, *apiPortPtr, *fileSIDs)
}

0 comments on commit 06cfc6c

Please sign in to comment.