mirror of
https://github.com/glauth/glauth.git
synced 2026-10-25 05:30:47 +00:00
Introducing goconvey testing and refactoring of config and ... (#204)
* Introducing goconvey testing and refactoring of config and plugin backends. * gofmt, oops * Refactored re-insertion of requested attributes
This commit is contained in:
committed by
GitHub
parent
674a6bdbf4
commit
4cf38893ac
@@ -254,7 +254,35 @@ make all
|
||||
- errors really are errors that cannot be handled or returned
|
||||
- returning a proper LDAP error code is handling an error
|
||||
|
||||
# Compatiblity
|
||||
# Testing
|
||||
|
||||
Of course, a core set of tests is being run by Travis CI. However, when developing new features/refactoring, a more comprehensive regression testing suite is needed.
|
||||
|
||||
You can run `go test` to execute the tests found in `glauth_test.go` -- better, if it is installed, you can run [goconvey](https://github.com/smartystreets/goconvey)
|
||||
|
||||
Since some tests cover TOTP, you will first need to install `oathtool` in your environment.
|
||||
|
||||
In order to test GLAuth against an LDAP backend, you will need docker. Run this command:
|
||||
```
|
||||
docker run \
|
||||
--rm \
|
||||
-d \
|
||||
-p 389:389 \
|
||||
--name openldap-service \
|
||||
--hostname ldap-service \
|
||||
--env LDAP_ORGANISATION="GLauth" \
|
||||
--env LDAP_DOMAIN="glauth.com" \
|
||||
--env LDAP_ADMIN_PASSWORD="password" \
|
||||
--env LDAP_CONFIG_PASSWORD="password" \
|
||||
--env LDAP_BASE_DN="dc=glauth,dc=com" \
|
||||
-v $PWD/misc/openldap/config:/etc/ldap/slapd.d \
|
||||
-v $PWD/misc/openldap/db:/var/lib/ldap \
|
||||
osixia/openldap:latest
|
||||
```
|
||||
|
||||
Refer to [this page](https://github.com/glauth/glauth/wiki/Quick-openldap-setup-to-test-LDAP-backend) for a somewhat more in-depth overview of testing with OpenLDAP.
|
||||
|
||||
# Compatibility
|
||||
|
||||
While our stated goal for GLAuth is to provide the simplest possible authentication server, we keep finding an increasing number of client appliances that are asking fairly "existential" questions of the server. We have been working on providing answers these clients will find satisfactory.
|
||||
|
||||
|
||||
+4
-4
@@ -228,10 +228,10 @@ type bintree struct {
|
||||
}
|
||||
|
||||
var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"assets": &bintree{nil, map[string]*bintree{
|
||||
"glauth.css": &bintree{assetsGlauthCss, map[string]*bintree{}},
|
||||
"glauth.js": &bintree{assetsGlauthJs, map[string]*bintree{}},
|
||||
"index.html": &bintree{assetsIndexHtml, map[string]*bintree{}},
|
||||
"assets": {nil, map[string]*bintree{
|
||||
"glauth.css": {assetsGlauthCss, map[string]*bintree{}},
|
||||
"glauth.js": {assetsGlauthJs, map[string]*bintree{}},
|
||||
"index.html": {assetsIndexHtml, map[string]*bintree{}},
|
||||
}},
|
||||
}}
|
||||
|
||||
|
||||
+184
-19
@@ -1,32 +1,197 @@
|
||||
package main
|
||||
|
||||
// Just the beginning of testing - more to be added
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestGetVersionString(t *testing.T) {
|
||||
type testEnv struct {
|
||||
checkanonymousrootDSE bool
|
||||
checkTOTP bool
|
||||
svcdn string
|
||||
otpdn string
|
||||
expectedinfo string
|
||||
expectedaccount string
|
||||
expectedfirstaccount string
|
||||
expectedgroup string
|
||||
}
|
||||
|
||||
// Setup config and check output
|
||||
LastGitTag = "7"
|
||||
BuildTime = "20180616_042045Z"
|
||||
GitCommit = "a9837f3112fc049fd1e9faca6f56d8be1bec91bd"
|
||||
GitClean = "1"
|
||||
GitBranch = "dev"
|
||||
GitTagIsCommit = "0"
|
||||
func TestIntegerStuff(t *testing.T) {
|
||||
|
||||
versionOutput := getVersionString()
|
||||
if versionOutput != "7" {
|
||||
t.Errorf("Finish writing this test, output was: %s", versionOutput)
|
||||
Convey("Testing sample-simple local file-based LDAP server", t, func() {
|
||||
svc := startSvc(SD, "bin/glauth", "-c", "sample-simple.cfg")
|
||||
batteryOfTests(
|
||||
t,
|
||||
svc, testEnv{
|
||||
checkanonymousrootDSE: true,
|
||||
checkTOTP: true,
|
||||
expectedinfo: "supportedLDAPVersion: 3",
|
||||
svcdn: "cn=serviceuser,ou=svcaccts,dc=glauth,dc=com",
|
||||
otpdn: "cn=otpuser,ou=superheros,dc=glauth,dc=com",
|
||||
expectedaccount: "dn: cn=hackers,ou=superheros,dc=glauth,dc=com",
|
||||
expectedfirstaccount: "dn: cn=hackers,ou=superheros,dc=glauth,dc=com",
|
||||
expectedgroup: "dn: cn=superheros,ou=groups,dc=glauth,dc=com",
|
||||
})
|
||||
stopSvc(svc)
|
||||
})
|
||||
|
||||
matchingLibrary := doRunGetFirst(RD, "ls", "bin/sqlite.so")
|
||||
if matchingLibrary == "bin/sqlite.so" {
|
||||
Convey("Testing sample-database LDAP server", t, func() {
|
||||
svc := startSvc(SD, "bin/glauth", "-c", "pkg/plugins/sample-database.cfg")
|
||||
batteryOfTests(
|
||||
t,
|
||||
svc, testEnv{
|
||||
checkanonymousrootDSE: true,
|
||||
checkTOTP: false,
|
||||
expectedinfo: "supportedLDAPVersion: 3",
|
||||
svcdn: "cn=serviceuser,ou=svcaccts,dc=glauth,dc=com",
|
||||
otpdn: "cn=otpuser,ou=superheros,dc=glauth,dc=com",
|
||||
expectedaccount: "dn: cn=hackers,ou=superheros,dc=glauth,dc=com",
|
||||
expectedfirstaccount: "dn: cn=hackers,ou=superheros,dc=glauth,dc=com",
|
||||
expectedgroup: "dn: cn=superheros,ou=groups,dc=glauth,dc=com",
|
||||
})
|
||||
stopSvc(svc)
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: write these cases
|
||||
matchingContainers := doRunGetFirst(RD, "sh", "-c", "docker ps | grep openldap-service | wc -l")
|
||||
if matchingContainers == "1" {
|
||||
Convey("Testing sample-simple local LDAP server", t, func() {
|
||||
svc := startSvc(SD, "bin/glauth", "-c", "sample-ldap-injection.cfg")
|
||||
batteryOfTests(
|
||||
t,
|
||||
svc, testEnv{
|
||||
checkanonymousrootDSE: false,
|
||||
checkTOTP: true,
|
||||
expectedinfo: "objectClass: top",
|
||||
svcdn: "cn=serviceuser,cn=svcaccts,ou=users,dc=glauth,dc=com",
|
||||
otpdn: "cn=otpuser,cn=superheros,ou=users,dc=glauth,dc=com",
|
||||
expectedaccount: "dn: cn=hackers,cn=superheros,ou=users,dc=glauth,dc=com",
|
||||
expectedfirstaccount: "dn: cn=johndoe,cn=superheros,ou=users,dc=glauth,dc=com",
|
||||
expectedgroup: "dn: cn=superheros,ou=users,dc=glauth,dc=com",
|
||||
})
|
||||
stopSvc(svc)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Cases to test:
|
||||
// 1) if GitTagIsCommit=1 - check for release-based strings (this build is release)
|
||||
// 2) if GitClean=1 - check for "Commit: " as well as value of commit str
|
||||
// 3) if GitClean=0 - Ensure "Commit: " is NOT there, as well ensure value of commit str is not there
|
||||
// 4) do additional checks for release behavior, as well as branch name
|
||||
func batteryOfTests(t *testing.T, svc *exec.Cmd, env testEnv) {
|
||||
Convey("When searching for the 'hackers' user", func() {
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
|
||||
Convey("We should find them in the 'superheros' group", func() {
|
||||
So(out, ShouldEqual, env.expectedaccount)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When querying the root SDE", func() {
|
||||
out := doRunGetSecond(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-s", "base", "(objectclass=*)")
|
||||
Convey("We should get some meta information", func() {
|
||||
So(out, ShouldEqual, env.expectedinfo)
|
||||
})
|
||||
})
|
||||
|
||||
if env.checkanonymousrootDSE {
|
||||
Convey("When querying the root SDE anonymously without authorizing in config file", func() {
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-x", "-s", "base", "(objectclass=*)")
|
||||
Convey("We should get error 50", func() {
|
||||
So(out, ShouldEqual, "exit status 50")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Convey("When enumerating posix groups", func() {
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(objectclass=posixgroup)")
|
||||
Convey("We should get a list starting with the 'superheros' group", func() {
|
||||
So(out, ShouldEqual, env.expectedgroup)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When searching for members of the 'superheros' group", func() {
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(memberOf=cn=superheros,ou=groups,dc=glauth,dc=com)")
|
||||
Convey("We should get a list starting with the 'hackers' user", func() {
|
||||
So(out, ShouldEqual, env.expectedfirstaccount)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When performing a complex search for members of 'superheros' group", func() {
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(&(objectClass=*)(memberOf=cn=superheros,ou=groups,dc=glauth,dc=com))")
|
||||
Convey("We should get a list starting with the 'hackers' user", func() {
|
||||
So(out, ShouldEqual, env.expectedfirstaccount)
|
||||
})
|
||||
})
|
||||
|
||||
if env.checkTOTP {
|
||||
Convey("When searching for the 'hacker' user using a TOTP-enabled account", func() {
|
||||
otpvalue := doRunGetFirst(RD, "oathtool", "--totp", "-b", "-d", "6", "3hnvnk4ycv44glzigd6s25j4dougs3rk")
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret"+otpvalue, "-x", "-bdc=glauth,dc=com", "cn=hackers")
|
||||
Convey("We should find them in in the 'superheros' group", func() {
|
||||
So(out, ShouldEqual, env.expectedaccount)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When searching for the 'hacker' user using a TOTP-enabled account and no value", func() {
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
|
||||
Convey("We should get 'Invalid credentials(49)'", func() {
|
||||
So(out, ShouldEqual, "exit status 49")
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When searching for the 'hacker' user using a TOTP-enabled account and the wrong value", func() {
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret123456", "-x", "-bdc=glauth,dc=com", "cn=hackers")
|
||||
Convey("We should get 'Invalid credentials(49)'", func() {
|
||||
So(out, ShouldEqual, "exit status 49")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -----=============================================================================----
|
||||
|
||||
const SD = 3 // Start Delay
|
||||
const RD = 2 // Response Delay
|
||||
|
||||
func startSvc(delay time.Duration, name string, arg ...string) *exec.Cmd {
|
||||
cmd := exec.Command(name, arg...)
|
||||
cmd.Start()
|
||||
if delay != 0 {
|
||||
time.Sleep(time.Second * delay)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func stopSvc(svc *exec.Cmd) {
|
||||
svc.Process.Kill()
|
||||
}
|
||||
|
||||
func doRunGetFirst(delay time.Duration, name string, arg ...string) string {
|
||||
out := strings.SplitN(doRun(delay, name, arg...), "\n", 2)
|
||||
if out == nil || len(out) < 1 {
|
||||
return "*fail*"
|
||||
}
|
||||
return out[0]
|
||||
}
|
||||
|
||||
func doRunGetSecond(delay time.Duration, name string, arg ...string) string {
|
||||
out := strings.SplitN(doRun(delay, name, arg...), "\n", 3)
|
||||
if out == nil || len(out) < 2 {
|
||||
return "*fail*"
|
||||
}
|
||||
return out[1]
|
||||
}
|
||||
|
||||
func doRun(delay time.Duration, name string, arg ...string) string {
|
||||
out, err := exec.Command(name, arg...).Output()
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
if delay != 0 {
|
||||
time.Sleep(time.Second * delay)
|
||||
}
|
||||
return strings.TrimSpace(string(out))
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ require (
|
||||
github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||
github.com/pquerna/otp v1.3.0
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/yaegashi/msgraph.go v0.1.1-0.20200221123608-2d438cf2a7cc
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
|
||||
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b
|
||||
|
||||
@@ -19,12 +19,16 @@ github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gG
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/hydronica/toml v0.4.2 h1:BY+iAvyl2u1BlfgkJQzqc1UXDGLWfpMmOWuqJrwAVDU=
|
||||
github.com/hydronica/toml v0.4.2/go.mod h1:c7QhbYq3Wp9SlOWuG7MAieKUyXP2P/hXhy/YqWfbS/4=
|
||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o=
|
||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
|
||||
github.com/jteeuwen/go-bindata v3.0.7+incompatible h1:91Uy4d9SYVr1kyTJ15wJsog+esAZZl7JmEfTkwmhJts=
|
||||
github.com/jteeuwen/go-bindata v3.0.7+incompatible/go.mod h1:JVvhzYOiGBnFSYRyV00iY8q7/0PThjIYav1p9h5dmKs=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
@@ -46,19 +50,26 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs=
|
||||
github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/yaegashi/msgraph.go v0.1.1-0.20200221123608-2d438cf2a7cc h1:ejaC8rvIvCWmsaFrvmGOxhBuMxxhBB1xRshuM98XQ7M=
|
||||
github.com/yaegashi/msgraph.go v0.1.1-0.20200221123608-2d438cf2a7cc/go.mod h1:tso14hwzqX4VbnWTNsxiL0DvMb2OwbGISFA7jDibdWc=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9 h1:L2auWcuQIvxz9xSEqzESnV/QN/gNRXNApHi3fYwl2w0=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -68,6 +79,8 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b h1:tdSyAzD5FHJmZAZ13d5WexAo7YJkiyGphhzFfInMnDw=
|
||||
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b/go.mod h1:cE0dCGx2UfBTjLFlzEx4EXJUmoX6BXBoX9GjKOvqha4=
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 34dedff0
|
||||
dn: cn=config
|
||||
objectClass: olcGlobal
|
||||
cn: config
|
||||
olcArgsFile: /var/run/slapd/slapd.args
|
||||
olcLogLevel: none
|
||||
olcPidFile: /var/run/slapd/slapd.pid
|
||||
olcToolThreads: 1
|
||||
structuralObjectClass: olcGlobal
|
||||
entryUUID: 5c21e0e8-7ddc-103b-9ebb-c740e015b81b
|
||||
creatorsName: cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
olcTLSCipherSuite: SECURE256:+SECURE128:-VERS-TLS-ALL:+VERS-TLS1.2:-RSA:-DHE
|
||||
-DSS:-CAMELLIA-128-CBC:-CAMELLIA-256-CBC
|
||||
olcTLSCACertificateFile: /container/service/slapd/assets/certs/ca.crt
|
||||
olcTLSCertificateFile: /container/service/slapd/assets/certs/ldap.crt
|
||||
olcTLSCertificateKeyFile: /container/service/slapd/assets/certs/ldap.key
|
||||
olcTLSDHParamFile: /container/service/slapd/assets/certs/dhparam.pem
|
||||
olcTLSVerifyClient: demand
|
||||
entryCSN: 20210811010255.807081Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210811010255Z
|
||||
@@ -0,0 +1,16 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 2aabc521
|
||||
dn: cn=module{0}
|
||||
objectClass: olcModuleList
|
||||
cn: module{0}
|
||||
olcModulePath: /usr/lib/ldap
|
||||
olcModuleLoad: {0}back_mdb
|
||||
olcModuleLoad: {1}memberof
|
||||
olcModuleLoad: {2}refint
|
||||
structuralObjectClass: olcModuleList
|
||||
entryUUID: 5c2b1fb4-7ddc-103b-9ec3-c740e015b81b
|
||||
creatorsName: cn=admin,cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.856380Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,12 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 bc37faae
|
||||
dn: cn=schema
|
||||
objectClass: olcSchemaConfig
|
||||
cn: schema
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c2570a0-7ddc-103b-9ebe-c740e015b81b
|
||||
creatorsName: cn=admin,cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.316331Z#000000#000#000000
|
||||
modifiersName: cn=admin,cn=config
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,249 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 57d21f8c
|
||||
dn: cn={0}core
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {0}core
|
||||
olcAttributeTypes: {0}( 2.5.4.2 NAME 'knowledgeInformation' DESC 'RFC2256: k
|
||||
nowledge information' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.
|
||||
121.1.15{32768} )
|
||||
olcAttributeTypes: {1}( 2.5.4.4 NAME ( 'sn' 'surname' ) DESC 'RFC2256: last
|
||||
(family) name(s) for which the entity is known by' SUP name )
|
||||
olcAttributeTypes: {2}( 2.5.4.5 NAME 'serialNumber' DESC 'RFC2256: serial nu
|
||||
mber of the entity' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMat
|
||||
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{64} )
|
||||
olcAttributeTypes: {3}( 2.5.4.6 NAME ( 'c' 'countryName' ) DESC 'RFC4519: tw
|
||||
o-letter ISO-3166 country code' SUP name SYNTAX 1.3.6.1.4.1.1466.115.121.1.
|
||||
11 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 2.5.4.7 NAME ( 'l' 'localityName' ) DESC 'RFC2256: l
|
||||
ocality which this object resides in' SUP name )
|
||||
olcAttributeTypes: {5}( 2.5.4.8 NAME ( 'st' 'stateOrProvinceName' ) DESC 'RF
|
||||
C2256: state or province which this object resides in' SUP name )
|
||||
olcAttributeTypes: {6}( 2.5.4.9 NAME ( 'street' 'streetAddress' ) DESC 'RFC2
|
||||
256: street address of this object' EQUALITY caseIgnoreMatch SUBSTR caseIgn
|
||||
oreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
|
||||
olcAttributeTypes: {7}( 2.5.4.10 NAME ( 'o' 'organizationName' ) DESC 'RFC22
|
||||
56: organization this object belongs to' SUP name )
|
||||
olcAttributeTypes: {8}( 2.5.4.11 NAME ( 'ou' 'organizationalUnitName' ) DESC
|
||||
'RFC2256: organizational unit this object belongs to' SUP name )
|
||||
olcAttributeTypes: {9}( 2.5.4.12 NAME 'title' DESC 'RFC2256: title associate
|
||||
d with the entity' SUP name )
|
||||
olcAttributeTypes: {10}( 2.5.4.14 NAME 'searchGuide' DESC 'RFC2256: search g
|
||||
uide, deprecated by enhancedSearchGuide' SYNTAX 1.3.6.1.4.1.1466.115.121.1.
|
||||
25 )
|
||||
olcAttributeTypes: {11}( 2.5.4.15 NAME 'businessCategory' DESC 'RFC2256: bus
|
||||
iness category' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch S
|
||||
YNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
|
||||
olcAttributeTypes: {12}( 2.5.4.16 NAME 'postalAddress' DESC 'RFC2256: postal
|
||||
address' EQUALITY caseIgnoreListMatch SUBSTR caseIgnoreListSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
|
||||
olcAttributeTypes: {13}( 2.5.4.17 NAME 'postalCode' DESC 'RFC2256: postal co
|
||||
de' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.
|
||||
1.4.1.1466.115.121.1.15{40} )
|
||||
olcAttributeTypes: {14}( 2.5.4.18 NAME 'postOfficeBox' DESC 'RFC2256: Post O
|
||||
ffice Box' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX
|
||||
1.3.6.1.4.1.1466.115.121.1.15{40} )
|
||||
olcAttributeTypes: {15}( 2.5.4.19 NAME 'physicalDeliveryOfficeName' DESC 'RF
|
||||
C2256: Physical Delivery Office Name' EQUALITY caseIgnoreMatch SUBSTR caseI
|
||||
gnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
|
||||
olcAttributeTypes: {16}( 2.5.4.20 NAME 'telephoneNumber' DESC 'RFC2256: Tele
|
||||
phone Number' EQUALITY telephoneNumberMatch SUBSTR telephoneNumberSubstring
|
||||
sMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.50{32} )
|
||||
olcAttributeTypes: {17}( 2.5.4.21 NAME 'telexNumber' DESC 'RFC2256: Telex Nu
|
||||
mber' SYNTAX 1.3.6.1.4.1.1466.115.121.1.52 )
|
||||
olcAttributeTypes: {18}( 2.5.4.22 NAME 'teletexTerminalIdentifier' DESC 'RFC
|
||||
2256: Teletex Terminal Identifier' SYNTAX 1.3.6.1.4.1.1466.115.121.1.51 )
|
||||
olcAttributeTypes: {19}( 2.5.4.23 NAME ( 'facsimileTelephoneNumber' 'fax' )
|
||||
DESC 'RFC2256: Facsimile (Fax) Telephone Number' SYNTAX 1.3.6.1.4.1.1466.11
|
||||
5.121.1.22 )
|
||||
olcAttributeTypes: {20}( 2.5.4.24 NAME 'x121Address' DESC 'RFC2256: X.121 Ad
|
||||
dress' EQUALITY numericStringMatch SUBSTR numericStringSubstringsMatch SYNT
|
||||
AX 1.3.6.1.4.1.1466.115.121.1.36{15} )
|
||||
olcAttributeTypes: {21}( 2.5.4.25 NAME 'internationaliSDNNumber' DESC 'RFC22
|
||||
56: international ISDN number' EQUALITY numericStringMatch SUBSTR numericSt
|
||||
ringSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} )
|
||||
olcAttributeTypes: {22}( 2.5.4.26 NAME 'registeredAddress' DESC 'RFC2256: re
|
||||
gistered postal address' SUP postalAddress SYNTAX 1.3.6.1.4.1.1466.115.121.
|
||||
1.41 )
|
||||
olcAttributeTypes: {23}( 2.5.4.27 NAME 'destinationIndicator' DESC 'RFC2256:
|
||||
destination indicator' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstring
|
||||
sMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{128} )
|
||||
olcAttributeTypes: {24}( 2.5.4.28 NAME 'preferredDeliveryMethod' DESC 'RFC22
|
||||
56: preferred delivery method' SYNTAX 1.3.6.1.4.1.1466.115.121.1.14 SINGLE-
|
||||
VALUE )
|
||||
olcAttributeTypes: {25}( 2.5.4.29 NAME 'presentationAddress' DESC 'RFC2256:
|
||||
presentation address' EQUALITY presentationAddressMatch SYNTAX 1.3.6.1.4.1.
|
||||
1466.115.121.1.43 SINGLE-VALUE )
|
||||
olcAttributeTypes: {26}( 2.5.4.30 NAME 'supportedApplicationContext' DESC 'R
|
||||
FC2256: supported application context' EQUALITY objectIdentifierMatch SYNTA
|
||||
X 1.3.6.1.4.1.1466.115.121.1.38 )
|
||||
olcAttributeTypes: {27}( 2.5.4.31 NAME 'member' DESC 'RFC2256: member of a g
|
||||
roup' SUP distinguishedName )
|
||||
olcAttributeTypes: {28}( 2.5.4.32 NAME 'owner' DESC 'RFC2256: owner (of the
|
||||
object)' SUP distinguishedName )
|
||||
olcAttributeTypes: {29}( 2.5.4.33 NAME 'roleOccupant' DESC 'RFC2256: occupan
|
||||
t of role' SUP distinguishedName )
|
||||
olcAttributeTypes: {30}( 2.5.4.36 NAME 'userCertificate' DESC 'RFC2256: X.50
|
||||
9 user certificate, use ;binary' EQUALITY certificateExactMatch SYNTAX 1.3.
|
||||
6.1.4.1.1466.115.121.1.8 )
|
||||
olcAttributeTypes: {31}( 2.5.4.37 NAME 'cACertificate' DESC 'RFC2256: X.509
|
||||
CA certificate, use ;binary' EQUALITY certificateExactMatch SYNTAX 1.3.6.1.
|
||||
4.1.1466.115.121.1.8 )
|
||||
olcAttributeTypes: {32}( 2.5.4.38 NAME 'authorityRevocationList' DESC 'RFC22
|
||||
56: X.509 authority revocation list, use ;binary' SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.9 )
|
||||
olcAttributeTypes: {33}( 2.5.4.39 NAME 'certificateRevocationList' DESC 'RFC
|
||||
2256: X.509 certificate revocation list, use ;binary' SYNTAX 1.3.6.1.4.1.14
|
||||
66.115.121.1.9 )
|
||||
olcAttributeTypes: {34}( 2.5.4.40 NAME 'crossCertificatePair' DESC 'RFC2256:
|
||||
X.509 cross certificate pair, use ;binary' SYNTAX 1.3.6.1.4.1.1466.115.121
|
||||
.1.10 )
|
||||
olcAttributeTypes: {35}( 2.5.4.42 NAME ( 'givenName' 'gn' ) DESC 'RFC2256: f
|
||||
irst name(s) for which the entity is known by' SUP name )
|
||||
olcAttributeTypes: {36}( 2.5.4.43 NAME 'initials' DESC 'RFC2256: initials of
|
||||
some or all of names, but not the surname(s).' SUP name )
|
||||
olcAttributeTypes: {37}( 2.5.4.44 NAME 'generationQualifier' DESC 'RFC2256:
|
||||
name qualifier indicating a generation' SUP name )
|
||||
olcAttributeTypes: {38}( 2.5.4.45 NAME 'x500UniqueIdentifier' DESC 'RFC2256:
|
||||
X.500 unique identifier' EQUALITY bitStringMatch SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.6 )
|
||||
olcAttributeTypes: {39}( 2.5.4.46 NAME 'dnQualifier' DESC 'RFC2256: DN quali
|
||||
fier' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR case
|
||||
IgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
|
||||
olcAttributeTypes: {40}( 2.5.4.47 NAME 'enhancedSearchGuide' DESC 'RFC2256:
|
||||
enhanced search guide' SYNTAX 1.3.6.1.4.1.1466.115.121.1.21 )
|
||||
olcAttributeTypes: {41}( 2.5.4.48 NAME 'protocolInformation' DESC 'RFC2256:
|
||||
protocol information' EQUALITY protocolInformationMatch SYNTAX 1.3.6.1.4.1.
|
||||
1466.115.121.1.42 )
|
||||
olcAttributeTypes: {42}( 2.5.4.50 NAME 'uniqueMember' DESC 'RFC2256: unique
|
||||
member of a group' EQUALITY uniqueMemberMatch SYNTAX 1.3.6.1.4.1.1466.115.1
|
||||
21.1.34 )
|
||||
olcAttributeTypes: {43}( 2.5.4.51 NAME 'houseIdentifier' DESC 'RFC2256: hous
|
||||
e identifier' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYN
|
||||
TAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
|
||||
olcAttributeTypes: {44}( 2.5.4.52 NAME 'supportedAlgorithms' DESC 'RFC2256:
|
||||
supported algorithms' SYNTAX 1.3.6.1.4.1.1466.115.121.1.49 )
|
||||
olcAttributeTypes: {45}( 2.5.4.53 NAME 'deltaRevocationList' DESC 'RFC2256:
|
||||
delta revocation list; use ;binary' SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
|
||||
olcAttributeTypes: {46}( 2.5.4.54 NAME 'dmdName' DESC 'RFC2256: name of DMD'
|
||||
SUP name )
|
||||
olcAttributeTypes: {47}( 2.5.4.65 NAME 'pseudonym' DESC 'X.520(4th): pseudon
|
||||
ym for the object' SUP name )
|
||||
olcAttributeTypes: {48}( 0.9.2342.19200300.100.1.3 NAME ( 'mail' 'rfc822Mail
|
||||
box' ) DESC 'RFC1274: RFC822 Mailbox' EQUALITY caseIgnoreIA5Match SUBST
|
||||
R caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256}
|
||||
)
|
||||
olcAttributeTypes: {49}( 0.9.2342.19200300.100.1.25 NAME ( 'dc' 'domainCompo
|
||||
nent' ) DESC 'RFC1274/2247: domain component' EQUALITY caseIgnoreIA5Match S
|
||||
UBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SIN
|
||||
GLE-VALUE )
|
||||
olcAttributeTypes: {50}( 0.9.2342.19200300.100.1.37 NAME 'associatedDomain'
|
||||
DESC 'RFC1274: domain associated with object' EQUALITY caseIgnoreIA5Match S
|
||||
UBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {51}( 1.2.840.113549.1.9.1 NAME ( 'email' 'emailAddress'
|
||||
'pkcs9email' ) DESC 'RFC3280: legacy attribute for email addresses in DNs'
|
||||
EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.
|
||||
6.1.4.1.1466.115.121.1.26{128} )
|
||||
olcObjectClasses: {0}( 2.5.6.2 NAME 'country' DESC 'RFC2256: a country' SUP
|
||||
top STRUCTURAL MUST c MAY ( searchGuide $ description ) )
|
||||
olcObjectClasses: {1}( 2.5.6.3 NAME 'locality' DESC 'RFC2256: a locality' SU
|
||||
P top STRUCTURAL MAY ( street $ seeAlso $ searchGuide $ st $ l $ descriptio
|
||||
n ) )
|
||||
olcObjectClasses: {2}( 2.5.6.4 NAME 'organization' DESC 'RFC2256: an organiz
|
||||
ation' SUP top STRUCTURAL MUST o MAY ( userPassword $ searchGuide $ seeAlso
|
||||
$ businessCategory $ x121Address $ registeredAddress $ destinationIndicato
|
||||
r $ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $ tel
|
||||
ephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $ street
|
||||
$ postOfficeBox $ postalCode $ postalAddress $ physicalDeliveryOfficeName
|
||||
$ st $ l $ description ) )
|
||||
olcObjectClasses: {3}( 2.5.6.5 NAME 'organizationalUnit' DESC 'RFC2256: an o
|
||||
rganizational unit' SUP top STRUCTURAL MUST ou MAY ( userPassword $ searchG
|
||||
uide $ seeAlso $ businessCategory $ x121Address $ registeredAddress $ desti
|
||||
nationIndicator $ preferredDeliveryMethod $ telexNumber $ teletexTerminalId
|
||||
entifier $ telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNu
|
||||
mber $ street $ postOfficeBox $ postalCode $ postalAddress $ physicalDelive
|
||||
ryOfficeName $ st $ l $ description ) )
|
||||
olcObjectClasses: {4}( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP to
|
||||
p STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAls
|
||||
o $ description ) )
|
||||
olcObjectClasses: {5}( 2.5.6.7 NAME 'organizationalPerson' DESC 'RFC2256: an
|
||||
organizational person' SUP person STRUCTURAL MAY ( title $ x121Address $ r
|
||||
egisteredAddress $ destinationIndicator $ preferredDeliveryMethod $ telexNu
|
||||
mber $ teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumbe
|
||||
r $ facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $ posta
|
||||
lAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )
|
||||
olcObjectClasses: {6}( 2.5.6.8 NAME 'organizationalRole' DESC 'RFC2256: an o
|
||||
rganizational role' SUP top STRUCTURAL MUST cn MAY ( x121Address $ register
|
||||
edAddress $ destinationIndicator $ preferredDeliveryMethod $ telexNumber $
|
||||
teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumber $ fac
|
||||
simileTelephoneNumber $ seeAlso $ roleOccupant $ preferredDeliveryMethod $
|
||||
street $ postOfficeBox $ postalCode $ postalAddress $ physicalDeliveryOffic
|
||||
eName $ ou $ st $ l $ description ) )
|
||||
olcObjectClasses: {7}( 2.5.6.9 NAME 'groupOfNames' DESC 'RFC2256: a group of
|
||||
names (DNs)' SUP top STRUCTURAL MUST ( member $ cn ) MAY ( businessCategor
|
||||
y $ seeAlso $ owner $ ou $ o $ description ) )
|
||||
olcObjectClasses: {8}( 2.5.6.10 NAME 'residentialPerson' DESC 'RFC2256: an r
|
||||
esidential person' SUP person STRUCTURAL MUST l MAY ( businessCategory $ x1
|
||||
21Address $ registeredAddress $ destinationIndicator $ preferredDeliveryMet
|
||||
hod $ telexNumber $ teletexTerminalIdentifier $ telephoneNumber $ internati
|
||||
onaliSDNNumber $ facsimileTelephoneNumber $ preferredDeliveryMethod $ stree
|
||||
t $ postOfficeBox $ postalCode $ postalAddress $ physicalDeliveryOfficeName
|
||||
$ st $ l ) )
|
||||
olcObjectClasses: {9}( 2.5.6.11 NAME 'applicationProcess' DESC 'RFC2256: an
|
||||
application process' SUP top STRUCTURAL MUST cn MAY ( seeAlso $ ou $ l $ de
|
||||
scription ) )
|
||||
olcObjectClasses: {10}( 2.5.6.12 NAME 'applicationEntity' DESC 'RFC2256: an
|
||||
application entity' SUP top STRUCTURAL MUST ( presentationAddress $ cn ) MA
|
||||
Y ( supportedApplicationContext $ seeAlso $ ou $ o $ l $ description ) )
|
||||
olcObjectClasses: {11}( 2.5.6.13 NAME 'dSA' DESC 'RFC2256: a directory syste
|
||||
m agent (a server)' SUP applicationEntity STRUCTURAL MAY knowledgeInformati
|
||||
on )
|
||||
olcObjectClasses: {12}( 2.5.6.14 NAME 'device' DESC 'RFC2256: a device' SUP
|
||||
top STRUCTURAL MUST cn MAY ( serialNumber $ seeAlso $ owner $ ou $ o $ l $
|
||||
description ) )
|
||||
olcObjectClasses: {13}( 2.5.6.15 NAME 'strongAuthenticationUser' DESC 'RFC22
|
||||
56: a strong authentication user' SUP top AUXILIARY MUST userCertificate )
|
||||
olcObjectClasses: {14}( 2.5.6.16 NAME 'certificationAuthority' DESC 'RFC2256
|
||||
: a certificate authority' SUP top AUXILIARY MUST ( authorityRevocationList
|
||||
$ certificateRevocationList $ cACertificate ) MAY crossCertificatePair )
|
||||
olcObjectClasses: {15}( 2.5.6.17 NAME 'groupOfUniqueNames' DESC 'RFC2256: a
|
||||
group of unique names (DN and Unique Identifier)' SUP top STRUCTURAL MUST (
|
||||
uniqueMember $ cn ) MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ de
|
||||
scription ) )
|
||||
olcObjectClasses: {16}( 2.5.6.18 NAME 'userSecurityInformation' DESC 'RFC225
|
||||
6: a user security information' SUP top AUXILIARY MAY ( supportedAlgorithms
|
||||
) )
|
||||
olcObjectClasses: {17}( 2.5.6.16.2 NAME 'certificationAuthority-V2' SUP cert
|
||||
ificationAuthority AUXILIARY MAY ( deltaRevocationList ) )
|
||||
olcObjectClasses: {18}( 2.5.6.19 NAME 'cRLDistributionPoint' SUP top STRUCTU
|
||||
RAL MUST ( cn ) MAY ( certificateRevocationList $ authorityRevocationList $
|
||||
deltaRevocationList ) )
|
||||
olcObjectClasses: {19}( 2.5.6.20 NAME 'dmd' SUP top STRUCTURAL MUST ( dmdNam
|
||||
e ) MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $ x121Add
|
||||
ress $ registeredAddress $ destinationIndicator $ preferredDeliveryMethod $
|
||||
telexNumber $ teletexTerminalIdentifier $ telephoneNumber $ internationali
|
||||
SDNNumber $ facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode
|
||||
$ postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )
|
||||
olcObjectClasses: {20}( 2.5.6.21 NAME 'pkiUser' DESC 'RFC2587: a PKI user' S
|
||||
UP top AUXILIARY MAY userCertificate )
|
||||
olcObjectClasses: {21}( 2.5.6.22 NAME 'pkiCA' DESC 'RFC2587: PKI certificate
|
||||
authority' SUP top AUXILIARY MAY ( authorityRevocationList $ certificateRe
|
||||
vocationList $ cACertificate $ crossCertificatePair ) )
|
||||
olcObjectClasses: {22}( 2.5.6.23 NAME 'deltaCRL' DESC 'RFC2587: PKI user' SU
|
||||
P top AUXILIARY MAY deltaRevocationList )
|
||||
olcObjectClasses: {23}( 1.3.6.1.4.1.250.3.15 NAME 'labeledURIObject' DESC 'R
|
||||
FC2079: object that contains the URI attribute type' MAY ( labeledURI ) SUP
|
||||
top AUXILIARY )
|
||||
olcObjectClasses: {24}( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObjec
|
||||
t' DESC 'RFC1274: simple security object' SUP top AUXILIARY MUST userPasswo
|
||||
rd )
|
||||
olcObjectClasses: {25}( 1.3.6.1.4.1.1466.344 NAME 'dcObject' DESC 'RFC2247:
|
||||
domain component object' SUP top AUXILIARY MUST dc )
|
||||
olcObjectClasses: {26}( 1.3.6.1.1.3.1 NAME 'uidObject' DESC 'RFC2377: uid ob
|
||||
ject' SUP top AUXILIARY MUST uid )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c26a290-7ddc-103b-9ebf-c740e015b81b
|
||||
creatorsName: cn=admin,cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.324162Z#000000#000#000000
|
||||
modifiersName: cn=admin,cn=config
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,178 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 3133677b
|
||||
dn: cn={1}cosine
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {1}cosine
|
||||
olcAttributeTypes: {0}( 0.9.2342.19200300.100.1.2 NAME 'textEncodedORAddress
|
||||
' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.
|
||||
4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {1}( 0.9.2342.19200300.100.1.4 NAME 'info' DESC 'RFC1274:
|
||||
general information' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsM
|
||||
atch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{2048} )
|
||||
olcAttributeTypes: {2}( 0.9.2342.19200300.100.1.5 NAME ( 'drink' 'favouriteD
|
||||
rink' ) DESC 'RFC1274: favorite drink' EQUALITY caseIgnoreMatch SUBSTR case
|
||||
IgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {3}( 0.9.2342.19200300.100.1.6 NAME 'roomNumber' DESC 'RF
|
||||
C1274: room number' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMat
|
||||
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {4}( 0.9.2342.19200300.100.1.7 NAME 'photo' DESC 'RFC1274
|
||||
: photo (G3 fax)' SYNTAX 1.3.6.1.4.1.1466.115.121.1.23{25000} )
|
||||
olcAttributeTypes: {5}( 0.9.2342.19200300.100.1.8 NAME 'userClass' DESC 'RFC
|
||||
1274: category of user' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstring
|
||||
sMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {6}( 0.9.2342.19200300.100.1.9 NAME 'host' DESC 'RFC1274:
|
||||
host computer' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch S
|
||||
YNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {7}( 0.9.2342.19200300.100.1.10 NAME 'manager' DESC 'RFC1
|
||||
274: DN of manager' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466
|
||||
.115.121.1.12 )
|
||||
olcAttributeTypes: {8}( 0.9.2342.19200300.100.1.11 NAME 'documentIdentifier'
|
||||
DESC 'RFC1274: unique identifier of document' EQUALITY caseIgnoreMatch SUB
|
||||
STR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {9}( 0.9.2342.19200300.100.1.12 NAME 'documentTitle' DESC
|
||||
'RFC1274: title of document' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSub
|
||||
stringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {10}( 0.9.2342.19200300.100.1.13 NAME 'documentVersion' D
|
||||
ESC 'RFC1274: version of document' EQUALITY caseIgnoreMatch SUBSTR caseIgno
|
||||
reSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {11}( 0.9.2342.19200300.100.1.14 NAME 'documentAuthor' DE
|
||||
SC 'RFC1274: DN of author of document' EQUALITY distinguishedNameMatch SYNT
|
||||
AX 1.3.6.1.4.1.1466.115.121.1.12 )
|
||||
olcAttributeTypes: {12}( 0.9.2342.19200300.100.1.15 NAME 'documentLocation'
|
||||
DESC 'RFC1274: location of document original' EQUALITY caseIgnoreMatch SUBS
|
||||
TR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {13}( 0.9.2342.19200300.100.1.20 NAME ( 'homePhone' 'home
|
||||
TelephoneNumber' ) DESC 'RFC1274: home telephone number' EQUALITY telephone
|
||||
NumberMatch SUBSTR telephoneNumberSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.50 )
|
||||
olcAttributeTypes: {14}( 0.9.2342.19200300.100.1.21 NAME 'secretary' DESC 'R
|
||||
FC1274: DN of secretary' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1
|
||||
.1466.115.121.1.12 )
|
||||
olcAttributeTypes: {15}( 0.9.2342.19200300.100.1.22 NAME 'otherMailbox' SYNT
|
||||
AX 1.3.6.1.4.1.1466.115.121.1.39 )
|
||||
olcAttributeTypes: {16}( 0.9.2342.19200300.100.1.26 NAME 'aRecord' EQUALITY
|
||||
caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {17}( 0.9.2342.19200300.100.1.27 NAME 'mDRecord' EQUALITY
|
||||
caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {18}( 0.9.2342.19200300.100.1.28 NAME 'mXRecord' EQUALITY
|
||||
caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {19}( 0.9.2342.19200300.100.1.29 NAME 'nSRecord' EQUALITY
|
||||
caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {20}( 0.9.2342.19200300.100.1.30 NAME 'sOARecord' EQUALIT
|
||||
Y caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {21}( 0.9.2342.19200300.100.1.31 NAME 'cNAMERecord' EQUAL
|
||||
ITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {22}( 0.9.2342.19200300.100.1.38 NAME 'associatedName' DE
|
||||
SC 'RFC1274: DN of entry associated with domain' EQUALITY distinguishedName
|
||||
Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
|
||||
olcAttributeTypes: {23}( 0.9.2342.19200300.100.1.39 NAME 'homePostalAddress'
|
||||
DESC 'RFC1274: home postal address' EQUALITY caseIgnoreListMatch SUBSTR ca
|
||||
seIgnoreListSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
|
||||
olcAttributeTypes: {24}( 0.9.2342.19200300.100.1.40 NAME 'personalTitle' DES
|
||||
C 'RFC1274: personal title' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubst
|
||||
ringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {25}( 0.9.2342.19200300.100.1.41 NAME ( 'mobile' 'mobileT
|
||||
elephoneNumber' ) DESC 'RFC1274: mobile telephone number' EQUALITY telephon
|
||||
eNumberMatch SUBSTR telephoneNumberSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.
|
||||
115.121.1.50 )
|
||||
olcAttributeTypes: {26}( 0.9.2342.19200300.100.1.42 NAME ( 'pager' 'pagerTel
|
||||
ephoneNumber' ) DESC 'RFC1274: pager telephone number' EQUALITY telephoneNu
|
||||
mberMatch SUBSTR telephoneNumberSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115
|
||||
.121.1.50 )
|
||||
olcAttributeTypes: {27}( 0.9.2342.19200300.100.1.43 NAME ( 'co' 'friendlyCou
|
||||
ntryName' ) DESC 'RFC1274: friendly country name' EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {28}( 0.9.2342.19200300.100.1.44 NAME 'uniqueIdentifier'
|
||||
DESC 'RFC1274: unique identifer' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.
|
||||
1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {29}( 0.9.2342.19200300.100.1.45 NAME 'organizationalStat
|
||||
us' DESC 'RFC1274: organizational status' EQUALITY caseIgnoreMatch SUBSTR c
|
||||
aseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {30}( 0.9.2342.19200300.100.1.46 NAME 'janetMailbox' DESC
|
||||
'RFC1274: Janet mailbox' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5S
|
||||
ubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
|
||||
olcAttributeTypes: {31}( 0.9.2342.19200300.100.1.47 NAME 'mailPreferenceOpti
|
||||
on' DESC 'RFC1274: mail preference option' SYNTAX 1.3.6.1.4.1.1466.115.121.
|
||||
1.27 )
|
||||
olcAttributeTypes: {32}( 0.9.2342.19200300.100.1.48 NAME 'buildingName' DESC
|
||||
'RFC1274: name of building' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubs
|
||||
tringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {33}( 0.9.2342.19200300.100.1.49 NAME 'dSAQuality' DESC '
|
||||
RFC1274: DSA Quality' SYNTAX 1.3.6.1.4.1.1466.115.121.1.19 SINGLE-VALUE )
|
||||
olcAttributeTypes: {34}( 0.9.2342.19200300.100.1.50 NAME 'singleLevelQuality
|
||||
' DESC 'RFC1274: Single Level Quality' SYNTAX 1.3.6.1.4.1.1466.115.121.1.13
|
||||
SINGLE-VALUE )
|
||||
olcAttributeTypes: {35}( 0.9.2342.19200300.100.1.51 NAME 'subtreeMinimumQual
|
||||
ity' DESC 'RFC1274: Subtree Mininum Quality' SYNTAX 1.3.6.1.4.1.1466.115.12
|
||||
1.1.13 SINGLE-VALUE )
|
||||
olcAttributeTypes: {36}( 0.9.2342.19200300.100.1.52 NAME 'subtreeMaximumQual
|
||||
ity' DESC 'RFC1274: Subtree Maximun Quality' SYNTAX 1.3.6.1.4.1.1466.115.12
|
||||
1.1.13 SINGLE-VALUE )
|
||||
olcAttributeTypes: {37}( 0.9.2342.19200300.100.1.53 NAME 'personalSignature'
|
||||
DESC 'RFC1274: Personal Signature (G3 fax)' SYNTAX 1.3.6.1.4.1.1466.115.12
|
||||
1.1.23 )
|
||||
olcAttributeTypes: {38}( 0.9.2342.19200300.100.1.54 NAME 'dITRedirect' DESC
|
||||
'RFC1274: DIT Redirect' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.
|
||||
1466.115.121.1.12 )
|
||||
olcAttributeTypes: {39}( 0.9.2342.19200300.100.1.55 NAME 'audio' DESC 'RFC12
|
||||
74: audio (u-law)' SYNTAX 1.3.6.1.4.1.1466.115.121.1.4{25000} )
|
||||
olcAttributeTypes: {40}( 0.9.2342.19200300.100.1.56 NAME 'documentPublisher'
|
||||
DESC 'RFC1274: publisher of document' EQUALITY caseIgnoreMatch SUBSTR case
|
||||
IgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcObjectClasses: {0}( 0.9.2342.19200300.100.4.4 NAME ( 'pilotPerson' 'newPi
|
||||
lotPerson' ) SUP person STRUCTURAL MAY ( userid $ textEncodedORAddress $ rf
|
||||
c822Mailbox $ favouriteDrink $ roomNumber $ userClass $ homeTelephoneNumber
|
||||
$ homePostalAddress $ secretary $ personalTitle $ preferredDeliveryMethod
|
||||
$ businessCategory $ janetMailbox $ otherMailbox $ mobileTelephoneNumber $
|
||||
pagerTelephoneNumber $ organizationalStatus $ mailPreferenceOption $ person
|
||||
alSignature ) )
|
||||
olcObjectClasses: {1}( 0.9.2342.19200300.100.4.5 NAME 'account' SUP top STRU
|
||||
CTURAL MUST userid MAY ( description $ seeAlso $ localityName $ organizatio
|
||||
nName $ organizationalUnitName $ host ) )
|
||||
olcObjectClasses: {2}( 0.9.2342.19200300.100.4.6 NAME 'document' SUP top STR
|
||||
UCTURAL MUST documentIdentifier MAY ( commonName $ description $ seeAlso $
|
||||
localityName $ organizationName $ organizationalUnitName $ documentTitle $
|
||||
documentVersion $ documentAuthor $ documentLocation $ documentPublisher ) )
|
||||
olcObjectClasses: {3}( 0.9.2342.19200300.100.4.7 NAME 'room' SUP top STRUCTU
|
||||
RAL MUST commonName MAY ( roomNumber $ description $ seeAlso $ telephoneNum
|
||||
ber ) )
|
||||
olcObjectClasses: {4}( 0.9.2342.19200300.100.4.9 NAME 'documentSeries' SUP t
|
||||
op STRUCTURAL MUST commonName MAY ( description $ seeAlso $ telephonenumber
|
||||
$ localityName $ organizationName $ organizationalUnitName ) )
|
||||
olcObjectClasses: {5}( 0.9.2342.19200300.100.4.13 NAME 'domain' SUP top STRU
|
||||
CTURAL MUST domainComponent MAY ( associatedName $ organizationName $ descr
|
||||
iption $ businessCategory $ seeAlso $ searchGuide $ userPassword $ locality
|
||||
Name $ stateOrProvinceName $ streetAddress $ physicalDeliveryOfficeName $ p
|
||||
ostalAddress $ postalCode $ postOfficeBox $ streetAddress $ facsimileTeleph
|
||||
oneNumber $ internationalISDNNumber $ telephoneNumber $ teletexTerminalIden
|
||||
tifier $ telexNumber $ preferredDeliveryMethod $ destinationIndicator $ reg
|
||||
isteredAddress $ x121Address ) )
|
||||
olcObjectClasses: {6}( 0.9.2342.19200300.100.4.14 NAME 'RFC822localPart' SUP
|
||||
domain STRUCTURAL MAY ( commonName $ surname $ description $ seeAlso $ tel
|
||||
ephoneNumber $ physicalDeliveryOfficeName $ postalAddress $ postalCode $ po
|
||||
stOfficeBox $ streetAddress $ facsimileTelephoneNumber $ internationalISDNN
|
||||
umber $ telephoneNumber $ teletexTerminalIdentifier $ telexNumber $ preferr
|
||||
edDeliveryMethod $ destinationIndicator $ registeredAddress $ x121Address )
|
||||
)
|
||||
olcObjectClasses: {7}( 0.9.2342.19200300.100.4.15 NAME 'dNSDomain' SUP domai
|
||||
n STRUCTURAL MAY ( ARecord $ MDRecord $ MXRecord $ NSRecord $ SOARecord $ C
|
||||
NAMERecord ) )
|
||||
olcObjectClasses: {8}( 0.9.2342.19200300.100.4.17 NAME 'domainRelatedObject'
|
||||
DESC 'RFC1274: an object related to an domain' SUP top AUXILIARY MUST asso
|
||||
ciatedDomain )
|
||||
olcObjectClasses: {9}( 0.9.2342.19200300.100.4.18 NAME 'friendlyCountry' SUP
|
||||
country STRUCTURAL MUST friendlyCountryName )
|
||||
olcObjectClasses: {10}( 0.9.2342.19200300.100.4.20 NAME 'pilotOrganization'
|
||||
SUP ( organization $ organizationalUnit ) STRUCTURAL MAY buildingName )
|
||||
olcObjectClasses: {11}( 0.9.2342.19200300.100.4.21 NAME 'pilotDSA' SUP dsa S
|
||||
TRUCTURAL MAY dSAQuality )
|
||||
olcObjectClasses: {12}( 0.9.2342.19200300.100.4.22 NAME 'qualityLabelledData
|
||||
' SUP top AUXILIARY MUST dsaQuality MAY ( subtreeMinimumQuality $ subtreeMa
|
||||
ximumQuality ) )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c286ac6-7ddc-103b-9ec0-c740e015b81b
|
||||
creatorsName: cn=admin,cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.335841Z#000000#000#000000
|
||||
modifiersName: cn=admin,cn=config
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,108 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 8c7d43da
|
||||
dn: cn={2}nis
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {2}nis
|
||||
olcAttributeTypes: {0}( 1.3.6.1.1.1.1.2 NAME 'gecos' DESC 'The GECOS field;
|
||||
the common name' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5Substrings
|
||||
Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
|
||||
olcAttributeTypes: {1}( 1.3.6.1.1.1.1.3 NAME 'homeDirectory' DESC 'The absol
|
||||
ute path to the home directory' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4
|
||||
.1.1466.115.121.1.26 SINGLE-VALUE )
|
||||
olcAttributeTypes: {2}( 1.3.6.1.1.1.1.4 NAME 'loginShell' DESC 'The path to
|
||||
the login shell' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121
|
||||
.1.26 SINGLE-VALUE )
|
||||
olcAttributeTypes: {3}( 1.3.6.1.1.1.1.5 NAME 'shadowLastChange' EQUALITY int
|
||||
egerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 1.3.6.1.1.1.1.6 NAME 'shadowMin' EQUALITY integerMat
|
||||
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {5}( 1.3.6.1.1.1.1.7 NAME 'shadowMax' EQUALITY integerMat
|
||||
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {6}( 1.3.6.1.1.1.1.8 NAME 'shadowWarning' EQUALITY intege
|
||||
rMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {7}( 1.3.6.1.1.1.1.9 NAME 'shadowInactive' EQUALITY integ
|
||||
erMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {8}( 1.3.6.1.1.1.1.10 NAME 'shadowExpire' EQUALITY intege
|
||||
rMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {9}( 1.3.6.1.1.1.1.11 NAME 'shadowFlag' EQUALITY integerM
|
||||
atch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {10}( 1.3.6.1.1.1.1.12 NAME 'memberUid' EQUALITY caseExac
|
||||
tIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.12
|
||||
1.1.26 )
|
||||
olcAttributeTypes: {11}( 1.3.6.1.1.1.1.13 NAME 'memberNisNetgroup' EQUALITY
|
||||
caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.146
|
||||
6.115.121.1.26 )
|
||||
olcAttributeTypes: {12}( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple' DESC 'Net
|
||||
group triple' SYNTAX 1.3.6.1.1.1.0.0 )
|
||||
olcAttributeTypes: {13}( 1.3.6.1.1.1.1.15 NAME 'ipServicePort' EQUALITY inte
|
||||
gerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {14}( 1.3.6.1.1.1.1.16 NAME 'ipServiceProtocol' SUP name
|
||||
)
|
||||
olcAttributeTypes: {15}( 1.3.6.1.1.1.1.17 NAME 'ipProtocolNumber' EQUALITY i
|
||||
ntegerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {16}( 1.3.6.1.1.1.1.18 NAME 'oncRpcNumber' EQUALITY integ
|
||||
erMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {17}( 1.3.6.1.1.1.1.19 NAME 'ipHostNumber' DESC 'IP addre
|
||||
ss' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
|
||||
olcAttributeTypes: {18}( 1.3.6.1.1.1.1.20 NAME 'ipNetworkNumber' DESC 'IP ne
|
||||
twork' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128
|
||||
} SINGLE-VALUE )
|
||||
olcAttributeTypes: {19}( 1.3.6.1.1.1.1.21 NAME 'ipNetmaskNumber' DESC 'IP ne
|
||||
tmask' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128
|
||||
} SINGLE-VALUE )
|
||||
olcAttributeTypes: {20}( 1.3.6.1.1.1.1.22 NAME 'macAddress' DESC 'MAC addres
|
||||
s' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
|
||||
olcAttributeTypes: {21}( 1.3.6.1.1.1.1.23 NAME 'bootParameter' DESC 'rpc.boo
|
||||
tparamd parameter' SYNTAX 1.3.6.1.1.1.0.1 )
|
||||
olcAttributeTypes: {22}( 1.3.6.1.1.1.1.24 NAME 'bootFile' DESC 'Boot image n
|
||||
ame' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {23}( 1.3.6.1.1.1.1.26 NAME 'nisMapName' SUP name )
|
||||
olcAttributeTypes: {24}( 1.3.6.1.1.1.1.27 NAME 'nisMapEntry' EQUALITY caseEx
|
||||
actIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.
|
||||
121.1.26{1024} SINGLE-VALUE )
|
||||
olcObjectClasses: {0}( 1.3.6.1.1.1.2.0 NAME 'posixAccount' DESC 'Abstraction
|
||||
of an account with POSIX attributes' SUP top AUXILIARY MUST ( cn $ uid $ u
|
||||
idNumber $ gidNumber $ homeDirectory ) MAY ( userPassword $ loginShell $ ge
|
||||
cos $ description ) )
|
||||
olcObjectClasses: {1}( 1.3.6.1.1.1.2.1 NAME 'shadowAccount' DESC 'Additional
|
||||
attributes for shadow passwords' SUP top AUXILIARY MUST uid MAY ( userPass
|
||||
word $ shadowLastChange $ shadowMin $ shadowMax $ shadowWarning $ shadowIna
|
||||
ctive $ shadowExpire $ shadowFlag $ description ) )
|
||||
olcObjectClasses: {2}( 1.3.6.1.1.1.2.2 NAME 'posixGroup' DESC 'Abstraction o
|
||||
f a group of accounts' SUP top STRUCTURAL MUST ( cn $ gidNumber ) MAY ( use
|
||||
rPassword $ memberUid $ description ) )
|
||||
olcObjectClasses: {3}( 1.3.6.1.1.1.2.3 NAME 'ipService' DESC 'Abstraction an
|
||||
Internet Protocol service' SUP top STRUCTURAL MUST ( cn $ ipServicePort $
|
||||
ipServiceProtocol ) MAY description )
|
||||
olcObjectClasses: {4}( 1.3.6.1.1.1.2.4 NAME 'ipProtocol' DESC 'Abstraction o
|
||||
f an IP protocol' SUP top STRUCTURAL MUST ( cn $ ipProtocolNumber $ descrip
|
||||
tion ) MAY description )
|
||||
olcObjectClasses: {5}( 1.3.6.1.1.1.2.5 NAME 'oncRpc' DESC 'Abstraction of an
|
||||
ONC/RPC binding' SUP top STRUCTURAL MUST ( cn $ oncRpcNumber $ description
|
||||
) MAY description )
|
||||
olcObjectClasses: {6}( 1.3.6.1.1.1.2.6 NAME 'ipHost' DESC 'Abstraction of a
|
||||
host, an IP device' SUP top AUXILIARY MUST ( cn $ ipHostNumber ) MAY ( l $
|
||||
description $ manager ) )
|
||||
olcObjectClasses: {7}( 1.3.6.1.1.1.2.7 NAME 'ipNetwork' DESC 'Abstraction of
|
||||
an IP network' SUP top STRUCTURAL MUST ( cn $ ipNetworkNumber ) MAY ( ipNe
|
||||
tmaskNumber $ l $ description $ manager ) )
|
||||
olcObjectClasses: {8}( 1.3.6.1.1.1.2.8 NAME 'nisNetgroup' DESC 'Abstraction
|
||||
of a netgroup' SUP top STRUCTURAL MUST cn MAY ( nisNetgroupTriple $ memberN
|
||||
isNetgroup $ description ) )
|
||||
olcObjectClasses: {9}( 1.3.6.1.1.1.2.9 NAME 'nisMap' DESC 'A generic abstrac
|
||||
tion of a NIS map' SUP top STRUCTURAL MUST nisMapName MAY description )
|
||||
olcObjectClasses: {10}( 1.3.6.1.1.1.2.10 NAME 'nisObject' DESC 'An entry in
|
||||
a NIS map' SUP top STRUCTURAL MUST ( cn $ nisMapEntry $ nisMapName ) MAY de
|
||||
scription )
|
||||
olcObjectClasses: {11}( 1.3.6.1.1.1.2.11 NAME 'ieee802Device' DESC 'A device
|
||||
with a MAC address' SUP top AUXILIARY MAY macAddress )
|
||||
olcObjectClasses: {12}( 1.3.6.1.1.1.2.12 NAME 'bootableDevice' DESC 'A devic
|
||||
e with boot parameters' SUP top AUXILIARY MAY ( bootFile $ bootParameter )
|
||||
)
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c2966ce-7ddc-103b-9ec1-c740e015b81b
|
||||
creatorsName: cn=admin,cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.342294Z#000000#000#000000
|
||||
modifiersName: cn=admin,cn=config
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,49 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 b409a0c2
|
||||
dn: cn={3}inetorgperson
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {3}inetorgperson
|
||||
olcAttributeTypes: {0}( 2.16.840.1.113730.3.1.1 NAME 'carLicense' DESC 'RFC2
|
||||
798: vehicle license or registration plate' EQUALITY caseIgnoreMatch SUBSTR
|
||||
caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {1}( 2.16.840.1.113730.3.1.2 NAME 'departmentNumber' DESC
|
||||
'RFC2798: identifies a department within an organization' EQUALITY caseIgn
|
||||
oreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1
|
||||
.15 )
|
||||
olcAttributeTypes: {2}( 2.16.840.1.113730.3.1.241 NAME 'displayName' DESC 'R
|
||||
FC2798: preferred name to be used when displaying entries' EQUALITY caseIgn
|
||||
oreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1
|
||||
.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {3}( 2.16.840.1.113730.3.1.3 NAME 'employeeNumber' DESC '
|
||||
RFC2798: numerically identifies an employee within an organization' EQUALIT
|
||||
Y caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.
|
||||
115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 2.16.840.1.113730.3.1.4 NAME 'employeeType' DESC 'RF
|
||||
C2798: type of employment for a person' EQUALITY caseIgnoreMatch SUBSTR cas
|
||||
eIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {5}( 0.9.2342.19200300.100.1.60 NAME 'jpegPhoto' DESC 'RF
|
||||
C2798: a JPEG image' SYNTAX 1.3.6.1.4.1.1466.115.121.1.28 )
|
||||
olcAttributeTypes: {6}( 2.16.840.1.113730.3.1.39 NAME 'preferredLanguage' DE
|
||||
SC 'RFC2798: preferred written or spoken language for a person' EQUALITY ca
|
||||
seIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.
|
||||
121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {7}( 2.16.840.1.113730.3.1.40 NAME 'userSMIMECertificate'
|
||||
DESC 'RFC2798: PKCS#7 SignedData used to support S/MIME' SYNTAX 1.3.6.1.4.
|
||||
1.1466.115.121.1.5 )
|
||||
olcAttributeTypes: {8}( 2.16.840.1.113730.3.1.216 NAME 'userPKCS12' DESC 'RF
|
||||
C2798: personal identity information, a PKCS #12 PFX' SYNTAX 1.3.6.1.4.1.14
|
||||
66.115.121.1.5 )
|
||||
olcObjectClasses: {0}( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' DESC 'RF
|
||||
C2798: Internet Organizational Person' SUP organizationalPerson STRUCTURAL
|
||||
MAY ( audio $ businessCategory $ carLicense $ departmentNumber $ displayNam
|
||||
e $ employeeNumber $ employeeType $ givenName $ homePhone $ homePostalAddre
|
||||
ss $ initials $ jpegPhoto $ labeledURI $ mail $ manager $ mobile $ o $ page
|
||||
r $ photo $ roomNumber $ secretary $ uid $ userCertificate $ x500uniqueIden
|
||||
tifier $ preferredLanguage $ userSMIMECertificate $ userPKCS12 ) )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c2a5016-7ddc-103b-9ec2-c740e015b81b
|
||||
creatorsName: cn=admin,cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.348266Z#000000#000#000000
|
||||
modifiersName: cn=admin,cn=config
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,65 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 cded21ef
|
||||
dn: cn={4}ppolicy
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {4}ppolicy
|
||||
olcAttributeTypes: {0}( 1.3.6.1.4.1.42.2.27.8.1.1 NAME 'pwdAttribute' EQUALI
|
||||
TY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
|
||||
olcAttributeTypes: {1}( 1.3.6.1.4.1.42.2.27.8.1.2 NAME 'pwdMinAge' EQUALITY
|
||||
integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.
|
||||
1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {2}( 1.3.6.1.4.1.42.2.27.8.1.3 NAME 'pwdMaxAge' EQUALITY
|
||||
integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.
|
||||
1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {3}( 1.3.6.1.4.1.42.2.27.8.1.4 NAME 'pwdInHistory' EQUALI
|
||||
TY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.1
|
||||
21.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 1.3.6.1.4.1.42.2.27.8.1.5 NAME 'pwdCheckQuality' EQU
|
||||
ALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.11
|
||||
5.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {5}( 1.3.6.1.4.1.42.2.27.8.1.6 NAME 'pwdMinLength' EQUALI
|
||||
TY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.
|
||||
121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {6}( 1.3.6.1.4.1.42.2.27.8.1.7 NAME 'pwdExpireWarning' EQ
|
||||
UALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.
|
||||
115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {7}( 1.3.6.1.4.1.42.2.27.8.1.8 NAME 'pwdGraceAuthNLimit'
|
||||
EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.146
|
||||
6.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {8}( 1.3.6.1.4.1.42.2.27.8.1.9 NAME 'pwdLockout' EQUALITY
|
||||
booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
|
||||
olcAttributeTypes: {9}( 1.3.6.1.4.1.42.2.27.8.1.10 NAME 'pwdLockoutDuration'
|
||||
EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.14
|
||||
66.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {10}( 1.3.6.1.4.1.42.2.27.8.1.11 NAME 'pwdMaxFailure' EQU
|
||||
ALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {11}( 1.3.6.1.4.1.42.2.27.8.1.12 NAME 'pwdFailureCountInt
|
||||
erval' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.
|
||||
4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {12}( 1.3.6.1.4.1.42.2.27.8.1.13 NAME 'pwdMustChange' EQU
|
||||
ALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
|
||||
olcAttributeTypes: {13}( 1.3.6.1.4.1.42.2.27.8.1.14 NAME 'pwdAllowUserChange
|
||||
' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
|
||||
olcAttributeTypes: {14}( 1.3.6.1.4.1.42.2.27.8.1.15 NAME 'pwdSafeModify' EQU
|
||||
ALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
|
||||
olcAttributeTypes: {15}( 1.3.6.1.4.1.4754.1.99.1 NAME 'pwdCheckModule' DESC
|
||||
'Loadable module that instantiates "check_password() function' EQUALITY cas
|
||||
eExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
|
||||
olcAttributeTypes: {16}( 1.3.6.1.4.1.42.2.27.8.1.30 NAME 'pwdMaxRecordedFail
|
||||
ure' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.
|
||||
1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcObjectClasses: {0}( 1.3.6.1.4.1.4754.2.99.1 NAME 'pwdPolicyChecker' SUP t
|
||||
op AUXILIARY MAY pwdCheckModule )
|
||||
olcObjectClasses: {1}( 1.3.6.1.4.1.42.2.27.8.2.1 NAME 'pwdPolicy' SUP top AU
|
||||
XILIARY MUST pwdAttribute MAY ( pwdMinAge $ pwdMaxAge $ pwdInHistory $ pwdC
|
||||
heckQuality $ pwdMinLength $ pwdExpireWarning $ pwdGraceAuthNLimit $ pwdLoc
|
||||
kout $ pwdLockoutDuration $ pwdMaxFailure $ pwdFailureCountInterval $ pwdMu
|
||||
stChange $ pwdAllowUserChange $ pwdSafeModify $ pwdMaxRecordedFailure ) )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c51364a-7ddc-103b-8d41-8b35b6446851
|
||||
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.603187Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,175 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 7d21399c
|
||||
dn: cn={5}kopano
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {5}kopano
|
||||
olcAttributeTypes: {0}( 1.3.6.1.4.1.47732.1.1.1.1 NAME 'kopanoQuotaOverride'
|
||||
DESC 'KOPANO: Override child quota' EQUALITY integerMatch SYNTAX 1.3.6.1.4
|
||||
.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {1}( 1.3.6.1.4.1.47732.1.1.1.2 NAME 'kopanoQuotaWarn' DES
|
||||
C 'KOPANO: Warning quota size in MB' EQUALITY integerMatch SYNTAX 1.3.6.1.4
|
||||
.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {2}( 1.3.6.1.4.1.47732.1.1.1.3 NAME 'kopanoQuotaSoft' DES
|
||||
C 'KOPANO: Soft quota size in MB' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.
|
||||
1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {3}( 1.3.6.1.4.1.47732.1.1.1.4 NAME 'kopanoQuotaHard' DES
|
||||
C 'KOPANO: Hard quota size in MB' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.
|
||||
1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 1.3.6.1.4.1.47732.1.1.1.5 NAME 'kopanoUserDefaultQuo
|
||||
taOverride' DESC 'KOPANO: Override User default quota for children' EQUALIT
|
||||
Y integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {5}( 1.3.6.1.4.1.47732.1.1.1.6 NAME 'kopanoUserDefaultQuo
|
||||
taWarn' DESC 'KOPANO: User default warning quota size in MB' EQUALITY integ
|
||||
erMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {6}( 1.3.6.1.4.1.47732.1.1.1.7 NAME 'kopanoUserDefaultQuo
|
||||
taSoft' DESC 'KOPANO: User default soft quota size in MB' EQUALITY integerM
|
||||
atch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {7}( 1.3.6.1.4.1.47732.1.1.1.8 NAME 'kopanoUserDefaultQuo
|
||||
taHard' DESC 'KOPANO: User default hard quota size in MB' EQUALITY integerM
|
||||
atch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {8}( 1.3.6.1.4.1.47732.1.1.2.1 NAME 'kopanoAdmin' DESC 'K
|
||||
OPANO: Administrator of kopano' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.14
|
||||
66.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {9}( 1.3.6.1.4.1.47732.1.1.2.2 NAME 'kopanoSharedStoreOnl
|
||||
y' DESC 'KOPANO: is store a shared store' EQUALITY integerMatch SYNTAX 1.3.
|
||||
6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {10}( 1.3.6.1.4.1.47732.1.1.2.3 NAME 'kopanoAccount' DESC
|
||||
'KOPANO: entry is a part of kopano' EQUALITY integerMatch SYNTAX 1.3.6.1.4
|
||||
.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {11}( 1.3.6.1.4.1.47732.1.1.2.4 NAME 'kopanoSendAsPrivile
|
||||
ge' DESC 'KOPANO: Users may directly send email as this user' EQUALITY case
|
||||
IgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.12
|
||||
1.1.15 )
|
||||
olcAttributeTypes: {12}( 1.3.6.1.4.1.47732.1.1.2.5 NAME 'kopanoMrAccept' DES
|
||||
C 'KOPANO: user should auto-accept meeting requests' EQUALITY integerMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {13}( 1.3.6.1.4.1.47732.1.1.2.6 NAME 'kopanoMrDeclineConf
|
||||
lict' DESC 'KOPANO: user should automatically decline conflicting meeting r
|
||||
equests' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-
|
||||
VALUE )
|
||||
olcAttributeTypes: {14}( 1.3.6.1.4.1.47732.1.1.2.7 NAME 'kopanoMrDeclineRecu
|
||||
rring' DESC 'KOPANO: user should automatically decline recurring meeting re
|
||||
quests' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-V
|
||||
ALUE )
|
||||
olcAttributeTypes: {15}( 1.3.6.1.4.1.47732.1.1.2.8 NAME 'kopanoId' DESC 'KOP
|
||||
ANO: Generic unique ID' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.40 SINGLE-VALUE )
|
||||
olcAttributeTypes: {16}( 1.3.6.1.4.1.47732.1.1.2.9 NAME 'kopanoResourceType'
|
||||
DESC 'KOPANO: for shared stores, resource is type Room or Equipment' EQUAL
|
||||
ITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.146
|
||||
6.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {17}( 1.3.6.1.4.1.47732.1.1.2.10 NAME 'kopanoResourceCapa
|
||||
city' DESC 'KOPANO: number of rooms or equipment available' EQUALITY intege
|
||||
rMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {18}( 1.3.6.1.4.1.47732.1.1.2.11 NAME 'kopanoHidden' DESC
|
||||
'KOPANO: This object should be hidden from address book' EQUALITY integerM
|
||||
atch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {19}( 1.3.6.1.4.1.47732.1.1.2.13 NAME 'kopanoEnabledFeatu
|
||||
res' DESC 'KOPANO: This user has these features explicitly enabled' EQUALIT
|
||||
Y caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
|
||||
olcAttributeTypes: {20}( 1.3.6.1.4.1.47732.1.1.2.14 NAME 'kopanoDisabledFeat
|
||||
ures' DESC 'KOPANO: This user has these features explicitly disabled' EQUAL
|
||||
ITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
|
||||
olcAttributeTypes: {21}( 1.3.6.1.4.1.47732.1.1.3.1 NAME 'kopanoAliases' DESC
|
||||
'KOPANO: All other email addresses for this user' EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {22}( 1.3.6.1.4.1.47732.1.1.4.1 NAME 'kopanoUserServer' D
|
||||
ESC 'KOPANO: Home server for the user' EQUALITY caseIgnoreMatch SUBSTR case
|
||||
IgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {23}( 1.3.6.1.4.1.47732.1.1.6.1 NAME 'kopanoUserArchiveSe
|
||||
rvers' DESC 'KOPANO: List of server names that contain an archive store for
|
||||
the user' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX
|
||||
1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {24}( 1.3.6.1.4.1.47732.1.1.6.2 NAME 'kopanoUserArchiveCo
|
||||
uplings' DESC 'KOPANO: List of username:foldername pairs that specify many-
|
||||
to-one archive locations' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstri
|
||||
ngsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {25}( 1.3.6.1.4.1.47732.1.2.2.1 NAME 'kopanoSecurityGroup
|
||||
' DESC 'KOPANO: group has security possibilities' EQUALITY integerMatch SYN
|
||||
TAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {26}( 1.3.6.1.4.1.47732.1.3.2.4 NAME 'kopanoViewPrivilege
|
||||
' DESC 'KOPANO: Companies with view privileges over selected company' EQUAL
|
||||
ITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.146
|
||||
6.115.121.1.15 )
|
||||
olcAttributeTypes: {27}( 1.3.6.1.4.1.47732.1.3.2.5 NAME 'kopanoAdminPrivileg
|
||||
e' DESC 'KOPANO: Users from different companies which are administrator ove
|
||||
r selected company' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMat
|
||||
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {28}( 1.3.6.1.4.1.47732.1.3.2.6 NAME 'kopanoSystemAdmin'
|
||||
DESC 'KOPANO: The user who is the system administrator for this company' EQ
|
||||
UALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.
|
||||
1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {29}( 1.3.6.1.4.1.47732.1.3.1.5 NAME 'kopanoQuotaUserWarn
|
||||
ingRecipients' DESC 'KOPANO: Users who will receive a notification email wh
|
||||
en a user exceeds his quota' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubs
|
||||
tringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {30}( 1.3.6.1.4.1.47732.1.3.1.6 NAME 'kopanoQuotaCompanyW
|
||||
arningRecipients' DESC 'KOPANO: Users who will receive a notification email
|
||||
when a company exceeds its quota' EQUALITY caseIgnoreMatch SUBSTR caseIgno
|
||||
reSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {31}( 1.3.6.1.4.1.47732.1.3.4.1 NAME 'kopanoCompanyServer
|
||||
' DESC 'KOPANO: Home server for the public folders for a company' EQUALITY
|
||||
caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.11
|
||||
5.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {32}( 1.3.6.1.4.1.47732.1.4.4.1 NAME 'kopanoHttpPort' DES
|
||||
C 'KOPANO: Port for the http connection' EQUALITY integerMatch SYNTAX 1.3.6
|
||||
.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {33}( 1.3.6.1.4.1.47732.1.4.4.2 NAME 'kopanoSslPort' DESC
|
||||
'KOPANO: Port for the ssl connection' EQUALITY integerMatch SYNTAX 1.3.6.1
|
||||
.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {34}( 1.3.6.1.4.1.47732.1.4.4.3 NAME 'kopanoFilePath' DES
|
||||
C 'KOPANO: The Unix socket or named pipe to the server' EQUALITY caseIgnore
|
||||
Match SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
olcAttributeTypes: {35}( 1.3.6.1.4.1.47732.1.4.4.4 NAME 'kopanoContainsPubli
|
||||
c' DESC 'KOPANO: This server contains the public store' EQUALITY integerMat
|
||||
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {36}( 1.3.6.1.4.1.47732.1.4.4.6 NAME 'kopanoProxyURL' DES
|
||||
C 'KOPANO: Full proxy URL for this server' EQUALITY caseIgnoreMatch SUBSTR
|
||||
caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
|
||||
)
|
||||
olcAttributeTypes: {37}( 1.3.6.1.4.1.47732.1.5.5.1 NAME 'kopanoFilter' DESC
|
||||
'KOPANO: LDAP Filter to apply' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSu
|
||||
bstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {38}( 1.3.6.1.4.1.47732.1.5.5.2 NAME 'kopanoBase' DESC 'K
|
||||
OPANO: LDAP Search base to apply' EQUALITY caseIgnoreMatch SUBSTR caseIgnor
|
||||
eSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcObjectClasses: {0}( 1.3.6.1.4.1.47732.1.1.0.0 NAME 'kopano-user' DESC 'KO
|
||||
PANO: an user of Kopano' SUP top AUXILIARY MUST cn MAY ( kopanoQuotaOverrid
|
||||
e $ kopanoQuotaWarn $ kopanoQuotaSoft $ kopanoSendAsPrivilege $ kopanoQuota
|
||||
Hard $ kopanoAdmin $ kopanoSharedStoreOnly $ kopanoResourceType $ kopanoRes
|
||||
ourceCapacity $ kopanoAccount $ kopanoHidden $ kopanoAliases $ kopanoUserSe
|
||||
rver $ kopanoEnabledFeatures $ kopanoDisabledFeatures $ kopanoUserArchiveSe
|
||||
rvers $ kopanoUserArchiveCouplings $ uidNumber ) )
|
||||
olcObjectClasses: {1}( 1.3.6.1.4.1.47732.1.6.0.0 NAME 'kopano-contact' DESC
|
||||
'KOPANO: a contact of Kopano' SUP top AUXILIARY MUST ( cn $ uidNumber ) MAY
|
||||
( kopanoSendAsPrivilege $ kopanoHidden $ kopanoAliases $ kopanoAccount ) )
|
||||
olcObjectClasses: {2}( 1.3.6.1.4.1.47732.1.2.0.0 NAME 'kopano-group' DESC 'K
|
||||
OPANO: a group of Kopano' SUP top AUXILIARY MUST cn MAY ( kopanoAccount $ k
|
||||
opanoHidden $ mail $ kopanoAliases $ kopanoSecurityGroup $ kopanoSendAsPriv
|
||||
ilege $ gidNumber ) )
|
||||
olcObjectClasses: {3}( 1.3.6.1.4.1.47732.1.3.0.0 NAME 'kopano-company' DESC
|
||||
'KOPANO: a company of Kopano' SUP top AUXILIARY MUST ou MAY ( kopanoAccount
|
||||
$ kopanoHidden $ kopanoViewPrivilege $ kopanoAdminPrivilege $ kopanoSystem
|
||||
Admin $ kopanoQuotaOverride $ kopanoQuotaWarn $ kopanoUserDefaultQuotaOverr
|
||||
ide $ kopanoUserDefaultQuotaWarn $ kopanoUserDefaultQuotaSoft $ kopanoUserD
|
||||
efaultQuotaHard $ kopanoQuotaUserWarningRecipients $ kopanoQuotaCompanyWarn
|
||||
ingRecipients $ kopanoCompanyServer ) )
|
||||
olcObjectClasses: {4}( 1.3.6.1.4.1.47732.1.4.0.0 NAME 'kopano-server' DESC '
|
||||
KOPANO: a Kopano server' SUP top AUXILIARY MUST cn MAY ( kopanoAccount $ ko
|
||||
panoHidden $ kopanoHttpPort $ kopanoSslPort $ kopanoFilePath $ kopanoContai
|
||||
nsPublic $ kopanoProxyURL ) )
|
||||
olcObjectClasses: {5}( 1.3.6.1.4.1.47732.1.5.0.0 NAME 'kopano-addresslist' D
|
||||
ESC 'KOPANO: a Kopano Addresslist' SUP top STRUCTURAL MUST cn MAY ( kopanoA
|
||||
ccount $ kopanoHidden $ kopanoFilter $ kopanoBase ) )
|
||||
olcObjectClasses: {6}( 1.3.6.1.4.1.47732.1.7.0.0 NAME 'kopano-dynamicgroup'
|
||||
DESC 'KOPANO: a Kopano dynamic group' SUP top STRUCTURAL MUST cn MAY ( kopa
|
||||
noAccount $ kopanoHidden $ mail $ kopanoAliases $ kopanoFilter $ kopanoBase
|
||||
) )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c5ee420-7ddc-103b-8d42-8b35b6446851
|
||||
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.692846Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,18 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 815bdd09
|
||||
dn: cn={6}openssh-lpk
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {6}openssh-lpk
|
||||
olcAttributeTypes: {0}( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' D
|
||||
ESC 'MANDATORY: OpenSSH Public key' EQUALITY octetStringMatch SYNTAX 1.3.6.
|
||||
1.4.1.1466.115.121.1.40 )
|
||||
olcObjectClasses: {0}( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' DE
|
||||
SC 'MANDATORY: OpenSSH LPK objectclass' SUP top AUXILIARY MAY ( sshPublicKe
|
||||
y $ uid ) )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c6226ee-7ddc-103b-8d43-8b35b6446851
|
||||
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.714216Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,50 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 38be59a6
|
||||
dn: cn={7}postfix-book
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {7}postfix-book
|
||||
olcAttributeTypes: {0}( 1.3.6.1.4.1.29426.1.10.1 NAME 'mailHomeDirectory' DE
|
||||
SC 'The absolute path to the mail user home directory' EQUALITY caseExactIA
|
||||
5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
|
||||
olcAttributeTypes: {1}( 1.3.6.1.4.1.29426.1.10.2 NAME 'mailAlias' DESC 'RFC8
|
||||
22 Mailbox - mail alias' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5Su
|
||||
bstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
|
||||
olcAttributeTypes: {2}( 1.3.6.1.4.1.29426.1.10.3 NAME 'mailUidNumber' DESC '
|
||||
UID required to access the mailbox' EQUALITY integerMatch SYNTAX 1.3.6.1.4.
|
||||
1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {3}( 1.3.6.1.4.1.29426.1.10.4 NAME 'mailGidNumber' DESC '
|
||||
GID required to access the mailbox' EQUALITY integerMatch SYNTAX 1.3.6.1.4.
|
||||
1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 1.3.6.1.4.1.29426.1.10.5 NAME 'mailEnabled' DESC 'TR
|
||||
UE to enable, FALSE to disable account' EQUALITY booleanMatch SYNTAX 1.3.6.
|
||||
1.4.1.1466.115.121.1.7 SINGLE-VALUE )
|
||||
olcAttributeTypes: {5}( 1.3.6.1.4.1.29426.1.10.6 NAME 'mailGroupMember' DESC
|
||||
'Name of a mail distribution list' EQUALITY caseExactIA5Match SYNTAX 1.3.6
|
||||
.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {6}( 1.3.6.1.4.1.29426.1.10.7 NAME 'mailQuota' DESC 'Mail
|
||||
quota limit in kilobytes' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.14
|
||||
66.115.121.1.26 )
|
||||
olcAttributeTypes: {7}( 1.3.6.1.4.1.29426.1.10.8 NAME 'mailStorageDirectory'
|
||||
DESC 'The absolute path to the mail users mailbox' EQUALITY caseExactIA5Ma
|
||||
tch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
|
||||
olcAttributeTypes: {8}( 1.3.6.1.4.1.29426.1.10.9 NAME 'mailSieveRuleSource'
|
||||
DESC 'Sun ONE Messaging Server defined attribute' SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.26 X-ORIGIN 'Sun ONE Messaging Server' )
|
||||
olcAttributeTypes: {9}( 1.3.6.1.4.1.29426.1.10.10 NAME 'mailForwardingAddres
|
||||
s' DESC 'Address(es) to forward all incoming messages to.' EQUALITY caseIgn
|
||||
oreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{320} )
|
||||
olcObjectClasses: {0}( 1.3.6.1.4.1.29426.1.2.2.1 NAME 'PostfixBookMailAccoun
|
||||
t' DESC 'Mail account used in Postfix Book' SUP top AUXILIARY MUST mail MAY
|
||||
( mailHomeDirectory $ mailAlias $ mailGroupMember $ mailUidNumber $ mailGi
|
||||
dNumber $ mailEnabled $ mailQuota $ mailStorageDirectory $ mailSieveRuleSou
|
||||
rce ) )
|
||||
olcObjectClasses: {1}( 1.3.6.1.4.1.29426.1.2.2.2 NAME 'PostfixBookMailForwar
|
||||
d' DESC 'Mail forward used in Postfix Book' SUP top AUXILIARY MUST ( mail $
|
||||
mailAlias ) MAY mailForwardingAddress )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c658af0-7ddc-103b-8d44-8b35b6446851
|
||||
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.736438Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,235 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 41b81a66
|
||||
dn: cn={8}samba
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {8}samba
|
||||
olcAttributeTypes: {0}( 1.3.6.1.4.1.7165.2.1.24 NAME 'sambaLMPassword' DESC
|
||||
'LanManager Password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.26{32} SINGLE-VALUE )
|
||||
olcAttributeTypes: {1}( 1.3.6.1.4.1.7165.2.1.25 NAME 'sambaNTPassword' DESC
|
||||
'MD4 hash of the unicode password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6
|
||||
.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
|
||||
olcAttributeTypes: {2}( 1.3.6.1.4.1.7165.2.1.26 NAME 'sambaAcctFlags' DESC '
|
||||
Account Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.
|
||||
1.26{16} SINGLE-VALUE )
|
||||
olcAttributeTypes: {3}( 1.3.6.1.4.1.7165.2.1.27 NAME 'sambaPwdLastSet' DESC
|
||||
'Timestamp of the last password update' EQUALITY integerMatch SYNTAX 1.3.6.
|
||||
1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 1.3.6.1.4.1.7165.2.1.28 NAME 'sambaPwdCanChange' DES
|
||||
C 'Timestamp of when the user is allowed to update the password' EQUALITY i
|
||||
ntegerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {5}( 1.3.6.1.4.1.7165.2.1.29 NAME 'sambaPwdMustChange' DE
|
||||
SC 'Timestamp of when the password will expire' EQUALITY integerMatch SYNTA
|
||||
X 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {6}( 1.3.6.1.4.1.7165.2.1.30 NAME 'sambaLogonTime' DESC '
|
||||
Timestamp of last logon' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.
|
||||
121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {7}( 1.3.6.1.4.1.7165.2.1.31 NAME 'sambaLogoffTime' DESC
|
||||
'Timestamp of last logoff' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.11
|
||||
5.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {8}( 1.3.6.1.4.1.7165.2.1.32 NAME 'sambaKickoffTime' DESC
|
||||
'Timestamp of when the user will be logged off automatically' EQUALITY int
|
||||
egerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {9}( 1.3.6.1.4.1.7165.2.1.48 NAME 'sambaBadPasswordCount'
|
||||
DESC 'Bad password attempt count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1
|
||||
.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {10}( 1.3.6.1.4.1.7165.2.1.49 NAME 'sambaBadPasswordTime'
|
||||
DESC 'Time of the last bad password attempt' EQUALITY integerMatch SYNTAX
|
||||
1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {11}( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours' DESC
|
||||
'Logon Hours' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.
|
||||
1.26{42} SINGLE-VALUE )
|
||||
olcAttributeTypes: {12}( 1.3.6.1.4.1.7165.2.1.33 NAME 'sambaHomeDrive' DESC
|
||||
'Driver letter of home directory mapping' EQUALITY caseIgnoreIA5Match SYNTA
|
||||
X 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE )
|
||||
olcAttributeTypes: {13}( 1.3.6.1.4.1.7165.2.1.34 NAME 'sambaLogonScript' DES
|
||||
C 'Logon script path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.
|
||||
121.1.15{255} SINGLE-VALUE )
|
||||
olcAttributeTypes: {14}( 1.3.6.1.4.1.7165.2.1.35 NAME 'sambaProfilePath' DES
|
||||
C 'Roaming profile path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.15{255} SINGLE-VALUE )
|
||||
olcAttributeTypes: {15}( 1.3.6.1.4.1.7165.2.1.36 NAME 'sambaUserWorkstations
|
||||
' DESC 'List of user workstations the user is allowed to logon to' EQUALITY
|
||||
caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
|
||||
olcAttributeTypes: {16}( 1.3.6.1.4.1.7165.2.1.37 NAME 'sambaHomePath' DESC '
|
||||
Home directory UNC path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.15{128} )
|
||||
olcAttributeTypes: {17}( 1.3.6.1.4.1.7165.2.1.38 NAME 'sambaDomainName' DESC
|
||||
'Windows NT domain to which the user belongs' EQUALITY caseIgnoreMatch SYN
|
||||
TAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
|
||||
olcAttributeTypes: {18}( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial' DESC
|
||||
'Base64 encoded user parameter string' EQUALITY caseExactMatch SYNTAX 1.3.
|
||||
6.1.4.1.1466.115.121.1.15{1050} )
|
||||
olcAttributeTypes: {19}( 1.3.6.1.4.1.7165.2.1.54 NAME 'sambaPasswordHistory'
|
||||
DESC 'Concatenated MD5 hashes of the salted NT passwords used on this acco
|
||||
unt' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} )
|
||||
olcAttributeTypes: {20}( 1.3.6.1.4.1.7165.2.1.20 NAME 'sambaSID' DESC 'Secur
|
||||
ity ID' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNT
|
||||
AX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
|
||||
olcAttributeTypes: {21}( 1.3.6.1.4.1.7165.2.1.23 NAME 'sambaPrimaryGroupSID'
|
||||
DESC 'Primary Group Security ID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.
|
||||
1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
|
||||
olcAttributeTypes: {22}( 1.3.6.1.4.1.7165.2.1.51 NAME 'sambaSIDList' DESC 'S
|
||||
ecurity ID List' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.12
|
||||
1.1.26{64} )
|
||||
olcAttributeTypes: {23}( 1.3.6.1.4.1.7165.2.1.19 NAME 'sambaGroupType' DESC
|
||||
'NT Group Type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
|
||||
SINGLE-VALUE )
|
||||
olcAttributeTypes: {24}( 1.3.6.1.4.1.7165.2.1.21 NAME 'sambaNextUserRid' DES
|
||||
C 'Next NT rid to give our for users' EQUALITY integerMatch SYNTAX 1.3.6.1.
|
||||
4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {25}( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid' DE
|
||||
SC 'Next NT rid to give out for groups' EQUALITY integerMatch SYNTAX 1.3.6.
|
||||
1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {26}( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid' DESC 'N
|
||||
ext NT rid to give out for anything' EQUALITY integerMatch SYNTAX 1.3.6.1.4
|
||||
.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {27}( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBa
|
||||
se' DESC 'Base at which the samba RID generation algorithm should operate'
|
||||
EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {28}( 1.3.6.1.4.1.7165.2.1.41 NAME 'sambaShareName' DESC
|
||||
'Share Name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
olcAttributeTypes: {29}( 1.3.6.1.4.1.7165.2.1.42 NAME 'sambaOptionName' DESC
|
||||
'Option Name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SY
|
||||
NTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {30}( 1.3.6.1.4.1.7165.2.1.43 NAME 'sambaBoolOption' DESC
|
||||
'A boolean option' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1
|
||||
.7 SINGLE-VALUE )
|
||||
olcAttributeTypes: {31}( 1.3.6.1.4.1.7165.2.1.44 NAME 'sambaIntegerOption' D
|
||||
ESC 'An integer option' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.1
|
||||
21.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {32}( 1.3.6.1.4.1.7165.2.1.45 NAME 'sambaStringOption' DE
|
||||
SC 'A string option' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115
|
||||
.121.1.26 SINGLE-VALUE )
|
||||
olcAttributeTypes: {33}( 1.3.6.1.4.1.7165.2.1.46 NAME 'sambaStringListOption
|
||||
' DESC 'A string list option' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1
|
||||
466.115.121.1.15 )
|
||||
olcAttributeTypes: {34}( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags' DESC
|
||||
'Trust Password Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466
|
||||
.115.121.1.26 )
|
||||
olcAttributeTypes: {35}( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength' DE
|
||||
SC 'Minimal password length (default: 5)' EQUALITY integerMatch SYNTAX 1.3.
|
||||
6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {36}( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength
|
||||
' DESC 'Length of Password History Entries (default: 0 => off)' EQUALITY in
|
||||
tegerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {37}( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd' D
|
||||
ESC 'Force Users to logon for password change (default: 0 => off, 2 => on)'
|
||||
EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {38}( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge' DESC
|
||||
'Maximum password age, in seconds (default: -1 => never expire passwords)'
|
||||
EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {39}( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge' DESC
|
||||
'Minimum password age, in seconds (default: 0 => allow immediate password c
|
||||
hange)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-V
|
||||
ALUE )
|
||||
olcAttributeTypes: {40}( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration'
|
||||
DESC 'Lockout duration in minutes (default: 30, -1 => forever)' EQUALITY i
|
||||
ntegerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {41}( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservati
|
||||
onWindow' DESC 'Reset time after lockout in minutes (default: 30)' EQUALITY
|
||||
integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {42}( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold
|
||||
' DESC 'Lockout users after bad logon attempts (default: 0 => off)' EQUALIT
|
||||
Y integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {43}( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff' DES
|
||||
C 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)' EQUA
|
||||
LITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {44}( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwd
|
||||
Change' DESC 'Allow Machine Password changes (default: 0 => off)' EQUALITY
|
||||
integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {45}( 1.3.6.1.4.1.7165.2.1.68 NAME 'sambaClearTextPasswor
|
||||
d' DESC 'Clear text password (used for trusted domain passwords)' EQUALITY
|
||||
octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
|
||||
olcAttributeTypes: {46}( 1.3.6.1.4.1.7165.2.1.69 NAME 'sambaPreviousClearTex
|
||||
tPassword' DESC 'Previous clear text password (used for trusted domain pass
|
||||
words)' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
|
||||
olcAttributeTypes: {47}( 1.3.6.1.4.1.7165.2.1.70 NAME 'sambaTrustType' DESC
|
||||
'Type of trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
|
||||
SINGLE-VALUE )
|
||||
olcAttributeTypes: {48}( 1.3.6.1.4.1.7165.2.1.71 NAME 'sambaTrustAttributes'
|
||||
DESC 'Trust attributes for a trusted domain' EQUALITY integerMatch SYNTAX
|
||||
1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {49}( 1.3.6.1.4.1.7165.2.1.72 NAME 'sambaTrustDirection'
|
||||
DESC 'Direction of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {50}( 1.3.6.1.4.1.7165.2.1.73 NAME 'sambaTrustPartner' DE
|
||||
SC 'Fully qualified name of the domain with which a trust exists' EQUALITY
|
||||
caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
|
||||
olcAttributeTypes: {51}( 1.3.6.1.4.1.7165.2.1.74 NAME 'sambaFlatName' DESC '
|
||||
NetBIOS name of a domain' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.
|
||||
115.121.1.15{128} )
|
||||
olcAttributeTypes: {52}( 1.3.6.1.4.1.7165.2.1.75 NAME 'sambaTrustAuthOutgoin
|
||||
g' DESC 'Authentication information for the outgoing portion of a trust' EQ
|
||||
UALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
|
||||
olcAttributeTypes: {53}( 1.3.6.1.4.1.7165.2.1.76 NAME 'sambaTrustAuthIncomin
|
||||
g' DESC 'Authentication information for the incoming portion of a trust' EQ
|
||||
UALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
|
||||
olcAttributeTypes: {54}( 1.3.6.1.4.1.7165.2.1.77 NAME 'sambaSecurityIdentifi
|
||||
er' DESC 'SID of a trusted domain' EQUALITY caseIgnoreIA5Match SUBSTR caseE
|
||||
xactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALU
|
||||
E )
|
||||
olcAttributeTypes: {55}( 1.3.6.1.4.1.7165.2.1.78 NAME 'sambaTrustForestTrust
|
||||
Info' DESC 'Forest trust information for a trusted domain object' EQUALITY
|
||||
caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
|
||||
olcAttributeTypes: {56}( 1.3.6.1.4.1.7165.2.1.79 NAME 'sambaTrustPosixOffset
|
||||
' DESC 'POSIX offset of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1
|
||||
466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {57}( 1.3.6.1.4.1.7165.2.1.80 NAME 'sambaSupportedEncrypt
|
||||
ionTypes' DESC 'Supported encryption types of a trust' EQUALITY integerMatc
|
||||
h SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcObjectClasses: {0}( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' DESC 'S
|
||||
amba 3.0 Auxilary SAM Account' SUP top AUXILIARY MUST ( uid $ sambaSID ) MA
|
||||
Y ( cn $ sambaLMPassword $ sambaNTPassword $ sambaPwdLastSet $ sambaLogonTi
|
||||
me $ sambaLogoffTime $ sambaKickoffTime $ sambaPwdCanChange $ sambaPwdMustC
|
||||
hange $ sambaAcctFlags $ displayName $ sambaHomePath $ sambaHomeDrive $ sam
|
||||
baLogonScript $ sambaProfilePath $ description $ sambaUserWorkstations $ sa
|
||||
mbaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial $ sambaBadPasswordCo
|
||||
unt $ sambaBadPasswordTime $ sambaPasswordHistory $ sambaLogonHours ) )
|
||||
olcObjectClasses: {1}( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' DESC
|
||||
'Samba Group Mapping' SUP top AUXILIARY MUST ( gidNumber $ sambaSID $ samba
|
||||
GroupType ) MAY ( displayName $ description $ sambaSIDList ) )
|
||||
olcObjectClasses: {2}( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' DES
|
||||
C 'Samba Trust Password' SUP top STRUCTURAL MUST ( sambaDomainName $ sambaN
|
||||
TPassword $ sambaTrustFlags ) MAY ( sambaSID $ sambaPwdLastSet ) )
|
||||
olcObjectClasses: {3}( 1.3.6.1.4.1.7165.2.2.15 NAME 'sambaTrustedDomainPassw
|
||||
ord' DESC 'Samba Trusted Domain Password' SUP top STRUCTURAL MUST ( sambaDo
|
||||
mainName $ sambaSID $ sambaClearTextPassword $ sambaPwdLastSet ) MAY sambaP
|
||||
reviousClearTextPassword )
|
||||
olcObjectClasses: {4}( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' DESC 'Samba
|
||||
Domain Information' SUP top STRUCTURAL MUST ( sambaDomainName $ sambaSID )
|
||||
MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithm
|
||||
icRidBase $ sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd
|
||||
$ sambaMaxPwdAge $ sambaMinPwdAge $ sambaLockoutDuration $ sambaLockoutObse
|
||||
rvationWindow $ sambaLockoutThreshold $ sambaForceLogoff $ sambaRefuseMachi
|
||||
nePwdChange ) )
|
||||
olcObjectClasses: {5}( 1.3.6.1.4.1.7165.2.2.7 NAME 'sambaUnixIdPool' DESC 'P
|
||||
ool for allocating UNIX uids/gids' SUP top AUXILIARY MUST ( uidNumber $ gid
|
||||
Number ) )
|
||||
olcObjectClasses: {6}( 1.3.6.1.4.1.7165.2.2.8 NAME 'sambaIdmapEntry' DESC 'M
|
||||
apping from a SID to an ID' SUP top AUXILIARY MUST sambaSID MAY ( uidNumber
|
||||
$ gidNumber ) )
|
||||
olcObjectClasses: {7}( 1.3.6.1.4.1.7165.2.2.9 NAME 'sambaSidEntry' DESC 'Str
|
||||
uctural Class for a SID' SUP top STRUCTURAL MUST sambaSID )
|
||||
olcObjectClasses: {8}( 1.3.6.1.4.1.7165.2.2.10 NAME 'sambaConfig' DESC 'Samb
|
||||
a Configuration Section' SUP top AUXILIARY MAY description )
|
||||
olcObjectClasses: {9}( 1.3.6.1.4.1.7165.2.2.11 NAME 'sambaShare' DESC 'Samba
|
||||
Share Section' SUP top STRUCTURAL MUST sambaShareName MAY description )
|
||||
olcObjectClasses: {10}( 1.3.6.1.4.1.7165.2.2.12 NAME 'sambaConfigOption' DES
|
||||
C 'Samba Configuration Option' SUP top STRUCTURAL MUST sambaOptionName MAY
|
||||
( sambaBoolOption $ sambaIntegerOption $ sambaStringOption $ sambaStringLis
|
||||
toption $ description ) )
|
||||
olcObjectClasses: {11}( 1.3.6.1.4.1.7165.2.2.16 NAME 'sambaTrustedDomain' DE
|
||||
SC 'Samba Trusted Domain Object' SUP top STRUCTURAL MUST cn MAY ( sambaTrus
|
||||
tType $ sambaTrustAttributes $ sambaTrustDirection $ sambaTrustPartner $ sa
|
||||
mbaFlatName $ sambaTrustAuthOutgoing $ sambaTrustAuthIncoming $ sambaSecuri
|
||||
tyIdentifier $ sambaTrustForestTrustInfo $ sambaTrustPosixOffset $ sambaSup
|
||||
portedEncryptionTypes ) )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c692e8a-7ddc-103b-8d45-8b35b6446851
|
||||
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.760287Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,18 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 6d98bb57
|
||||
dn: olcDatabase={-1}frontend
|
||||
objectClass: olcDatabaseConfig
|
||||
objectClass: olcFrontendConfig
|
||||
olcDatabase: {-1}frontend
|
||||
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=extern
|
||||
al,cn=auth manage by * break
|
||||
olcAccess: {1}to dn.exact="" by * read
|
||||
olcAccess: {2}to dn.base="cn=Subschema" by * read
|
||||
olcSizeLimit: 500
|
||||
structuralObjectClass: olcDatabaseConfig
|
||||
entryUUID: 5c22f244-7ddc-103b-9ebc-c740e015b81b
|
||||
creatorsName: cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.299952Z#000000#000#000000
|
||||
modifiersName: cn=config
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,16 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 fec87138
|
||||
dn: olcDatabase={0}config
|
||||
objectClass: olcDatabaseConfig
|
||||
olcDatabase: {0}config
|
||||
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=extern
|
||||
al,cn=auth manage by * break
|
||||
olcRootDN: cn=admin,cn=config
|
||||
structuralObjectClass: olcDatabaseConfig
|
||||
entryUUID: 5c248d0c-7ddc-103b-9ebd-c740e015b81b
|
||||
creatorsName: cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
olcRootPW:: e1NTSEF9eU16WmFPaHpXM0xWOFB0UktoVWJRcm1jRTJld2JMdGY=
|
||||
entryCSN: 20210811010255.817110Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210811010255Z
|
||||
@@ -0,0 +1,31 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 6039bcca
|
||||
dn: olcDatabase={1}mdb
|
||||
objectClass: olcDatabaseConfig
|
||||
objectClass: olcMdbConfig
|
||||
olcDatabase: {1}mdb
|
||||
olcDbDirectory: /var/lib/ldap
|
||||
olcSuffix: dc=glauth,dc=com
|
||||
olcLastMod: TRUE
|
||||
olcRootDN: cn=admin,dc=glauth,dc=com
|
||||
olcDbCheckpoint: 512 30
|
||||
olcDbMaxSize: 1073741824
|
||||
structuralObjectClass: olcMdbConfig
|
||||
entryUUID: 5c2cdd40-7ddc-103b-9ec4-c740e015b81b
|
||||
creatorsName: cn=admin,cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
olcDbIndex: uid eq
|
||||
olcDbIndex: mail eq
|
||||
olcDbIndex: memberOf eq
|
||||
olcDbIndex: entryCSN eq
|
||||
olcDbIndex: entryUUID eq
|
||||
olcDbIndex: objectClass eq
|
||||
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by dn="cn
|
||||
=serviceuser,cn=svcaccts,ou=users,dc=glauth,dc=com" write by anonymous auth
|
||||
by * none
|
||||
olcAccess: {1}to * by self write by dn="cn=serviceuser,cn=svcaccts,ou=users,
|
||||
dc=glauth,dc=com" write by users read by * none
|
||||
olcRootPW:: e1NTSEF9ZitwMnc4SjdQN0QxRlJCZUU5Q2Z6YUJFN1NRQm54WEY=
|
||||
entryCSN: 20210811010255.822508Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210811010255Z
|
||||
@@ -0,0 +1,18 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 5273ae52
|
||||
dn: olcOverlay={0}memberof
|
||||
objectClass: olcOverlayConfig
|
||||
objectClass: olcMemberOf
|
||||
olcOverlay: {0}memberof
|
||||
olcMemberOfDangling: ignore
|
||||
olcMemberOfRefInt: TRUE
|
||||
olcMemberOfGroupOC: groupOfUniqueNames
|
||||
olcMemberOfMemberAD: uniqueMember
|
||||
olcMemberOfMemberOfAD: memberOf
|
||||
structuralObjectClass: olcMemberOf
|
||||
entryUUID: 5c74c556-7ddc-103b-8d46-8b35b6446851
|
||||
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.836237Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,18 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 a7700674
|
||||
dn: olcOverlay={1}refint
|
||||
objectClass: olcOverlayConfig
|
||||
objectClass: olcRefintConfig
|
||||
olcOverlay: {1}refint
|
||||
olcRefintAttribute: owner
|
||||
olcRefintAttribute: manager
|
||||
olcRefintAttribute: uniqueMember
|
||||
olcRefintAttribute: member
|
||||
olcRefintAttribute: memberOf
|
||||
structuralObjectClass: olcRefintConfig
|
||||
entryUUID: 5c78d98e-7ddc-103b-8d47-8b35b6446851
|
||||
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.862968Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,4 @@
|
||||
export PREVIOUS_LDAP_TLS_CA_CRT_PATH=/container/service/slapd/assets/certs/ca.crt
|
||||
export PREVIOUS_LDAP_TLS_CRT_PATH=/container/service/slapd/assets/certs/ldap.crt
|
||||
export PREVIOUS_LDAP_TLS_KEY_PATH=/container/service/slapd/assets/certs/ldap.key
|
||||
export PREVIOUS_LDAP_TLS_DH_PARAM_PATH=/container/service/slapd/assets/certs/dhparam.pem
|
||||
Binary file not shown.
Binary file not shown.
@@ -12,7 +12,8 @@ type Backend struct {
|
||||
UseGraphAPI bool // For ownCloud backend only
|
||||
Plugin string // Path to plugin library, for plugin backend only
|
||||
PluginHandler string // Name of plugin's main handler function
|
||||
Database string // For MySQL backend only TODO REname to match plugin
|
||||
Database string // For Database backends only
|
||||
AnonymousDSE bool // For Config and Database backends only
|
||||
}
|
||||
type Helper struct {
|
||||
Enabled bool
|
||||
|
||||
+119
-354
@@ -1,14 +1,8 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -18,17 +12,14 @@ import (
|
||||
"github.com/glauth/glauth/pkg/stats"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nmcclain/ldap"
|
||||
"github.com/pquerna/otp/totp"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
var configattributematcher = regexp.MustCompile(`(?i)\((?P<attribute>[a-zA-Z0-9]+)\s*=\s*(?P<value>.*)\)`)
|
||||
|
||||
type configHandler struct {
|
||||
backend config.Backend
|
||||
log logr.Logger
|
||||
cfg *config.Config
|
||||
yubikeyAuth *yubigo.YubiAuth
|
||||
ldohelper LDAPOpsHelper
|
||||
attmatcher *regexp.Regexp
|
||||
}
|
||||
|
||||
@@ -41,358 +32,33 @@ func NewConfigHandler(opts ...Option) Handler {
|
||||
log: options.Logger,
|
||||
cfg: options.Config, // TODO only used to access Users and Groups, move that to dedicated options
|
||||
yubikeyAuth: options.YubiAuth,
|
||||
ldohelper: options.LDAPHelper,
|
||||
attmatcher: configattributematcher,
|
||||
}
|
||||
return handler
|
||||
}
|
||||
|
||||
func (h configHandler) GetBackend() config.Backend {
|
||||
return h.backend
|
||||
}
|
||||
func (h configHandler) GetLog() logr.Logger {
|
||||
return h.log
|
||||
}
|
||||
func (h configHandler) GetCfg() *config.Config {
|
||||
return h.cfg
|
||||
}
|
||||
func (h configHandler) GetYubikeyAuth() *yubigo.YubiAuth {
|
||||
return h.yubikeyAuth
|
||||
}
|
||||
|
||||
// Bind implements a bind request against the config file
|
||||
func (h configHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultCode ldap.LDAPResultCode, err error) {
|
||||
bindDN = strings.ToLower(bindDN)
|
||||
baseDN := strings.ToLower("," + h.backend.BaseDN)
|
||||
|
||||
h.log.V(6).Info("Bind request", "binddn", bindDN, "basedn", h.backend.BaseDN, "src", conn.RemoteAddr())
|
||||
|
||||
stats.Frontend.Add("bind_reqs", 1)
|
||||
|
||||
// parse the bindDN - ensure that the bindDN ends with the BaseDN
|
||||
if !strings.HasSuffix(bindDN, baseDN) {
|
||||
h.log.V(2).Info("BindDN not part of our BaseDN", "binddn", bindDN, "basedn", h.backend.BaseDN)
|
||||
// h.log.Warning(fmt.Sprintf("Bind Error: BindDN %s not our BaseDN %s", bindDN, baseDN))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
parts := strings.Split(strings.TrimSuffix(bindDN, baseDN), ",")
|
||||
groupName := ""
|
||||
userName := ""
|
||||
if len(parts) == 1 {
|
||||
userName = strings.TrimPrefix(parts[0], h.backend.NameFormat+"=")
|
||||
} else if len(parts) == 2 {
|
||||
userName = strings.TrimPrefix(parts[0], h.backend.NameFormat+"=")
|
||||
groupName = strings.TrimPrefix(parts[1], h.backend.GroupFormat+"=")
|
||||
} else {
|
||||
h.log.V(2).Info("BindDN should have only one or two parts", "binddn", bindDN, "numparts", len(parts))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
|
||||
// find the user
|
||||
user := config.User{}
|
||||
found := false
|
||||
for _, u := range h.cfg.Users {
|
||||
if strings.EqualFold(u.Name, userName) {
|
||||
found = true
|
||||
user = u
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
h.log.V(2).Info("User not found", "username", userName)
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
// find the group
|
||||
group := config.Group{}
|
||||
found = false
|
||||
for _, g := range h.cfg.Groups {
|
||||
if strings.EqualFold(g.Name, groupName) {
|
||||
found = true
|
||||
group = g
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
h.log.V(2).Info("Group not found", "groupname", groupName)
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
// validate group membership
|
||||
if user.PrimaryGroup != group.GIDNumber {
|
||||
h.log.V(2).Info("primary group mismatch", "username", userName, "primarygroup", user.PrimaryGroup, "groupid", group.GIDNumber)
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
|
||||
validotp := false
|
||||
|
||||
if len(user.Yubikey) == 0 && len(user.OTPSecret) == 0 {
|
||||
validotp = true
|
||||
}
|
||||
|
||||
if len(user.Yubikey) > 0 && h.yubikeyAuth != nil {
|
||||
if len(bindSimplePw) > 44 {
|
||||
otp := bindSimplePw[len(bindSimplePw)-44:]
|
||||
yubikeyid := otp[0:12]
|
||||
bindSimplePw = bindSimplePw[:len(bindSimplePw)-44]
|
||||
|
||||
if user.Yubikey == yubikeyid {
|
||||
_, ok, _ := h.yubikeyAuth.Verify(otp)
|
||||
|
||||
if ok {
|
||||
validotp = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store the full bind password provided before possibly modifying
|
||||
// in the otp check
|
||||
untouchedBindSimplePw := bindSimplePw
|
||||
|
||||
// Test OTP if exists
|
||||
if len(user.OTPSecret) > 0 && !validotp {
|
||||
if len(bindSimplePw) > 6 {
|
||||
otp := bindSimplePw[len(bindSimplePw)-6:]
|
||||
bindSimplePw = bindSimplePw[:len(bindSimplePw)-6]
|
||||
|
||||
validotp = totp.Validate(otp, user.OTPSecret)
|
||||
}
|
||||
}
|
||||
|
||||
// finally, validate user's pw
|
||||
|
||||
// check app passwords first
|
||||
if user.PassAppBcrypt != nil {
|
||||
for index, appPw := range user.PassAppBcrypt {
|
||||
decoded, err := hex.DecodeString(appPw)
|
||||
if err != nil {
|
||||
h.log.V(6).Info("invalid app credentials", "incorrect stored hash", "(omitted)")
|
||||
} else {
|
||||
if bcrypt.CompareHashAndPassword(decoded, []byte(untouchedBindSimplePw)) == nil {
|
||||
stats.Frontend.Add("bind_successes", 1)
|
||||
h.log.V(6).Info("Bind success using app pw", "index", index, "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if user.PassAppSHA256 != nil {
|
||||
hashFull := sha256.New()
|
||||
hashFull.Write([]byte(untouchedBindSimplePw))
|
||||
for index, appPw := range user.PassAppSHA256 {
|
||||
if appPw != hex.EncodeToString(hashFull.Sum(nil)) {
|
||||
h.log.V(6).Info("Attempt to bind app pw failed", "index", index, "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
} else {
|
||||
stats.Frontend.Add("bind_successes", 1)
|
||||
h.log.V(6).Info("Bind success using app pw", "index", index, "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then ensure the OTP is valid before checking
|
||||
if !validotp {
|
||||
h.log.V(2).Info("invalid OTP token", "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
|
||||
// Now, check the pasword hash
|
||||
if user.PassBcrypt != "" {
|
||||
decoded, err := hex.DecodeString(user.PassBcrypt)
|
||||
if err != nil {
|
||||
h.log.V(2).Info("invalid credentials", "incorrect stored hash", "(omitted)")
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
if bcrypt.CompareHashAndPassword(decoded, []byte(bindSimplePw)) != nil {
|
||||
h.log.V(2).Info("invalid credentials", "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
}
|
||||
if user.PassSHA256 != "" {
|
||||
hash := sha256.New()
|
||||
hash.Write([]byte(bindSimplePw))
|
||||
if user.PassSHA256 != hex.EncodeToString(hash.Sum(nil)) {
|
||||
h.log.V(2).Info("invalid credentials", "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
}
|
||||
|
||||
stats.Frontend.Add("bind_successes", 1)
|
||||
h.log.V(6).Info("Bind success", "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
return h.ldohelper.Bind(h, bindDN, bindSimplePw, conn)
|
||||
}
|
||||
|
||||
// Search implements a search request against the config file
|
||||
func (h configHandler) Search(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
|
||||
bindDN = strings.ToLower(bindDN)
|
||||
baseDN := strings.ToLower(h.backend.BaseDN)
|
||||
delimitedBaseDN := "," + baseDN
|
||||
searchBaseDN := strings.ToLower(searchReq.BaseDN)
|
||||
h.log.V(6).Info("Search request", "binddn", bindDN, "basedn", baseDN, "searchbasedn", searchBaseDN, "src", conn.RemoteAddr(), "scope", searchReq.Scope, "filter", searchReq.Filter)
|
||||
stats.Frontend.Add("search_reqs", 1)
|
||||
|
||||
// validate the user is authenticated and has appropriate access
|
||||
if len(bindDN) < 1 {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: Anonymous BindDN not allowed %s", bindDN)
|
||||
}
|
||||
|
||||
// special case: querying the root DSE
|
||||
if searchReq.Scope == 0 && (searchBaseDN == "" || searchBaseDN == baseDN) {
|
||||
h.log.V(6).Info("Search request", "special case", "root DSE")
|
||||
entries := []*ldap.Entry{}
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
// unfortunately, objectClass is not to be included so we will respect that
|
||||
// attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"*"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedSASLMechanisms", Values: []string{}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedLDAPVersion", Values: []string{"3"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedControl", Values: []string{}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedCapabilities", Values: []string{}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "subschemaSubentry", Values: []string{"cn=schema"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "serverName", Values: []string{"unknown"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "namingContexts", Values: []string{baseDN}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "defaultNamingContext", Values: []string{baseDN}})
|
||||
// ah, but you see, this is not enough because if your query is for, say 'objectClass', then our LDAP
|
||||
// library will weed out this entry since it does *not* contain an objectclass attribute
|
||||
attbits := h.attmatcher.FindStringSubmatch(searchReq.Filter)
|
||||
if len(attbits) == 3 {
|
||||
foundattname := false
|
||||
for _, attr := range attrs {
|
||||
if strings.ToLower(attr.Name) == strings.ToLower(attbits[1]) {
|
||||
foundattname = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// the ugly hack: we are going to pretend that the requested attribute is in there
|
||||
if !foundattname {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: attbits[1], Values: []string{attbits[2]}})
|
||||
}
|
||||
}
|
||||
entries = append(entries, &ldap.Entry{DN: searchBaseDN, Attributes: attrs})
|
||||
stats.Frontend.Add("search_successes", 1)
|
||||
h.log.V(6).Info("AP: Root Search OK", "filter", searchReq.Filter)
|
||||
return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess}, nil
|
||||
}
|
||||
|
||||
if searchBaseDN == "cn=schema" {
|
||||
h.log.V(6).Info("Search request", "special case", "schema discovery")
|
||||
entries := []*ldap.Entry{}
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "cn", Values: []string{"schema"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "hasSubordinates", Values: []string{"false"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "modifiersName", Values: []string{"cn=Directory Manager"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "modifyTimeStamp", Values: []string{"Mar 8, 2021, 12:46:29 PM PST (20210308204629Z)"}})
|
||||
// Iterate through schema attributes provided in schema/ directory
|
||||
filenames, _ := ioutil.ReadDir("schema")
|
||||
for _, filename := range filenames {
|
||||
file, err := os.Open(filepath.Join("schema", filename.Name()))
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Schema Error: attribute %s cannot be read", filename)
|
||||
}
|
||||
defer file.Close()
|
||||
values := []string{}
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
values = append(values, line)
|
||||
}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: filename.Name(), Values: values})
|
||||
}
|
||||
// This hack again. One more time, and it gets its own function...
|
||||
attbits := h.attmatcher.FindStringSubmatch(searchReq.Filter)
|
||||
if len(attbits) == 3 {
|
||||
foundattname := false
|
||||
for _, attr := range attrs {
|
||||
if strings.ToLower(attr.Name) == strings.ToLower(attbits[1]) {
|
||||
foundattname = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundattname {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: attbits[1], Values: []string{attbits[2]}})
|
||||
}
|
||||
}
|
||||
entries = append(entries, &ldap.Entry{DN: searchBaseDN, Attributes: attrs})
|
||||
stats.Frontend.Add("search_successes", 1)
|
||||
h.log.V(6).Info("AP: Schema Discovery OK", "filter", searchReq.Filter)
|
||||
return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess}, nil
|
||||
}
|
||||
|
||||
// TODO SHould I move this before our special cases handling (above?)
|
||||
if !strings.HasSuffix(bindDN, delimitedBaseDN) {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: BindDN %s not in our BaseDN %s", bindDN, h.backend.BaseDN)
|
||||
}
|
||||
if !strings.HasSuffix(searchBaseDN, h.backend.BaseDN) {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: search BaseDN %s is not in our BaseDN %s", searchBaseDN, h.backend.BaseDN)
|
||||
}
|
||||
// return all users in the config file - the LDAP library will filter results for us
|
||||
entries := []*ldap.Entry{}
|
||||
filterEntity, err := ldap.GetFilterObjectClass(searchReq.Filter)
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: error parsing filter: %s", searchReq.Filter)
|
||||
}
|
||||
switch filterEntity {
|
||||
default:
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: unhandled filter type: %s [%s]", filterEntity, searchReq.Filter)
|
||||
case "posixgroup":
|
||||
for _, g := range h.cfg.Groups {
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "cn", Values: []string{g.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{g.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s", g.Name)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "gidNumber", Values: []string{fmt.Sprintf("%d", g.GIDNumber)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"posixGroup"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uniqueMember", Values: h.getGroupMembers(g.GIDNumber)})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberUid", Values: h.getGroupMemberIDs(g.GIDNumber)})
|
||||
dn := fmt.Sprintf("cn=%s,%s=groups,%s", g.Name, h.backend.GroupFormat, h.backend.BaseDN)
|
||||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||
}
|
||||
case "posixaccount", "shadowaccount", "":
|
||||
for _, u := range h.cfg.Users {
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "cn", Values: []string{u.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{u.Name}})
|
||||
|
||||
if len(u.GivenName) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "givenName", Values: []string{u.GivenName}})
|
||||
}
|
||||
|
||||
if len(u.SN) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "sn", Values: []string{u.SN}})
|
||||
}
|
||||
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "ou", Values: []string{h.getGroupName(u.PrimaryGroup)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uidNumber", Values: []string{fmt.Sprintf("%d", u.UIDNumber)}})
|
||||
|
||||
if u.Disabled {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "accountStatus", Values: []string{"inactive"}})
|
||||
} else {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "accountStatus", Values: []string{"active"}})
|
||||
}
|
||||
|
||||
if len(u.Mail) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "mail", Values: []string{u.Mail}})
|
||||
}
|
||||
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"posixAccount", "shadowAccount"}})
|
||||
|
||||
if len(u.LoginShell) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "loginShell", Values: []string{u.LoginShell}})
|
||||
} else {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "loginShell", Values: []string{"/bin/bash"}})
|
||||
}
|
||||
|
||||
if len(u.Homedir) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "homeDirectory", Values: []string{u.Homedir}})
|
||||
} else {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "homeDirectory", Values: []string{"/home/" + u.Name}})
|
||||
}
|
||||
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s", u.Name)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "gecos", Values: []string{fmt.Sprintf("%s", u.Name)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "gidNumber", Values: []string{fmt.Sprintf("%d", u.PrimaryGroup)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberOf", Values: h.getGroupDNs(append(u.OtherGroups, u.PrimaryGroup))})
|
||||
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowExpire", Values: []string{"-1"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowFlag", Values: []string{"134538308"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowInactive", Values: []string{"-1"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowLastChange", Values: []string{"11000"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowMax", Values: []string{"99999"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowMin", Values: []string{"-1"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowWarning", Values: []string{"7"}})
|
||||
|
||||
if len(u.SSHKeys) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.SSHKeyAttr, Values: u.SSHKeys})
|
||||
}
|
||||
dn := fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), h.backend.BaseDN)
|
||||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||
}
|
||||
}
|
||||
stats.Frontend.Add("search_successes", 1)
|
||||
h.log.V(6).Info("AP: Search OK", "filter", searchReq.Filter)
|
||||
return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess}, nil
|
||||
return h.ldohelper.Search(h, bindDN, searchReq, conn)
|
||||
}
|
||||
|
||||
// Add is not supported for a static config file
|
||||
@@ -422,6 +88,105 @@ func (h configHandler) FindUser(userName string) (f bool, u config.User, err err
|
||||
return found, user, nil
|
||||
}
|
||||
|
||||
func (h configHandler) FindGroup(groupName string) (f bool, g config.Group, err error) {
|
||||
// TODO Does g get erased, and above does u get erased?
|
||||
// TODO and what about f?
|
||||
group := config.Group{}
|
||||
found := false
|
||||
for _, g := range h.cfg.Groups {
|
||||
if strings.EqualFold(g.Name, groupName) {
|
||||
found = true
|
||||
group = g
|
||||
}
|
||||
}
|
||||
return found, group, nil
|
||||
}
|
||||
|
||||
func (h configHandler) FindPosixAccounts() (entrylist []*ldap.Entry, err error) {
|
||||
entries := []*ldap.Entry{}
|
||||
|
||||
for _, u := range h.cfg.Users {
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "cn", Values: []string{u.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{u.Name}})
|
||||
|
||||
if len(u.GivenName) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "givenName", Values: []string{u.GivenName}})
|
||||
}
|
||||
|
||||
if len(u.SN) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "sn", Values: []string{u.SN}})
|
||||
}
|
||||
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "ou", Values: []string{h.getGroupName(u.PrimaryGroup)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uidNumber", Values: []string{fmt.Sprintf("%d", u.UIDNumber)}})
|
||||
|
||||
if u.Disabled {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "accountStatus", Values: []string{"inactive"}})
|
||||
} else {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "accountStatus", Values: []string{"active"}})
|
||||
}
|
||||
|
||||
if len(u.Mail) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "mail", Values: []string{u.Mail}})
|
||||
}
|
||||
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"posixAccount", "shadowAccount"}})
|
||||
|
||||
if len(u.LoginShell) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "loginShell", Values: []string{u.LoginShell}})
|
||||
} else {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "loginShell", Values: []string{"/bin/bash"}})
|
||||
}
|
||||
|
||||
if len(u.Homedir) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "homeDirectory", Values: []string{u.Homedir}})
|
||||
} else {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "homeDirectory", Values: []string{"/home/" + u.Name}})
|
||||
}
|
||||
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s", u.Name)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "gecos", Values: []string{fmt.Sprintf("%s", u.Name)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "gidNumber", Values: []string{fmt.Sprintf("%d", u.PrimaryGroup)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberOf", Values: h.getGroupDNs(append(u.OtherGroups, u.PrimaryGroup))})
|
||||
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowExpire", Values: []string{"-1"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowFlag", Values: []string{"134538308"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowInactive", Values: []string{"-1"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowLastChange", Values: []string{"11000"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowMax", Values: []string{"99999"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowMin", Values: []string{"-1"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowWarning", Values: []string{"7"}})
|
||||
|
||||
if len(u.SSHKeys) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.SSHKeyAttr, Values: u.SSHKeys})
|
||||
}
|
||||
dn := fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), h.backend.BaseDN)
|
||||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||
}
|
||||
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
func (h configHandler) FindPosixGroups() (entrylist []*ldap.Entry, err error) {
|
||||
entries := []*ldap.Entry{}
|
||||
|
||||
for _, g := range h.cfg.Groups {
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "cn", Values: []string{g.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{g.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s", g.Name)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "gidNumber", Values: []string{fmt.Sprintf("%d", g.GIDNumber)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"posixGroup"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uniqueMember", Values: h.getGroupMembers(g.GIDNumber)})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberUid", Values: h.getGroupMemberIDs(g.GIDNumber)})
|
||||
dn := fmt.Sprintf("cn=%s,%s=groups,%s", g.Name, h.backend.GroupFormat, h.backend.BaseDN)
|
||||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||
}
|
||||
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
// Close does not actually close anything, because the config data is kept in memory
|
||||
func (h configHandler) Close(boundDn string, conn net.Conn) error {
|
||||
stats.Frontend.Add("closes", 1)
|
||||
@@ -459,7 +224,7 @@ func (h configHandler) getGroupMembers(gid int) []string {
|
||||
}
|
||||
|
||||
m := []string{}
|
||||
for k, _ := range members {
|
||||
for k := range members {
|
||||
m = append(m, k)
|
||||
}
|
||||
|
||||
@@ -499,7 +264,7 @@ func (h configHandler) getGroupMemberIDs(gid int) []string {
|
||||
}
|
||||
|
||||
m := []string{}
|
||||
for k, _ := range members {
|
||||
for k := range members {
|
||||
m = append(m, k)
|
||||
}
|
||||
|
||||
@@ -531,7 +296,7 @@ func (h configHandler) getGroupDNs(gids []int) []string {
|
||||
}
|
||||
|
||||
g := []string{}
|
||||
for k, _ := range groups {
|
||||
for k := range groups {
|
||||
g = append(g, k)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
type HelperMaker interface {
|
||||
FindUser(userName string) (bool, config.User, error)
|
||||
FindGroup(groupName string) (bool, config.Group, error)
|
||||
}
|
||||
|
||||
// Handler is the common interface for all datastores
|
||||
|
||||
@@ -316,6 +316,10 @@ func (h ldapHandler) FindUser(userName string) (found bool, user config.User, er
|
||||
return false, config.User{}, nil
|
||||
}
|
||||
|
||||
func (h ldapHandler) FindGroup(groupName string) (found bool, group config.Group, err error) {
|
||||
return false, config.Group{}, nil
|
||||
}
|
||||
|
||||
func (h ldapHandler) Close(boundDn string, conn net.Conn) error {
|
||||
conn.Close() // close connection to the server when then client is closed
|
||||
h.lock.Lock()
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/GeertJohan/yubigo"
|
||||
"github.com/glauth/glauth/pkg/config"
|
||||
"github.com/glauth/glauth/pkg/stats"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nmcclain/ldap"
|
||||
"github.com/pquerna/otp/totp"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
var configattributematcher = regexp.MustCompile(`(?i)\((?P<attribute>[a-zA-Z0-9]+)\s*=\s*(?P<value>.*)\)`)
|
||||
|
||||
type LDAPOpsHandler interface {
|
||||
GetBackend() config.Backend
|
||||
GetLog() logr.Logger
|
||||
GetCfg() *config.Config
|
||||
GetYubikeyAuth() *yubigo.YubiAuth
|
||||
|
||||
FindUser(userName string) (f bool, u config.User, err error)
|
||||
FindGroup(groupName string) (f bool, g config.Group, err error)
|
||||
FindPosixAccounts() (entrylist []*ldap.Entry, err error)
|
||||
FindPosixGroups() (entrylist []*ldap.Entry, err error)
|
||||
}
|
||||
|
||||
type LDAPOpsHelper struct {
|
||||
}
|
||||
|
||||
func NewLDAPOpsHelper() LDAPOpsHelper {
|
||||
helper := LDAPOpsHelper{}
|
||||
return helper
|
||||
}
|
||||
|
||||
func (l LDAPOpsHelper) Bind(h LDAPOpsHandler, bindDN, bindSimplePw string, conn net.Conn) (resultCode ldap.LDAPResultCode, err error) {
|
||||
bindDN = strings.ToLower(bindDN)
|
||||
baseDN := strings.ToLower("," + h.GetBackend().BaseDN)
|
||||
|
||||
h.GetLog().V(6).Info("Bind request", "binddn", bindDN, "basedn", h.GetBackend().BaseDN, "src", conn.RemoteAddr())
|
||||
|
||||
stats.Frontend.Add("bind_reqs", 1)
|
||||
|
||||
if bindDN == "" && bindSimplePw == "" {
|
||||
stats.Frontend.Add("bind_successes", 1)
|
||||
h.GetLog().V(6).Info("Anonymous Bind success", "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
}
|
||||
|
||||
// parse the bindDN - ensure that the bindDN ends with the BaseDN
|
||||
if !strings.HasSuffix(bindDN, baseDN) {
|
||||
h.GetLog().V(2).Info("BindDN not part of our BaseDN", "binddn", bindDN, "basedn", h.GetBackend().BaseDN)
|
||||
// h.GetLog().Warning(fmt.Sprintf("Bind Error: BindDN %s not our BaseDN %s", bindDN, baseDN))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
parts := strings.Split(strings.TrimSuffix(bindDN, baseDN), ",")
|
||||
groupName := ""
|
||||
userName := ""
|
||||
if len(parts) == 1 {
|
||||
userName = strings.TrimPrefix(parts[0], h.GetBackend().NameFormat+"=")
|
||||
} else if len(parts) == 2 {
|
||||
userName = strings.TrimPrefix(parts[0], h.GetBackend().NameFormat+"=")
|
||||
groupName = strings.TrimPrefix(parts[1], h.GetBackend().GroupFormat+"=")
|
||||
} else {
|
||||
h.GetLog().V(2).Info("BindDN should have only one or two parts", "binddn", bindDN, "numparts", len(parts))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
|
||||
// find the user
|
||||
found, user, _ := h.FindUser(userName)
|
||||
if !found {
|
||||
h.GetLog().V(2).Info("User not found", "username", userName)
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
// find the group
|
||||
found, group, _ := h.FindGroup(groupName)
|
||||
if !found {
|
||||
h.GetLog().V(2).Info("Group not found", "groupname", groupName)
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
// validate group membership
|
||||
if user.PrimaryGroup != group.GIDNumber {
|
||||
h.GetLog().V(2).Info("primary group mismatch", "username", userName, "primarygroup", user.PrimaryGroup, "groupid", group.GIDNumber)
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
|
||||
validotp := false
|
||||
|
||||
if len(user.Yubikey) == 0 && len(user.OTPSecret) == 0 {
|
||||
validotp = true
|
||||
}
|
||||
|
||||
if len(user.Yubikey) > 0 && h.GetYubikeyAuth() != nil {
|
||||
if len(bindSimplePw) > 44 {
|
||||
otp := bindSimplePw[len(bindSimplePw)-44:]
|
||||
yubikeyid := otp[0:12]
|
||||
bindSimplePw = bindSimplePw[:len(bindSimplePw)-44]
|
||||
|
||||
if user.Yubikey == yubikeyid {
|
||||
_, ok, _ := h.GetYubikeyAuth().Verify(otp)
|
||||
|
||||
if ok {
|
||||
validotp = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store the full bind password provided before possibly modifying
|
||||
// in the otp check
|
||||
untouchedBindSimplePw := bindSimplePw
|
||||
|
||||
// Test OTP if exists
|
||||
if len(user.OTPSecret) > 0 && !validotp {
|
||||
if len(bindSimplePw) > 6 {
|
||||
otp := bindSimplePw[len(bindSimplePw)-6:]
|
||||
bindSimplePw = bindSimplePw[:len(bindSimplePw)-6]
|
||||
|
||||
validotp = totp.Validate(otp, user.OTPSecret)
|
||||
}
|
||||
}
|
||||
|
||||
// finally, validate user's pw
|
||||
|
||||
// check app passwords first
|
||||
if user.PassAppBcrypt != nil {
|
||||
for index, appPw := range user.PassAppBcrypt {
|
||||
decoded, err := hex.DecodeString(appPw)
|
||||
if err != nil {
|
||||
h.GetLog().V(6).Info("invalid app credentials", "incorrect stored hash", "(omitted)")
|
||||
} else {
|
||||
if bcrypt.CompareHashAndPassword(decoded, []byte(untouchedBindSimplePw)) == nil {
|
||||
stats.Frontend.Add("bind_successes", 1)
|
||||
h.GetLog().V(6).Info("Bind success using app pw", "index", index, "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if user.PassAppSHA256 != nil {
|
||||
hashFull := sha256.New()
|
||||
hashFull.Write([]byte(untouchedBindSimplePw))
|
||||
for index, appPw := range user.PassAppSHA256 {
|
||||
if appPw != hex.EncodeToString(hashFull.Sum(nil)) {
|
||||
h.GetLog().V(6).Info("Attempt to bind app pw failed", "index", index, "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
} else {
|
||||
stats.Frontend.Add("bind_successes", 1)
|
||||
h.GetLog().V(6).Info("Bind success using app pw", "index", index, "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then ensure the OTP is valid before checking
|
||||
if !validotp {
|
||||
h.GetLog().V(2).Info("invalid OTP token", "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
|
||||
// Now, check the pasword hash
|
||||
if user.PassBcrypt != "" {
|
||||
decoded, err := hex.DecodeString(user.PassBcrypt)
|
||||
if err != nil {
|
||||
h.GetLog().V(2).Info("invalid credentials", "incorrect stored hash", "(omitted)")
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
if bcrypt.CompareHashAndPassword(decoded, []byte(bindSimplePw)) != nil {
|
||||
h.GetLog().V(2).Info("invalid credentials", "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
}
|
||||
if user.PassSHA256 != "" {
|
||||
hash := sha256.New()
|
||||
hash.Write([]byte(bindSimplePw))
|
||||
if user.PassSHA256 != hex.EncodeToString(hash.Sum(nil)) {
|
||||
h.GetLog().V(2).Info("invalid credentials", "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
}
|
||||
|
||||
stats.Frontend.Add("bind_successes", 1)
|
||||
h.GetLog().V(6).Info("Bind success", "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
}
|
||||
|
||||
func (l LDAPOpsHelper) Search(h LDAPOpsHandler, bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
|
||||
bindDN = strings.ToLower(bindDN)
|
||||
baseDN := strings.ToLower(h.GetBackend().BaseDN)
|
||||
delimitedBaseDN := "," + baseDN
|
||||
searchBaseDN := strings.ToLower(searchReq.BaseDN)
|
||||
h.GetLog().V(6).Info("Search request", "binddn", bindDN, "basedn", baseDN, "searchbasedn", searchBaseDN, "src", conn.RemoteAddr(), "scope", searchReq.Scope, "filter", searchReq.Filter)
|
||||
stats.Frontend.Add("search_reqs", 1)
|
||||
|
||||
anonymous := len(bindDN) < 1
|
||||
|
||||
// special case: querying the root DSE
|
||||
if searchReq.Scope == 0 && (searchBaseDN == "" || searchBaseDN == baseDN) {
|
||||
if anonymous && !h.GetBackend().AnonymousDSE {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Root DSE Search Error: Anonymous BindDN not allowed %s", bindDN)
|
||||
}
|
||||
h.GetLog().V(6).Info("Search request", "special case", "root DSE")
|
||||
entries := []*ldap.Entry{}
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
// unfortunately, objectClass is not to be included so we will respect that
|
||||
// attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"*"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedSASLMechanisms", Values: []string{}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedLDAPVersion", Values: []string{"3"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedControl", Values: []string{}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedCapabilities", Values: []string{}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "subschemaSubentry", Values: []string{"cn=schema"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "serverName", Values: []string{"unknown"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "namingContexts", Values: []string{baseDN}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "defaultNamingContext", Values: []string{baseDN}})
|
||||
attrs = l.collectRequestedAttributesBack(attrs, searchReq)
|
||||
entries = append(entries, &ldap.Entry{DN: searchBaseDN, Attributes: attrs})
|
||||
stats.Frontend.Add("search_successes", 1)
|
||||
h.GetLog().V(6).Info("AP: Root Search OK", "filter", searchReq.Filter)
|
||||
return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess}, nil
|
||||
}
|
||||
|
||||
// validate the user is authenticated and has appropriate access
|
||||
if anonymous {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: Anonymous BindDN not allowed %s", bindDN)
|
||||
}
|
||||
|
||||
if searchBaseDN == "cn=schema" {
|
||||
h.GetLog().V(6).Info("Search request", "special case", "schema discovery")
|
||||
entries := []*ldap.Entry{}
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "cn", Values: []string{"schema"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "hasSubordinates", Values: []string{"false"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "modifiersName", Values: []string{"cn=Directory Manager"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "modifyTimeStamp", Values: []string{"Mar 8, 2021, 12:46:29 PM PST (20210308204629Z)"}})
|
||||
// Iterate through schema attributes provided in schema/ directory
|
||||
filenames, _ := ioutil.ReadDir("schema")
|
||||
for _, filename := range filenames {
|
||||
file, err := os.Open(filepath.Join("schema", filename.Name()))
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Schema Error: attribute %s cannot be read", filename)
|
||||
}
|
||||
defer file.Close()
|
||||
values := []string{}
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
values = append(values, line)
|
||||
}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: filename.Name(), Values: values})
|
||||
}
|
||||
attrs = l.collectRequestedAttributesBack(attrs, searchReq)
|
||||
entries = append(entries, &ldap.Entry{DN: searchBaseDN, Attributes: attrs})
|
||||
stats.Frontend.Add("search_successes", 1)
|
||||
h.GetLog().V(6).Info("AP: Schema Discovery OK", "filter", searchReq.Filter)
|
||||
return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess}, nil
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(bindDN, delimitedBaseDN) {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: BindDN %s not in our BaseDN %s", bindDN, h.GetBackend().BaseDN)
|
||||
}
|
||||
if !strings.HasSuffix(searchBaseDN, h.GetBackend().BaseDN) {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: search BaseDN %s is not in our BaseDN %s", searchBaseDN, h.GetBackend().BaseDN)
|
||||
}
|
||||
// return all users in the config file - the LDAP library will filter results for us
|
||||
entries := []*ldap.Entry{}
|
||||
filterEntity, err := ldap.GetFilterObjectClass(searchReq.Filter)
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: error parsing filter: %s", searchReq.Filter)
|
||||
}
|
||||
switch filterEntity {
|
||||
default:
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: unhandled filter type: %s [%s]", filterEntity, searchReq.Filter)
|
||||
case "posixgroup":
|
||||
posixentries, err := h.FindPosixGroups()
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: Unable to retrieve data [%s]", err.Error())
|
||||
}
|
||||
entries = append(entries, posixentries...)
|
||||
case "posixaccount", "shadowaccount", "":
|
||||
posixentries, err := h.FindPosixAccounts()
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: Unable to retrieve data [%s]", err.Error())
|
||||
}
|
||||
entries = append(entries, posixentries...)
|
||||
}
|
||||
stats.Frontend.Add("search_successes", 1)
|
||||
h.GetLog().V(6).Info("AP: Search OK", "filter", searchReq.Filter)
|
||||
return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess}, nil
|
||||
}
|
||||
|
||||
// If your query is for, say 'objectClass', then our LDAP
|
||||
// library will weed out this entry since it does *not* contain an objectclass attribute
|
||||
// so we are going to re-inject it to keep the LDAP library happy
|
||||
func (l LDAPOpsHelper) collectRequestedAttributesBack(attrs []*ldap.EntryAttribute, searchReq ldap.SearchRequest) []*ldap.EntryAttribute {
|
||||
attbits := configattributematcher.FindStringSubmatch(searchReq.Filter)
|
||||
if len(attbits) == 3 {
|
||||
foundattname := false
|
||||
for _, attr := range attrs {
|
||||
if strings.ToLower(attr.Name) == strings.ToLower(attbits[1]) {
|
||||
foundattname = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// the ugly hack: we are going to pretend that the requested attribute is in there
|
||||
if !foundattname {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: attbits[1], Values: []string{attbits[2]}})
|
||||
}
|
||||
}
|
||||
return attrs
|
||||
}
|
||||
+15
-7
@@ -13,13 +13,14 @@ type Option func(o *Options)
|
||||
|
||||
// Options defines the available options for this package.
|
||||
type Options struct {
|
||||
Backend config.Backend
|
||||
Handlers HandlerWrapper
|
||||
Logger logr.Logger
|
||||
Config *config.Config
|
||||
Context *context.Context
|
||||
YubiAuth *yubigo.YubiAuth
|
||||
Helper Handler
|
||||
Backend config.Backend
|
||||
Handlers HandlerWrapper
|
||||
Logger logr.Logger
|
||||
Config *config.Config
|
||||
Context *context.Context
|
||||
YubiAuth *yubigo.YubiAuth
|
||||
Helper Handler
|
||||
LDAPHelper LDAPOpsHelper
|
||||
}
|
||||
|
||||
// newOptions initializes the available default options.
|
||||
@@ -92,3 +93,10 @@ func Helper(val Handler) Option {
|
||||
o.Helper = val
|
||||
}
|
||||
}
|
||||
|
||||
// Global LDAP Handler
|
||||
func LDAPHelper(val LDAPOpsHelper) Option {
|
||||
return func(o *Options) {
|
||||
o.LDAPHelper = val
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +192,10 @@ func (h ownCloudHandler) FindUser(userName string) (found bool, user config.User
|
||||
return false, config.User{}, nil
|
||||
}
|
||||
|
||||
func (h ownCloudHandler) FindGroup(groupName string) (found bool, group config.Group, err error) {
|
||||
return false, config.Group{}, nil
|
||||
}
|
||||
|
||||
func (h ownCloudHandler) Close(boundDN string, conn net.Conn) error {
|
||||
conn.Close() // close connection to the server when then client is closed
|
||||
h.lock.Lock()
|
||||
|
||||
+18
-19
@@ -42,9 +42,8 @@ Tables:
|
||||
Here is how to insert example data using your database's REPL (more detailed information can be found in pkg/plugins/sample-database.cfg)
|
||||
|
||||
```sql
|
||||
INSERT INTO users(name, uidnumber, primarygroup, passsha256) VALUES('hackers', 5001, 5501, '6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a');
|
||||
INSERT INTO groups(name, gidnumber) VALUES('superheros', 5501);
|
||||
INSERT INTO groups(name, gidnumber) VALUES('crusaders', 5502);
|
||||
INSERT INTO groups(name, gidnumber) VALUES('svcaccts', 5502);
|
||||
INSERT INTO groups(name, gidnumber) VALUES('civilians', 5503);
|
||||
INSERT INTO groups(name, gidnumber) VALUES('caped', 5504);
|
||||
INSERT INTO groups(name, gidnumber) VALUES('lovesailing', 5505);
|
||||
@@ -52,10 +51,10 @@ INSERT INTO groups(name, gidnumber) VALUES('smoker', 5506);
|
||||
INSERT INTO includegroups(parentgroupid, includegroupid) VALUES(5503, 5501);
|
||||
INSERT INTO includegroups(parentgroupid, includegroupid) VALUES(5504, 5502);
|
||||
INSERT INTO includegroups(parentgroupid, includegroupid) VALUES(5504, 5501);
|
||||
INSERT INTO users(name, uidnumber, primarygroup, passsha256) VALUES('user1', 5001, 5501, '6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a');
|
||||
INSERT INTO users(name, uidnumber, primarygroup, passsha256) VALUES('user2', 5002, 5502, '6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a');
|
||||
INSERT INTO users(name, uidnumber, primarygroup, passsha256) VALUES('user3', 5003, 5504, '6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a');
|
||||
INSERT INTO users(name, uidnumber, primarygroup, passsha256, othergroups) VALUES('user4', 5004, 5504, '6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a', '5505,5506');
|
||||
INSERT INTO users(name, uidnumber, primarygroup, passsha256) VALUES('hackers', 5001, 5501, '6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a');
|
||||
INSERT INTO users(name, uidnumber, primarygroup, passsha256) VALUES('johndoe', 5002, 5502, '6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a');
|
||||
INSERT INTO users(name, uidnumber, primarygroup, passsha256) VALUES('serviceuser', 5003, 5502, '652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0');
|
||||
INSERT INTO users(name, uidnumber, primarygroup, passsha256, othergroups) VALUES('user4', 5004, 5504, '652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0', '5505,5506');
|
||||
```
|
||||
This should be equivalent to this configuration:
|
||||
```text
|
||||
@@ -66,36 +65,36 @@ This should be equivalent to this configuration:
|
||||
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||
|
||||
[[users]]
|
||||
name = "user1"
|
||||
name = "hackers"
|
||||
uidnumber = 5001
|
||||
primarygroup = 5501
|
||||
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||
|
||||
[[users]]
|
||||
name = "user2"
|
||||
name = "johndoe"
|
||||
uidnumber = 5002
|
||||
primarygroup = 5502
|
||||
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||
|
||||
[[users]]
|
||||
name = "user3"
|
||||
name = "serviceuser"
|
||||
uidnumber = 5003
|
||||
primarygroup = 5504
|
||||
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||
primarygroup = 5502
|
||||
passsha256 = "652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0" # mysecret
|
||||
|
||||
[[users]]
|
||||
name = "user4"
|
||||
uidnumber = 5003
|
||||
primarygroup = 5504
|
||||
othergroups = [5505, 5506]
|
||||
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||
passsha256 = "652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0" # mysecret
|
||||
|
||||
[[groups]]
|
||||
name = "superheros"
|
||||
gidnumber = 5501
|
||||
|
||||
[[groups]]
|
||||
name = "crusaders"
|
||||
name = "svcaccts"
|
||||
gidnumber = 5502
|
||||
|
||||
[[groups]]
|
||||
@@ -110,18 +109,18 @@ This should be equivalent to this configuration:
|
||||
```
|
||||
and LDAP should return these `memberOf` values:
|
||||
```text
|
||||
uid: user1
|
||||
uid: hackers
|
||||
ou: superheros
|
||||
memberOf: cn=caped,ou=groups,dc=militate,dc=com
|
||||
memberOf: cn=civilians,ou=groups,dc=militate,dc=com
|
||||
memberOf: cn=superheros,ou=groups,dc=militate,dc=com
|
||||
|
||||
uid: user2
|
||||
ou: crusaders
|
||||
uid: johndoe
|
||||
ou: svcaccts
|
||||
memberOf: cn=caped,ou=groups,dc=militate,dc=com
|
||||
memberOf: cn=crusaders,ou=groups,dc=militate,dc=com
|
||||
memberOf: cn=svcaccts,ou=groups,dc=militate,dc=com
|
||||
|
||||
uid: user3
|
||||
uid: serviceuser
|
||||
ou: caped
|
||||
memberOf: cn=caped,ou=groups,dc=militate,dc=com
|
||||
|
||||
@@ -133,6 +132,6 @@ memberOf: cn=smoker,ou=groups,dc=militate,dc=com
|
||||
```
|
||||
If you have the ldap client package installed, this can be easily confirmed by running
|
||||
```
|
||||
ldapsearch -H ldap://localhost:3893 -D cn=hackers,ou=superheros,dc=glauth,dc=com -w dogood -x -bdc=glauth,dc=com cn=user1
|
||||
ldapsearch -H ldap://localhost:3893 -D cn=hackers,ou=superheros,dc=glauth,dc=com -w dogood -x -bdc=glauth,dc=com cn=hackers
|
||||
```
|
||||
and so on.
|
||||
|
||||
+90
-221
@@ -1,13 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -18,10 +17,10 @@ import (
|
||||
"github.com/glauth/glauth/pkg/stats"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nmcclain/ldap"
|
||||
"github.com/pquerna/otp/totp"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
var configattributematcher = regexp.MustCompile(`(?i)\((?P<attribute>[a-zA-Z0-9]+)\s*=\s*(?P<value>.*)\)`)
|
||||
|
||||
type SqlBackend interface {
|
||||
// Name used by database/sql when loading the driver
|
||||
GetDriverName() string
|
||||
@@ -39,10 +38,13 @@ type database struct {
|
||||
type databaseHandler struct {
|
||||
backend config.Backend
|
||||
log logr.Logger
|
||||
cfg *config.Config
|
||||
yubikeyAuth *yubigo.YubiAuth
|
||||
sqlBackend SqlBackend
|
||||
database database
|
||||
MemGroups []config.Group
|
||||
ldohelper handler.LDAPOpsHelper
|
||||
attmatcher *regexp.Regexp
|
||||
}
|
||||
|
||||
// func NewDatabaseHandler_deprecated(log *logging.Logger, cfg *config.Config, yubikeyAuth *yubigo.YubiAuth, sqlBackend SqlBackend) handler.Handler {
|
||||
@@ -69,9 +71,12 @@ func NewDatabaseHandler(sqlBackend SqlBackend, opts ...handler.Option) handler.H
|
||||
handler := databaseHandler{
|
||||
backend: options.Backend,
|
||||
log: options.Logger,
|
||||
cfg: options.Config,
|
||||
yubikeyAuth: options.YubiAuth,
|
||||
sqlBackend: sqlBackend,
|
||||
database: dbInfo}
|
||||
database: dbInfo,
|
||||
ldohelper: options.LDAPHelper,
|
||||
attmatcher: configattributematcher}
|
||||
|
||||
sqlBackend.CreateSchema(db)
|
||||
|
||||
@@ -80,223 +85,25 @@ func NewDatabaseHandler(sqlBackend SqlBackend, opts ...handler.Option) handler.H
|
||||
return handler
|
||||
}
|
||||
|
||||
func (h databaseHandler) GetBackend() config.Backend {
|
||||
return h.backend
|
||||
}
|
||||
func (h databaseHandler) GetLog() logr.Logger {
|
||||
return h.log
|
||||
}
|
||||
func (h databaseHandler) GetCfg() *config.Config {
|
||||
return h.cfg
|
||||
}
|
||||
func (h databaseHandler) GetYubikeyAuth() *yubigo.YubiAuth {
|
||||
return h.yubikeyAuth
|
||||
}
|
||||
|
||||
func (h databaseHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultCode ldap.LDAPResultCode, err error) {
|
||||
bindDN = strings.ToLower(bindDN)
|
||||
baseDN := strings.ToLower("," + h.backend.BaseDN)
|
||||
|
||||
h.log.V(3).Info(fmt.Sprintf("Bind request: bindDN: %s, BaseDN: %s, source: %s", bindDN, h.backend.BaseDN, conn.RemoteAddr().String()))
|
||||
|
||||
stats.Frontend.Add("bind_reqs", 1)
|
||||
|
||||
// parse the bindDN - ensure that the bindDN ends with the BaseDN
|
||||
if !strings.HasSuffix(bindDN, baseDN) {
|
||||
h.log.V(2).Info(fmt.Sprintf("Bind Error: BindDN %s not our BaseDN %s", bindDN, h.backend.BaseDN))
|
||||
// h.log.V(2).Info(fmt.Sprintf("Bind Error: BindDN %s not our BaseDN %s", bindDN, baseDN))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
parts := strings.Split(strings.TrimSuffix(bindDN, baseDN), ",")
|
||||
groupName := ""
|
||||
userName := ""
|
||||
if len(parts) == 1 {
|
||||
userName = strings.TrimPrefix(parts[0], h.backend.NameFormat+"=")
|
||||
} else if len(parts) == 2 {
|
||||
userName = strings.TrimPrefix(parts[0], h.backend.NameFormat+"=")
|
||||
groupName = strings.TrimPrefix(parts[1], h.backend.GroupFormat+"=")
|
||||
} else {
|
||||
h.log.V(2).Info(fmt.Sprintf("Bind Error: BindDN %s should have only one or two parts (has %d)", bindDN, len(parts)))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
|
||||
// find the user
|
||||
user := config.User{}
|
||||
err = h.database.cnx.QueryRow(fmt.Sprintf(`
|
||||
SELECT u.uidnumber,u.primarygroup,u.passbcrypt,u.passsha256,u.otpsecret,u.yubikey
|
||||
FROM users u WHERE lower(u.name)=%s`, h.sqlBackend.GetPrepareSymbol()), userName).Scan(
|
||||
&user.UIDNumber, &user.PrimaryGroup, &user.PassBcrypt, &user.PassSHA256, &user.OTPSecret, &user.Yubikey)
|
||||
if err != nil {
|
||||
h.log.V(2).Info(fmt.Sprintf("Bind Error: User %s not found.", userName))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
// find the group
|
||||
group := config.Group{}
|
||||
err = h.database.cnx.QueryRow(fmt.Sprintf(`
|
||||
SELECT g.gidnumber FROM groups g WHERE lower(name)=%s`, h.sqlBackend.GetPrepareSymbol()), groupName).Scan(
|
||||
&group.GIDNumber)
|
||||
if err != nil {
|
||||
h.log.V(2).Info(fmt.Sprintf("Bind Error: Group %s not found.", userName))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
// validate group membership
|
||||
if user.PrimaryGroup != group.GIDNumber {
|
||||
h.log.V(2).Info(fmt.Sprintf("Bind Error: User %s primary group is not %s.", userName, groupName))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
|
||||
validotp := false
|
||||
|
||||
if len(user.Yubikey) == 0 && len(user.OTPSecret) == 0 {
|
||||
validotp = true
|
||||
}
|
||||
|
||||
if len(user.Yubikey) > 0 && h.yubikeyAuth != nil {
|
||||
if len(bindSimplePw) > 44 {
|
||||
otp := bindSimplePw[len(bindSimplePw)-44:]
|
||||
yubikeyid := otp[0:12]
|
||||
bindSimplePw = bindSimplePw[:len(bindSimplePw)-44]
|
||||
|
||||
if user.Yubikey == yubikeyid {
|
||||
_, ok, _ := h.yubikeyAuth.Verify(otp)
|
||||
|
||||
if ok {
|
||||
validotp = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store the full bind password provided before possibly modifying
|
||||
// in the otp check
|
||||
untouchedBindSimplePw := bindSimplePw
|
||||
|
||||
// Test OTP if exists
|
||||
if len(user.OTPSecret) > 0 && !validotp {
|
||||
if len(bindSimplePw) > 6 {
|
||||
otp := bindSimplePw[len(bindSimplePw)-6:]
|
||||
bindSimplePw = bindSimplePw[:len(bindSimplePw)-6]
|
||||
|
||||
validotp = totp.Validate(otp, user.OTPSecret)
|
||||
}
|
||||
}
|
||||
|
||||
// finally, validate user's pw
|
||||
|
||||
// check app passwords first
|
||||
if user.PassAppBcrypt != nil {
|
||||
for index, appPw := range user.PassAppBcrypt {
|
||||
decoded, err := hex.DecodeString(appPw)
|
||||
if err != nil {
|
||||
h.log.V(6).Info("invalid app credentials", "incorrect stored hash", "(omitted)")
|
||||
} else {
|
||||
if bcrypt.CompareHashAndPassword(decoded, []byte(untouchedBindSimplePw)) == nil {
|
||||
stats.Frontend.Add("bind_successes", 1)
|
||||
h.log.V(6).Info("Bind success using app pw", "index", index, "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if user.PassAppSHA256 != nil {
|
||||
hashFull := sha256.New()
|
||||
hashFull.Write([]byte(untouchedBindSimplePw))
|
||||
for index, appPw := range user.PassAppSHA256 {
|
||||
if appPw != hex.EncodeToString(hashFull.Sum(nil)) {
|
||||
h.log.V(2).Info(fmt.Sprintf("Attempted to bind app pw #%d - failure as %s from %s", index, bindDN, conn.RemoteAddr().String()))
|
||||
} else {
|
||||
stats.Frontend.Add("bind_successes", 1)
|
||||
h.log.V(3).Info("Bind success using app pw #%d as %s from %s", index, bindDN, conn.RemoteAddr().String())
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then ensure the OTP is valid before checking
|
||||
if !validotp {
|
||||
h.log.V(2).Info(fmt.Sprintf("Bind Error: invalid OTP token as %s from %s", bindDN, conn.RemoteAddr().String()))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
|
||||
// Now, check the password hash
|
||||
if user.PassBcrypt != "" {
|
||||
decoded, err := hex.DecodeString(user.PassBcrypt)
|
||||
if err != nil {
|
||||
h.log.V(2).Info("invalid credentials", "incorrect stored hash", "(omitted)")
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
if bcrypt.CompareHashAndPassword(decoded, []byte(bindSimplePw)) != nil {
|
||||
h.log.V(2).Info("invalid credentials", "binddn", bindDN, "src", conn.RemoteAddr())
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
}
|
||||
if user.PassSHA256 != "" {
|
||||
hash := sha256.New()
|
||||
hash.Write([]byte(bindSimplePw))
|
||||
if user.PassSHA256 != hex.EncodeToString(hash.Sum(nil)) {
|
||||
h.log.V(2).Info(fmt.Sprintf("Bind Error: invalid credentials as %s from %s", bindDN, conn.RemoteAddr().String()))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
}
|
||||
|
||||
stats.Frontend.Add("bind_successes", 1)
|
||||
h.log.V(3).Info(fmt.Sprintf("Bind success as %s from %s", bindDN, conn.RemoteAddr().String()))
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
return h.ldohelper.Bind(h, bindDN, bindSimplePw, conn)
|
||||
}
|
||||
|
||||
func (h databaseHandler) Search(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
|
||||
bindDN = strings.ToLower(bindDN)
|
||||
baseDN := strings.ToLower("," + h.backend.BaseDN)
|
||||
searchBaseDN := strings.ToLower(searchReq.BaseDN)
|
||||
h.log.V(3).Info(fmt.Sprintf("Search request as %s from %s for %s", bindDN, conn.RemoteAddr().String(), searchReq.Filter))
|
||||
stats.Frontend.Add("search_reqs", 1)
|
||||
|
||||
// validate the user is authenticated and has appropriate access
|
||||
if len(bindDN) < 1 {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: Anonymous BindDN not allowed %s", bindDN)
|
||||
}
|
||||
if !strings.HasSuffix(bindDN, baseDN) {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: BindDN %s not in our BaseDN %s", bindDN, h.backend.BaseDN)
|
||||
}
|
||||
if !strings.HasSuffix(searchBaseDN, h.backend.BaseDN) {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: search BaseDN %s is not in our BaseDN %s", searchBaseDN, h.backend.BaseDN)
|
||||
}
|
||||
// return all users in the config file - the LDAP library will filter results for us
|
||||
entries := []*ldap.Entry{}
|
||||
filterEntity, err := ldap.GetFilterObjectClass(searchReq.Filter)
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: error parsing filter: %s", searchReq.Filter)
|
||||
}
|
||||
switch filterEntity {
|
||||
default:
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: unhandled filter type: %s [%s]", filterEntity, searchReq.Filter)
|
||||
case "posixgroup":
|
||||
h.MemGroups, err = h.memoizeGroups()
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: Unable to memoize groups [%s]", err.Error())
|
||||
}
|
||||
|
||||
for _, g := range h.MemGroups {
|
||||
entries = append(entries, h.getGroup(g))
|
||||
}
|
||||
case "posixaccount", "":
|
||||
h.MemGroups, err = h.memoizeGroups()
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: Unable to memoize groups [%s]", err.Error())
|
||||
}
|
||||
|
||||
rows, err := h.database.cnx.Query(`
|
||||
SELECT u.name,u.uidnumber,u.primarygroup,u.passbcrypt,u.passsha256,u.otpsecret,u.yubikey,u.othergroups,u.givenname,u.sn,u.mail,u.loginshell,u.homedirectory,u.disabled
|
||||
FROM users u`)
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: Unable to retrieve data [%s]", err.Error())
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var otherGroups string
|
||||
var disabled int
|
||||
u := config.User{}
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&u.Name, &u.UIDNumber, &u.PrimaryGroup, &u.PassBcrypt, &u.PassSHA256, &u.OTPSecret, &u.Yubikey, &otherGroups, &u.GivenName, &u.SN, &u.Mail, &u.LoginShell, &u.Homedir, &disabled)
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: Unable to retrieve data [%s]", err.Error())
|
||||
}
|
||||
u.OtherGroups = h.commaListToTable(otherGroups)
|
||||
u.Disabled = h.intToBool(disabled)
|
||||
|
||||
entries = append(entries, h.getAccount(u))
|
||||
}
|
||||
}
|
||||
stats.Frontend.Add("search_successes", 1)
|
||||
h.log.V(3).Info(fmt.Sprintf("AP: Search OK: %s", searchReq.Filter))
|
||||
return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess}, nil
|
||||
return h.ldohelper.Search(h, bindDN, searchReq, conn)
|
||||
}
|
||||
|
||||
// Add is not yet supported for the sql backend
|
||||
@@ -329,6 +136,68 @@ func (h databaseHandler) FindUser(userName string) (f bool, u config.User, err e
|
||||
return found, user, err
|
||||
}
|
||||
|
||||
func (h databaseHandler) FindGroup(groupName string) (f bool, g config.Group, err error) {
|
||||
group := config.Group{}
|
||||
found := false
|
||||
|
||||
err = h.database.cnx.QueryRow(fmt.Sprintf(`
|
||||
SELECT g.gidnumber FROM groups g WHERE lower(name)=%s`, h.sqlBackend.GetPrepareSymbol()), groupName).Scan(
|
||||
&group.GIDNumber)
|
||||
if err == nil {
|
||||
found = true
|
||||
}
|
||||
|
||||
return found, group, err
|
||||
}
|
||||
|
||||
func (h databaseHandler) FindPosixAccounts() (entrylist []*ldap.Entry, err error) {
|
||||
entries := []*ldap.Entry{}
|
||||
|
||||
h.MemGroups, err = h.memoizeGroups()
|
||||
if err != nil {
|
||||
return entries, err
|
||||
}
|
||||
|
||||
rows, err := h.database.cnx.Query(`
|
||||
SELECT u.name,u.uidnumber,u.primarygroup,u.passbcrypt,u.passsha256,u.otpsecret,u.yubikey,u.othergroups,u.givenname,u.sn,u.mail,u.loginshell,u.homedirectory,u.disabled
|
||||
FROM users u`)
|
||||
if err != nil {
|
||||
return entries, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var otherGroups string
|
||||
var disabled int
|
||||
u := config.User{}
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&u.Name, &u.UIDNumber, &u.PrimaryGroup, &u.PassBcrypt, &u.PassSHA256, &u.OTPSecret, &u.Yubikey, &otherGroups, &u.GivenName, &u.SN, &u.Mail, &u.LoginShell, &u.Homedir, &disabled)
|
||||
if err != nil {
|
||||
return entries, err
|
||||
}
|
||||
u.OtherGroups = h.commaListToTable(otherGroups)
|
||||
u.Disabled = h.intToBool(disabled)
|
||||
|
||||
entries = append(entries, h.getAccount(u))
|
||||
}
|
||||
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
func (h databaseHandler) FindPosixGroups() (entrylist []*ldap.Entry, err error) {
|
||||
entries := []*ldap.Entry{}
|
||||
|
||||
h.MemGroups, err = h.memoizeGroups()
|
||||
if err != nil {
|
||||
return entries, err
|
||||
}
|
||||
|
||||
for _, g := range h.MemGroups {
|
||||
entries = append(entries, h.getGroup(g))
|
||||
}
|
||||
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
func (h databaseHandler) Close(boundDn string, conn net.Conn) error {
|
||||
stats.Frontend.Add("closes", 1)
|
||||
return nil
|
||||
@@ -446,7 +315,7 @@ func (h databaseHandler) getGroupMembers(gid int) []string {
|
||||
}
|
||||
|
||||
m := []string{}
|
||||
for k, _ := range members {
|
||||
for k := range members {
|
||||
m = append(m, k)
|
||||
}
|
||||
|
||||
@@ -503,7 +372,7 @@ func (h databaseHandler) getGroupMemberIDs(gid int) []string {
|
||||
}
|
||||
|
||||
m := []string{}
|
||||
for k, _ := range members {
|
||||
for k := range members {
|
||||
m = append(m, k)
|
||||
}
|
||||
|
||||
@@ -535,7 +404,7 @@ func (h databaseHandler) getGroupDNs(gids []int) []string {
|
||||
}
|
||||
|
||||
g := []string{}
|
||||
for k, _ := range groups {
|
||||
for k := range groups {
|
||||
g = append(g, k)
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ debug = true
|
||||
listen = "0.0.0.0:3893"
|
||||
|
||||
[ldaps]
|
||||
enabled = true
|
||||
enabled = false
|
||||
listen = "0.0.0.0:3894"
|
||||
cert = "certs/server.crt"
|
||||
key = "certs/server.key"
|
||||
|
||||
@@ -39,6 +39,8 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
|
||||
|
||||
var helper handler.Handler
|
||||
|
||||
loh := handler.NewLDAPOpsHelper()
|
||||
|
||||
// instantiate the helper, if any
|
||||
if s.c.Helper.Enabled {
|
||||
switch s.c.Helper.Datastore {
|
||||
@@ -47,6 +49,7 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
|
||||
handler.Logger(s.log),
|
||||
handler.Config(s.c),
|
||||
handler.YubiAuth(s.yubiAuth),
|
||||
handler.LDAPHelper(loh),
|
||||
)
|
||||
case "plugin":
|
||||
plug, err := plugin.Open(s.c.Helper.Plugin)
|
||||
@@ -68,6 +71,7 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
|
||||
handler.Logger(s.log),
|
||||
handler.Config(s.c),
|
||||
handler.YubiAuth(s.yubiAuth),
|
||||
handler.LDAPHelper(loh),
|
||||
)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported helper %s - must be one of 'config', 'plugin'", s.c.Helper.Datastore)
|
||||
@@ -102,6 +106,7 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
|
||||
handler.Logger(s.log),
|
||||
handler.Config(s.c), // TODO only used to access Users and Groups, move that to dedicated options
|
||||
handler.YubiAuth(s.yubiAuth),
|
||||
handler.LDAPHelper(loh),
|
||||
)
|
||||
case "plugin":
|
||||
plug, err := plugin.Open(backend.Plugin)
|
||||
@@ -122,7 +127,9 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
|
||||
h = initFunc(
|
||||
handler.Backend(backend),
|
||||
handler.Logger(s.log),
|
||||
handler.Config(s.c),
|
||||
handler.YubiAuth(s.yubiAuth),
|
||||
handler.LDAPHelper(loh),
|
||||
)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported backend %s - must be one of 'config', 'ldap','owncloud' or 'plugin'", backend.Datastore)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#################
|
||||
# glauth.conf
|
||||
|
||||
#################
|
||||
# General configuration.
|
||||
#debug = true
|
||||
syslog = true
|
||||
|
||||
#################
|
||||
# Server configuration.
|
||||
[ldap]
|
||||
enabled = true
|
||||
listen = "0.0.0.0:3893"
|
||||
|
||||
[ldaps]
|
||||
enabled = false
|
||||
listen = "0.0.0.0:636"
|
||||
cert = "glauth.crt"
|
||||
key = "glauth.key"
|
||||
|
||||
#################
|
||||
# The backend section controls the data store.
|
||||
[[backends]]
|
||||
datastore = "ldap"
|
||||
servers = [ "ldap://localhost:389" ]
|
||||
|
||||
[[backends]]
|
||||
datastore = "config"
|
||||
|
||||
[[users]]
|
||||
name = "otpuser"
|
||||
otpsecret = "3hnvnk4ycv44glzigd6s25j4dougs3rk"
|
||||
|
||||
#################
|
||||
# Enable and configure the optional REST API here.
|
||||
[api]
|
||||
enabled = false
|
||||
tls = true
|
||||
listen = "localhost:5555"
|
||||
cert = "glauth.crt"
|
||||
key = "glauth.key"
|
||||
|
||||
Reference in New Issue
Block a user